Extensions
What can be changed or added in REST Bundle without changing its code. Other packages of the ecosystem are listed on the JsonRpcBundle Extensions page.
RPC events
A REST call fires the same events as JSON-RPC (see Lifecycle), so an application listener works for both protocols:
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Ufo\JsonRpcBundle\EventDrivenModel\Events\RpcEvent;
use Ufo\JsonRpcBundle\EventDrivenModel\Events\RpcPostResponseEvent;
#[AsEventListener(event: RpcEvent::POST_RESPONSE)]
final class AuditListener
{
public function __invoke(RpcPostResponseEvent $event): void
{
// $event->rpcRequest->getMethod(), $event->response, $event->service
}
}
To tell a REST call from a JSON-RPC one, check the carrier: RequestCarrier::getCarrier() instanceof Ufo\RestBundle\Services\RpcFromRest.
Replacing the request parser
The controller depends on Ufo\RestBundle\Interfaces\RestRequestParserInterface with a single method parse(string $routeName, Request $request): Service. Extend RestRequestParser and alias the interface:
# config/services.yaml
Ufo\RestBundle\Interfaces\RestRequestParserInterface: '@App\Rest\TenantAwareParser'
use Symfony\Component\HttpFoundation\Request;
use Ufo\JsonRpcBundle\Server\ServiceMap\Service;
use Ufo\RestBundle\Services\RestRequestParser;
final class TenantAwareParser extends RestRequestParser
{
public function parse(string $routeName, Request $request): Service
{
// for example, reject a request without a tenant header before the call
return parent::parse($routeName, $request);
}
}
The parser must leave the carrier in RequestCarrier: the controller executes exactly RequestCarrier::getCarrier(). Exceptions implementing Ufo\RestBundle\Exceptions\RestErrorInterface are returned with a status equal to their code; the rest go through RestErrorNormalizer.
Reading the REST map
Ufo\RestBundle\Services\RestServiceMap returns the REST routes and RPC services of the current API group (from ApiGroupContext):
foreach ($restServiceMap->getVersions() as $version) {
foreach ($restServiceMap->getRoutes($version) as $name => $route) {
$service = $restServiceMap->getService($name, $version); // RPC Service
// $route->getPath(), $route->getMethods()
}
}
getRoute(), getService() and the methods called with an unknown version throw RestResourceNotFoundException.
Translations from a bundle
A bundle that provides RPC methods can also provide their titles and descriptions; REST documents pick them up (since 1.3):
public function prepend(ContainerBuilder $container): void
{
$container->prependExtensionConfig('ufo_json_rpc', [
'translations' => ['paths' => [__DIR__.'/../../translations']],
]);
}
Another adapter alongside REST
An adapter that imports its own routes file for each API group implements Ufo\JsonRpcBundle\Routing\IApiRouteImport (autoconfiguration, tag ufo.rpc.route_import), the same as RestRouteImport:
use Ufo\JsonRpcBundle\Routing\IApiRouteImport;
final class AcmeRouteImport implements IApiRouteImport
{
public function getResource(): string { return __DIR__.'/../../config/router.yaml'; }
public function getRouteNamePrefixAttribute(): string { return '_acme_name_prefix'; }
}
Do not extend the JsonRpcBundle route loader for this. A minimal adapter with RpcExecutor is described on the JsonRpcBundle For developers page.