Errors
The base fastapi_problem.error.Problem
accepts a title
, detail
, status
(default 500) and optional **kwargs
. An additional code
can be passed in,
which will be used as the type
, if not provided the type
is derived from
the class name.
And will return a JSON response with exc.status
as the status code and response body:
{
"type": "an-exception",
"title": "title",
"detail": "detail",
"status": 500,
"extra-key": "extra-value",
...
}
Derived types are generated using the class name after dropping ...Error
from
the end, and converting to kebab-case
. i.e. PascalCaseError
will derive the
type pascal-case
. If the class name doesn't suit your purposes, an optional
code
attribute can be set with the desired value of there response type
field.
Some convenience Problems are provided with predefined status
attributes.
To create custom errors subclasss these and define the title
attribute.
fastapi_problem.error.ServerProblem
provides status 500 errorsfastapi_problem.error.RedirectProblem
provides status 301 errorsfastapi_problem.error.BadRequestProblem
provides status 400 errorsfastapi_problem.error.UnauthorisedProblem
provides status 401 errorsfastapi_problem.error.ForbiddenProblem
provides status 403 errorsfastapi_problem.error.NotFoundProblem
provides status 404 errorsfastapi_problem.error.ConflictProblem
provides status 409 errorsfastapi_problem.error.UnprocessableProblem
provides status 422 errors
Custom Errors
Subclassing the convenience classes provide a simple way to consistently raise the same error with detail/extras changing based on the raised context.
from fastapi_problem.error import NotFoundProblem
class UserNotFoundError(NotFoundProblem):
title = "User not found."
raise UserNotFoundError(detail="detail")
Whereas a defined code
will be used in the output.
class UserNotFoundError(NotFoundProblem):
title = "User not found."
type_ = "cant-find-user"
raise UserNotFoundError(detail="detail")
If additional kwargs are provided when the error is raised, they will be included in the output (ensure the provided values are json seriablizable.
Headers
Problem subclasses can define specific headers at definition, or provide instance specific headers at raise. These headers will be extracted and returned as part of the response.
Headers provided when raising will overwrite any matching headers defined on the class.
class HeaderProblem(StatusProblem):
status = 400
headers = {"x-define-header": "value"}
raise HeaderProblem(headers={"x-instance-header": "value2"})
response.headers == {
"x-define-header": "value",
"x-instance-header": "value2",
}
Redirects
An additional helper class RedirectProblem
is provided for handling 3XX
problems with a Location
header. This subclass takes an additional required
init argument location
.
class PermanentRedirect(RedirectProblem):
status = 308
title = "Permanent redirect"
raise PermanentRedirect("https://location", "detail of move")
e.headers == {
"Location": "https://location",
}
Error Documentation
The RFC-9457 spec defines that the type
field should provide a URI that can
link to documentation about the error type that has occurred. By default the
Problem class provides a unique identifier for the type, rather than a full
url. If your service/project provides documentation on error types, the
documentation uri can be provided to the handler which will result in response
type
fields being converted to a full link. The uri .format()
will be
called with the type, title, status and any additional extras provided when the
error is raised.
Where a full resolvable documentation uri does not exist, the rfc allows for a tag uri.
Strict mode
The RFC-9457 spec defines the type as requiring a URI format, when no reference
is provided, it should default to about:blank
. Initializing the handler in
strict_rfc9457
more requires the documentation_uri_template
to be defined, and
in cases where the Problem doesn't explicitly define a type_
attribute, the
type will default to about:blank
.