labthings_fastapi.middleware.url_for ==================================== .. py:module:: labthings_fastapi.middleware.url_for .. autoapi-nested-parse:: 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 serializer 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 ---------- .. autoapisummary:: labthings_fastapi.middleware.url_for.url_for_ctx Classes ------- .. autoapisummary:: labthings_fastapi.middleware.url_for.URLFor Functions --------- .. autoapisummary:: labthings_fastapi.middleware.url_for.set_url_for_context labthings_fastapi.middleware.url_for.dummy_url_for labthings_fastapi.middleware.url_for.url_for labthings_fastapi.middleware.url_for.url_for_middleware Module Contents --------------- .. py:data:: url_for_ctx :type: contextvars.ContextVar[collections.abc.Callable[Ellipsis, starlette.datastructures.URL]] Context variable storing the url_for function for the current request. .. py:function:: 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. :param url_for_function: The url_for function to set in the context variable. .. py:function:: dummy_url_for(endpoint: str, **params: Any) -> starlette.datastructures.URL Generate a fake URL as a placeholder for a real ``url_for`` function. This is intended for use in test code. :param endpoint: The name of the endpoint. :param \**params: The path parameters. :return: A fake URL. .. py:function:: 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_for`` function stored in a context variable to convert endpoint names and parameters to URLs. It is intended to have the same signature as `fastapi.Request.url_for`\ . This function will raise a `NoUrlForContextError` if there is no ``url_for`` function 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. `URLFor` is provided as a safe way to return URLs: it ensures that the URL is only generated at serialisation time, when there is a valid ``url_for`` function in the context. This also means the URL is always correct for the request being handled. :param endpoint_name: The name of the endpoint to generate a URL for. :param \**params: The path parameters to use in the URL. :return: The generated URL. :raises NoUrlForContextError: if there is no url_for function in the context. .. py:function:: url_for_middleware(request: fastapi.Request, call_next: collections.abc.Callable[[fastapi.Request], collections.abc.Awaitable[fastapi.Response]]) -> fastapi.Response :async: Middleware to set the url_for context variable for each request. This middleware retrieves the ``url_for`` function from the incoming request, and sets it in the context variable for the duration of the request. :param request: The incoming FastAPI request. :param call_next: The next middleware or endpoint handler to call. :return: The response from the next handler. .. py:class:: 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 `pydantic` models 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 `URLFor` instance anywhere, but converting it to a string (i.e. generating the URL) requires a valid `url_for` function and should generally be left for FastAPI. Fields or return values annotated as `.URLFor` will only accept a `.URLFor` instance, 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 `.URLFor` instance, is not supported, and will raise a `TypeError`. Create a URLFor instance. :param endpoint_name: The name of the endpoint to generate a URL for. :param \**params: The path parameters to use in the URL. .. py:attribute:: endpoint_name .. py:attribute:: params .. py:method:: __str__() -> str Convert the URLFor instance to a URL string. :return: The generated URL as a string. .. py:method:: __get_pydantic_core_schema__(source: type[Any], handler: pydantic.GetCoreSchemaHandler) -> pydantic_core.core_schema.CoreSchema :classmethod: Get the pydantic core schema for the URLFor type. This magic method allows `pydantic` to 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. :param source: The source type being converted. :param handler: The pydantic core schema handler. :return: The pydantic core schema for the URLFor type. .. py:method:: _validate(value: Any, handler: collections.abc.Callable[[Any], Self]) -> Self :classmethod: Validate and convert a value to a URLFor instance. :param value: The value to validate. :param handler: The handler to convert the value if needed. :return: The validated URLFor instance. :raises ValueError: if the value is not a URLFor instance.