labthings_fastapi.middleware.url_for
Middleware to make url_for available as a context variable.
This module is intended mostly for internal use within LabThings. The short
summary is that, if you need to refer to other endpoints in the LabThings
server, you should not return hard-coded URLs, but instead use a URLFor
object. This will be converted to a URL when it’s serialised by FastAPI, using
the correct url_for function for the current request.
Under the hood, this module defines a url_for function that performs the
conversion. This function may only be run in certain places in the code, as
it relies on a context variable. As a rule of thumb, it’s OK to call
url_for from a serialiser of a pydantic model, but you should not call
it from within an Action or Property.
There are several places in LabThings where we need to be able to include URLs
to other endpoints in the LabThings server, most notably in the output of
Actions. For example, if an Action outputs a Blob, the URL to download
that Blob would need to be generated.
Actions are particularly complicated, as they are often invoked by one HTTP
request, and polled by subsequent requests. In order to ensure that the URL
we generate is consistent with the URL being requested, we should always use
the url_for method from the HTTP request we are responding to. This means
it is, in general, not a great idea to generate URLs within an Action and hold
on to them as strings. While it will work most of the time, it would be better
to store the endpoint name, and only convert it to a URL when the action’s
output is serialised by FastAPI.
This module includes a ContextVar for the url_for function, and provides
a middleware function that sets the context variable for every request, and a
custom type that works with pydantic to convert endpoint names to URLs at
serialisation time.
Attributes
Context variable storing the url_for function for the current request. |
Classes
A pydantic-compatible type that converts endpoint names to URLs. |
Functions
|
Set the url_for context variable for the duration of the context. |
|
Generate a fake URL as a placeholder for a real |
|
Get a URL for the given endpoint name and path parameters. |
|
Middleware to set the url_for context variable for each request. |
Module Contents
- labthings_fastapi.middleware.url_for.url_for_ctx: contextvars.ContextVar[collections.abc.Callable[Ellipsis, starlette.datastructures.URL]]
Context variable storing the url_for function for the current request.
- labthings_fastapi.middleware.url_for.set_url_for_context(url_for_function: collections.abc.Callable[Ellipsis, starlette.datastructures.URL]) collections.abc.Iterator[None]
Set the url_for context variable for the duration of the context.
- Parameters:
url_for_function – The url_for function to set in the context variable.
- labthings_fastapi.middleware.url_for.dummy_url_for(endpoint: str, **params: Any) starlette.datastructures.URL
Generate a fake URL as a placeholder for a real
url_forfunction.This is intended for use in test code.
- Parameters:
endpoint – The name of the endpoint.
**params – The path parameters.
- Returns:
A fake URL.
- labthings_fastapi.middleware.url_for.url_for(endpoint_name: str, **params: Any) starlette.datastructures.URL
Get a URL for the given endpoint name and path parameters.
This function uses the
url_forfunction stored in a context variable to convert endpoint names and parameters to URLs. It is intended to have the same signature asfastapi.Request.url_for.This function will raise a
NoUrlForContextErrorif there is nourl_forfunction in the context variable. This will be the case if the function is called outside of a request handler. As a rule, this function should not be called from within Actions or Properties.URLForis provided as a safe way to return URLs: it ensures that the URL is only generated at serialisation time, when there is a validurl_forfunction in the context. This also means the URL is always correct for the request being handled.- Parameters:
endpoint_name – The name of the endpoint to generate a URL for.
**params – The path parameters to use in the URL.
- Returns:
The generated URL.
- Raises:
NoUrlForContextError – if there is no url_for function in the context.
- async labthings_fastapi.middleware.url_for.url_for_middleware(request: fastapi.Request, call_next: collections.abc.Callable[[fastapi.Request], collections.abc.Awaitable[fastapi.Response]]) fastapi.Response
Middleware to set the url_for context variable for each request.
This middleware retrieves the
url_forfunction from the incoming request, and sets it in the context variable for the duration of the request.- Parameters:
request – The incoming FastAPI request.
call_next – The next middleware or endpoint handler to call.
- Returns:
The response from the next handler.
- class labthings_fastapi.middleware.url_for.URLFor(endpoint_name: str, **params: Any)
A pydantic-compatible type that converts endpoint names to URLs.
This class is intended to be used as a field type in
pydanticmodels or as a return type from actions or properties. It does not convert endpoint names to URLs immediately, but instead stores the endpoint name and parameters, and only generates the URL when it is serialised by FastAPI.It is safe to create a
URLForinstance anywhere, but converting it to a string (i.e. generating the URL) requires a validurl_forfunction and should generally be left for FastAPI.Fields or return values annotated as
URLForwill only accept aURLForinstance, but will be serialised to JSON as a string, and will show up in the JSONSchema as a string.Validating a string, i.e. converting a string to a
URLForinstance, is not supported, and will raise aTypeError.Create a URLFor instance.
- Parameters:
endpoint_name – The name of the endpoint to generate a URL for.
**params – The path parameters to use in the URL.
- endpoint_name
- params
- classmethod __get_pydantic_core_schema__(source: type[Any], handler: pydantic.GetCoreSchemaHandler) pydantic_core.core_schema.CoreSchema
Get the pydantic core schema for the URLFor type.
This magic method allows
pydanticto serialise URLFor instances, and generate a JSONSchema for them. Currently, URLFor instances may not be validated from strings, and attempting to do so will raise an error.The “core schema” we generate describes the field as a string, and serialises it by calling
str(obj)which in turn calls our__str__method to generate the URL.- Parameters:
source – The source type being converted.
handler – The pydantic core schema handler.
- Returns:
The pydantic core schema for the URLFor type.
- classmethod _validate(value: Any, handler: collections.abc.Callable[[Any], Self]) Self
Validate and convert a value to a URLFor instance.
- Parameters:
value – The value to validate.
handler – The handler to convert the value if needed.
- Returns:
The validated URLFor instance.
- Raises:
ValueError – if the value is not a URLFor instance.