Error handling

← Error handling

Ashterix

docs: rewrite JsonRpcBundle docs, add SDK docs, move them under docs/api

en/docs/api/rest-bundle/error_handling.md new file +94 −0

Error handling

Format

Every error of a REST call or document is returned as an RFC 9457 (problem details) document with the HTTP status of the error:

{
    "_error_object_standard": "RFC 9457",
    "status": 400,
    "type": "about:blank",
    "instance": "/rest/catalog/items/42",
    "title": "Ufo\\RestBundle\\Exceptions\\RestBadRequestException",
    "detail": "Invalid Data for call method: catalog.update",
    "detail-data": {
        "title": ["This value is too short. It should have 3 characters or more."]
    }
}
Field Value
status the HTTP status, the same as the response status
type always about:blank
instance the request path
title the REST exception class
detail the error message
detail-data only if the RPC error contains an array of data: per-parameter messages for validation and type errors

Stack traces are not included in the document.

How the status is chosen

The RPC core turns any method exception into an RPC error (the rpc.error event): exceptions from the ufo-tech/rpc-exceptions package keep their class and code, an argument TypeError becomes a parameter error, other exceptions are wrapped (Error handling in JsonRpcBundle). The REST layer recreates the exception from the RPC error and converts it with the RestErrorNormalizer class:

RPC exception REST exception Status
RpcJsonParseException RestBadRequestException 400
RpcMethodNotFoundExceptionRpc RestResourceNotFoundException 404
ConstraintsImposedException RestValidationException 422
RpcBadParamException (parameter validation and type errors) RestBadRequestException 400
RpcBadRequestException RestBadRequestException 400
RpcInternalException, RpcRuntimeException RestInternalServerErrorException 500
RpcLogicException RestBadRequestException 400
RpcTokenNotSentException, RpcInvalidTokenException RestUnauthorizedException 401
RpcDataNotFoundException RestResourceNotFoundException 404
CustomApplicationException RestApplicationException the exception code if it is an HTTP error code, otherwise 400
any other RestBadRequestException the exception code if it is an HTTP error code, otherwise 400

The table is checked top to bottom with instanceof, so subclasses come before their parent classes. An HTTP error code is a code from the RestErrorNormalizer::REST_ERROR_CODES list (standard 4xx and 5xx codes). If an exception from any row of the table has such a code, the status is taken from it.

The 404 row for RpcMethodNotFoundExceptionRpc, the 422 row for ConstraintsImposedException and keeping the HTTP code of an application error are available since version 1.3. In 1.0–1.2 these cases returned 400. See Fixed issues.

REST layer errors

Situation Exception Status
no REST route for the path, unknown version, a method of another group RestResourceNotFoundException 404
the HTTP method is not allowed for the route RestResourceNotAllowedException 405
invalid or scalar JSON body RestBadRequestException 400
token not sent or invalid RestUnauthorizedException 401

Returning a specific status from a method

Throw an RPC exception from the table or an exception with an HTTP code:

use Ufo\RpcError\CustomApplicationException;
use Ufo\RpcError\RpcDataNotFoundException;

/**
 * @throws RpcDataNotFoundException
 * @throws CustomApplicationException
 */
#[Route('/items/{id}', name: 'item', methods: ['GET'])]
public function item(int $id): array
{
    $item = $this->repository->find($id) ?? throw new RpcDataNotFoundException('Item is not found'); // 404
    if ($item->isClosed()) {
        throw new CustomApplicationException('Item is closed', 409);                              // 409
    }
    return $item->toArray();
}

Via JSON-RPC the same exceptions produce ordinary RPC errors, so one method serves both protocols. The @throws tags add these statuses to the OpenAPI documentation.

Notes:

  • An exception with code 0 becomes an internal RPC error and returns 500.
  • RPC core validation errors (#[RPC\Assertions], parameter types) return 400 with detail-data. 422 applies only to a ConstraintsImposedException that reaches the REST layer directly.
  • An unknown method or path gives 404, but a wrong HTTP method for an existing path gives 405.