Request lifecycle
How REST Bundle processes a request: from the HTTP request to the RPC call and back. The description matches version 1.3; how the core processes the same call is described on the JsonRpcBundle lifecycle page.
REST call
kernel.request, priority 32:RouterListenerfinds the generated REST route. Its defaults contain_rest_route(the REST route name without the version),_verfor versions other thanv1,api_groupand_rest_name_prefix.kernel.request, priority 30:RestControllerListenerwrites the group toApiGroupContextand, for a REST call, points_controllertoRestEntryPointController::restwith therpcRouteandverattributes.RestRequestParser::parse()- finds the REST route and the RPC
Servicefor the group and version (404if missing); - checks the HTTP method:
HEADcounts asGET, a method that is not allowed gives405; - resets the RPC event pool (
RpcEventFactory::reset()), setsHttpTokenHolderand theRpcFromRestcarrier, checks the token (protected_api).
- finds the REST route and the RPC
RpcFromRestbuilds anRpcRequest: a generatedid, the RPC method name, the merged parameters andapiVersion.RpcExecutor::execute()executes the request the same way as JSON-RPC:rpc.request→rpc.pre_execute(building arguments, validation, conversion,#[RPC\Lock], method call) →rpc.pre_response→rpc.post_execute. Any error goes throughrpc.errorand becomes an error response.- The controller returns
200with the method result or converts the error into an RFC 9457 problem viaRestErrorNormalizer. kernel.terminate:rpc.post_responsefires for a successful call (#[RPC\CacheRelation]invalidation, post-response listeners). Not for an error.
A request without a matching REST route lands in the catch-all entry point ufo_rest_api_entrypoint (priority -100), and the parser returns 404. A request with a wrong HTTP method lands in the <name>_method_not_allowed route (priority -10), and the parser returns 405.
Documentation
- Priority 32: routing to a route with the
_rest_docdefault. - Priority 30:
RestControllerListenerwrites the group toApiGroupContext. - Priority 8:
RestDocLocaleListenerpicks the language fromAccept-Language(RpcLocaleNegotiator::applyLocale()). RestEntryPointController::openapiAction()/postmanAction()checks the token (protected_doc) and builds the document for the version and group.kernel.response:Content-LanguageandVary: Accept-Language.
No RPC events are fired on this path; the document is built on every request.
Events
A REST call fires the same events as JSON-RPC, so the application's listeners work for both:
| Event | Constant | When |
|---|---|---|
rpc.request |
RpcEvent::REQUEST |
the request is accepted |
rpc.pre_execute |
RpcEvent::PRE_EXECUTE |
before the method |
rpc.pre_response |
RpcEvent::PRE_RESPONSE |
the response is formed |
rpc.post_execute |
RpcEvent::POST_EXECUTE |
after the method |
rpc.error |
RpcEvent::ERROR |
any error |
rpc.post_response |
RpcEvent::POST_RESPONSE |
on kernel.terminate, after a successful call |
Each event is described in detail in Lifecycle events.
Before 1.3 the REST controller executed the request through RpcRequestHandler without RpcExecutor, and rpc.post_response was not fired for REST.
State between requests
The API group is kept in ApiGroupContext, the carrier in RequestCarrier, the token holder in IRpcSecurity; these services belong to JsonRpcBundle and are reset between requests in long-running workers. RestServiceMap builds the REST routes for a group once and switches between already built maps when the group in ApiGroupContext changes.