elasticms/client-helper-bundle
ClientHelperBundle provides helpers for integrating elasticMS clients, with links to documentation and centralized issue/PR tracking in the elasticMS monorepo. Useful for simplifying client-side setup and tooling in EMS-based projects.
Installation:
composer require elasticms/client-helper-bundle
Add to config/bundles.php (Symfony/Laravel bridge):
return [
// ...
ElasticMS\ClientHelperBundle\ElasticMSClientHelperBundle::class => ['all' => true],
];
First Use Case: Generate a standardized API client for frontend consumption:
php artisan elasticms:client-helper:generate
This creates a ClientHelper service in config/elasticms.php with default endpoints (e.g., /api/v1).
Frontend Integration: Use the generated client in your frontend (React/Vue example):
import { useApiClient } from 'elasticms/client-helper';
const { data, error, isLoading } = useApiClient('/users');
Key Config File:
Edit config/elasticms.php to define:
Authorization: Bearer {{ token }})Pattern: Replace custom fetch/axios calls with bundle-provided utilities.
// Laravel Service Provider (AppServiceProvider.php)
$this->app->bind('elasticms.client', function ($app) {
return new \ElasticMS\ClientHelperBundle\Client(
$app['http.client'],
config('elasticms.api.base_url')
);
});
Frontend Usage:
// Auto-injects Laravel CSRF token if configured
const { data } = useApiClient('/posts', {
params: { limit: 10 },
headers: { 'X-Custom-Header': 'value' }
});
Pattern: Validate and submit forms with minimal boilerplate.
// Laravel Controller
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'title' => 'required|string|max:255',
]);
if ($validator->fails()) {
return response()->json([
'errors' => $validator->errors(),
], 422);
}
// Bundle auto-maps errors to frontend
$post = Post::create($request->validated());
return response()->json($post);
}
Frontend:
const { submitForm } = useFormHandler('/posts', {
onSuccess: (data) => toast.success('Post created!'),
onError: (errors) => {
errors.title?.forEach(msg => toast.error(msg));
}
});
Pattern: Generate frontend routes from CMS content.
// Define routes in config/elasticms.php
'routes' => [
'content' => [
'path' => '/content/{slug}',
'controller' => \App\Http\Controllers\ContentController::class,
'method' => 'show',
],
],
Frontend:
import { useDynamicRoute } from 'elasticms/client-helper';
const { route } = useDynamicRoute('content', { slug: 'about-us' });
// Renders <Link to={route}>About Us</Link>
Pattern: Extend bundle behavior via Laravel events.
// Listen to API response modification
Event::listen(\ElasticMS\ClientHelperBundle\Events\ApiResponse::class, function ($event) {
$event->response->setData([
'meta' => [
'request_id' => Str::uuid(),
'timestamp' => now()->toIso8601String(),
],
]);
});
Pattern: Auto-refresh OAuth tokens.
// config/elasticms.php
'auth' => [
'driver' => 'oauth',
'refresh_token_endpoint' => '/oauth/token',
'storage' => 'session', // or 'cookie', 'localStorage'
],
Frontend:
const { token } = useAuthHelper();
if (!token) {
redirectTo('/login');
}
Symfony vs. Laravel Conflicts:
HttpClient. If you encounter ClassNotFoundException, install:
composer require symfony/http-client
AppServiceProvider:
$this->app->bind(\Symfony\Contracts\HttpClient\HttpClientInterface::class, function () {
return new \GuzzleHttp\Client(); // or Laravel's HttpClient
});
CORS Misconfigurations:
// app/Http/Middleware/Cors.php
protected $allowedOrigins = ['http://localhost:3000', 'https://your-app.com'];
Token Storage Security:
localStorage for sensitive apps. Use HttpOnly cookies or sessionStorage instead.config/elasticms.php:
'auth' => [
'storage' => 'cookie',
'cookie' => [
'secure' => env('APP_ENV') === 'production',
'http_only' => true,
'same_site' => 'strict',
],
],
ElasticMS Dependency:
ElasticMS\CMSBundle in composer.json before using CMS-specific features.Error Handling Gaps:
Event::listen(\ElasticMS\ClientHelperBundle\Events\ApiError::class, function ($event) {
if ($event->status === 403) {
$event->message = 'Access denied. Please login.';
}
});
Log API Requests:
Enable debug mode in config/elasticms.php:
'debug' => env('APP_DEBUG'),
Logs requests to storage/logs/elasticms.log.
Frontend Console Errors:
elasticms-client-helper.js in network tab).useApiClient with a callback to debug:
useApiClient('/users', {
onRequest: (config) => console.log('Request:', config),
onResponse: (response) => console.log('Response:', response),
});
Token Refresh Loops:
// config/elasticms.php
'auth' => [
'refresh_debounce_ms' => 5000, // 5-second delay
],
Custom API Clients: Create a subclass to add project-specific logic:
namespace App\Services;
use ElasticMS\ClientHelperBundle\Client;
class CustomClient extends Client
{
public function customEndpoint()
{
return $this->request('GET', '/custom');
}
}
Register in AppServiceProvider:
$this->app->bind('custom.client', function () {
return new CustomClient($this->app['http.client'], config('elasticms.api.base_url'));
});
Override Frontend Helpers: Publish and extend the JavaScript bundle:
php artisan vendor:publish --tag=elasticms-client-helper-assets
Edit resources/js/elasticms-client-helper.js to add custom hooks.
Add New Error Types: Extend the error mapper:
namespace App\Services;
use ElasticMS\ClientHelperBundle\ErrorMapper;
class AppErrorMapper extends ErrorMapper
{
protected function mapCustomError($status, $message, $errors)
{
return [
'code' => 'CUSTOM_ERROR',
'message' => 'Custom error occurred: ' . $message,
];
}
}
Bind in AppServiceProvider:
$this->app->bind(\ElasticMS\ClientHelperBundle\Contracts\ErrorMapper::class, AppErrorMapper::class);
Avoid Over-Fetching:
The bundle defaults to returning full responses. Use select for Eloquent queries:
// Laravel Controller
return Post::select('id', 'title')->get();
Lazy-Load Helpers: Dynamically import frontend helpers to reduce bundle size:
How can I help you explore Laravel packages today?