devim/symfony4-rpc-server-bundle
Installation Add the bundle to your Symfony 4 project via Composer:
composer require devim/symfony4-rpc-server-bundle
Register the bundle in config/bundles.php:
return [
// ...
Devim\RpcServerBundle\DevimRpcServerBundle::class => ['all' => true],
];
Configuration
Define RPC endpoints in config/packages/devim_rpc_server.yaml:
devim_rpc_server:
endpoints:
- { path: '/api/rpc', methods: ['POST'] }
First RPC Method
Create a service annotated with @RpcMethod:
use Devim\RpcServerBundle\Annotation\RpcMethod;
class MyRpcService
{
/**
* @RpcMethod("add")
*/
public function add(int $a, int $b): int
{
return $a + $b;
}
}
Register the service in services.yaml:
services:
App\Service\MyRpcService:
tags: ['rpc.method']
Testing
Send a POST request to /api/rpc with JSON payload:
{
"method": "add",
"params": [5, 3]
}
Expected response:
{ "result": 8 }
Annotation-Driven
Use @RpcMethod to expose public methods as RPC endpoints. Name the method in the annotation to define the RPC callable name.
/**
* @RpcMethod("user.get")
*/
public function getUser(int $id): array
Parameter Handling
array or custom DTOs for complex inputs.
/**
* @RpcMethod("order.create")
*/
public function createOrder(OrderDto $order): OrderResponse
Authentication/Authorization Integrate with Symfony’s security system via event listeners:
# config/packages/devim_rpc_server.yaml
devim_rpc_server:
listeners:
- App\EventListener\RpcAuthListener
Example listener:
class RpcAuthListener implements RpcEventSubscriberInterface
{
public function onRpcCall(RpcEvent $event)
{
if (!$event->getUser()) {
throw new \RuntimeException('Unauthorized');
}
}
}
Error Handling
Throw exceptions (e.g., RpcException) for custom error responses:
public function deleteUser(int $id): void
{
if (!$this->userRepository->exists($id)) {
throw new RpcException('User not found', 404);
}
// ...
}
Async Methods Use Symfony’s Messenger component for async RPC calls:
/**
* @RpcMethod("task.async")
*/
public function asyncTask(string $data): void
{
$this->messageBus->dispatch(new AsyncTaskMessage($data));
}
API Versioning
Prefix RPC methods with version tags (e.g., @RpcMethod("v1.user.get")) and route based on path segments.
Documentation
Generate OpenAPI/Swagger docs by integrating with nelmio/api-doc-bundle and annotating RPC methods:
/**
* @RpcMethod("user.list")
* @ApiResource()
*/
Rate Limiting
Use Symfony’s RateLimitStrategy middleware to restrict RPC calls:
# config/packages/framework.yaml
framework:
http_client:
rate_limit_strategy: Symfony\Component\HttpClient\RateLimit\RateLimitStrategy
Logging Log RPC calls via Symfony’s logger:
use Psr\Log\LoggerInterface;
class RpcLogger implements RpcEventSubscriberInterface
{
public function __construct(private LoggerInterface $logger) {}
public function onRpcCall(RpcEvent $event)
{
$this->logger->info('RPC call', [
'method' => $event->getMethod(),
'params' => $event->getParams(),
]);
}
}
Deprecated Bundle
symfony/ux-rpc.Annotation Processing
doctrine/annotations is installed and configured in composer.json:
"require": {
"doctrine/annotations": "^1.0"
}
@RpcMethod annotations:
php bin/console cache:clear
CORS Issues The bundle does not include CORS middleware by default. Add it manually:
# config/packages/nelmio_cors.yaml
nelmio_cors:
defaults:
allow_origin: ["*"]
allow_methods: ["POST"]
allow_headers: ["Content-Type"]
expose_headers: ["*"]
Parameter Validation
use Symfony\Component\Validator\Constraints as Assert;
/**
* @RpcMethod("user.update")
* @Assert\Type("App\Dto\UserDto")
*/
public function updateUser(UserDto $user)
Circular Dependencies
Avoid circular references in RPC services (e.g., ServiceA calling ServiceB which calls ServiceA). Use dependency injection carefully.
Enable Debug Mode
Set APP_DEBUG=1 in .env to see detailed RPC call logs in Symfony’s profiler.
Check Event Dispatching
Use RpcEvent listeners to inspect calls:
public function onRpcCall(RpcEvent $event)
{
dump($event->getMethod(), $event->getParams());
}
Test with curl
Validate RPC calls manually:
curl -X POST http://localhost/api/rpc \
-H "Content-Type: application/json" \
-d '{"method":"add","params":[1,2]}'
Common Errors
APP_DEBUG).Custom Serialization
Override default JSON serialization by implementing RpcSerializerInterface:
class CustomSerializer implements RpcSerializerInterface
{
public function serialize($data): string
{
return json_encode($data, JSON_PRETTY_PRINT);
}
public function deserialize(string $data): array
{
return json_decode($data, true);
}
}
Register it in services.yaml:
services:
App\Serializer\CustomSerializer:
tags: ['rpc.serializer']
Middleware Support Add pre/post-processing middleware:
devim_rpc_server:
middlewares:
- App\Middleware\RpcLoggingMiddleware
Dynamic Endpoints
Register RPC methods dynamically via RpcMethodRegistry:
$registry->addMethod('dynamic.method', [$this, 'dynamicAction']);
Batch Processing
Extend the bundle to support batch RPC calls (e.g., {"methods": [{"name": "add", "params": [...]}, ...]}).
How can I help you explore Laravel packages today?