Installation
Run composer require druidvav/api-service-bundle in your Symfony project root.
Verify the package appears in composer.json under require.
Enable the Bundle
Add new Druidvav\ApiServiceBundle\DvApiServiceBundle() to app/Kernel.php (or config/bundles.php for Symfony 4.3+).
Basic Configuration
Define a logger in config/packages/dv_api_service.yaml:
dv_api_service:
logger: "@monolog.logger.api" # Replace with your logger service ID
First API Service
Create a service class (e.g., src/ApiService/MyService.php):
namespace App\ApiService;
class MyService implements \Druidvav\ApiServiceBundle\ApiServiceInterface
{
public function execute(array $params): array
{
return ['result' => 'Hello, API!'];
}
}
Register the Service
Tag it in config/services.yaml:
services:
App\ApiService\MyService:
tags: ["jsonrpc.api-service"]
Test via JSON-RPC Use a client (e.g., Postman) to call:
POST /api/jsonrpc
{
"jsonrpc": "2.0",
"method": "MyService.execute",
"params": {"key": "value"},
"id": 1
}
Implement ApiServiceInterface
All services must implement execute(array $params): array for JSON-RPC compatibility.
Example:
class UserService implements ApiServiceInterface {
public function execute(array $params): array {
return ['user' => $this->userRepository->find($params['id'])];
}
}
Dependency Injection Use Symfony’s autowiring to inject services (e.g., repositories, managers):
services:
App\ApiService\UserService:
arguments:
$userRepository: "@App\Repository\UserRepository"
Request Handling
The bundle routes JSON-RPC requests to /api/jsonrpc by default. Override the route in config/routes.yaml:
dv_api_service_jsonrpc:
path: /custom/api
methods: POST
controller: Druidvav\ApiServiceBundle\Controller\JsonRpcController::executeAction
Authentication Extend the controller to add auth middleware:
// src/Controller/CustomJsonRpcController.php
class CustomJsonRpcController extends JsonRpcController {
public function executeAction(Request $request) {
if (!$this->isAuthenticated($request)) {
throw new \RuntimeException('Unauthorized');
}
return parent::executeAction($request);
}
}
Update routes to use your controller.
Error Handling Customize error responses by extending the bundle’s exception handler:
// config/services.yaml
services:
Druidvav\ApiServiceBundle\Exception\JsonRpcExceptionListener:
arguments:
$errorFormatter: "@App\Service\CustomErrorFormatter"
Batch Processing
Use executeBatch(array $services, array $params) for parallel API calls:
$batch = [
'UserService.execute' => ['id' => 1],
'OrderService.fetch' => ['userId' => 1],
];
$results = $this->apiService->executeBatch($batch);
Dynamic Service Loading Load services dynamically via a service locator:
$service = $this->container->get('jsonrpc.api-service.' . $serviceName);
Middleware Pipeline Add pre/post-processing middleware:
services:
App\Middleware\ApiLoggerMiddleware:
tags:
- { name: kernel.event_listener, event: dv_api_service.pre_execute, method: onPreExecute }
Service Tagging
jsonrpc.api-service tag is misspelled or missing.config/services.yaml and clear cache (php bin/console cache:clear).Logger Configuration
logger in config.yml is misconfigured.@monolog.logger.api or @logger).Circular Dependencies
JSON-RPC Version
1.0 vs 2.0).2.0 in your service responses and client requests.Route Conflicts
/api/jsonrpc conflicting with other routes.Enable Debug Mode
Symfony’s debug toolbar shows JSON-RPC requests/responses. Enable in .env:
APP_DEBUG=1
Log Raw Requests Add a listener to log incoming JSON-RPC payloads:
// src/EventListener/ApiRequestLogger.php
class ApiRequestLogger {
public function onPreExecute(RequestEvent $event) {
$this->logger->info('API Request:', ['data' => $event->getRequest()->getContent()]);
}
}
Register it in config/services.yaml:
tags:
- { name: kernel.event_listener, event: dv_api_service.pre_execute, method: onPreExecute }
Validate Service Responses
Ensure execute() always returns an array (JSON-RPC requires structured responses):
return ['success' => true, 'data' => $result];
Custom Response Formatters Override the default JSON-RPC formatter:
// src/Service/CustomJsonRpcFormatter.php
class CustomJsonRpcFormatter implements JsonRpcFormatterInterface {
public function format(array $result, $id): string {
return json_encode(['custom' => $result, 'id' => $id]);
}
}
Bind it in config/services.yaml:
services:
jsonrpc.formatter: "@App\Service\CustomJsonRpcFormatter"
Add HTTP Headers Modify the controller to inject headers:
// src/Controller/CustomJsonRpcController.php
public function executeAction(Request $request) {
$response = parent::executeAction($request);
$response->headers->set('X-API-Version', '1.0');
return $response;
}
Rate Limiting Use Symfony’s rate limiter middleware:
# config/packages/framework.yaml
framework:
http_client:
rate_limiter: "@App\Service\ApiRateLimiter"
Documentation Auto-generate OpenAPI/Swagger docs by annotating services:
/**
* @ApiService(
* description="Fetches a user by ID",
* params={
* "type": "object",
* "properties": {
* "id": {"type": "integer"}
* }
* }
* )
*/
class UserService implements ApiServiceInterface { ... }
How can I help you explore Laravel packages today?