Skip to content

Make url_for easier to access from pydantic serialisation. #211

@rwb27

Description

@rwb27

Various things in LabThings need to contain URLs, for example the serialisation of a Blob includes a download URL, and the representation of an Invocation includes a URL for polling. Currently, these are generated in a somewhat ad-hoc manner using Request.url_for - but the Request object isn't always available when it's needed.

Additionally, some objects (for example Action outputs) may be downloaded in a different request from the one where they were created. This could lead to errors if url_for is called in the request that starts the action, but the URL is returned in the request that polls it. It's an edge case, but it would be nice to know we're following best practice.

Finally, it's a general rule that we should avoid manipulating URLs in the web app as strings: particularly if LabThings is combined with another server (e.g. to add authentication), we should minimise our assumptions about URLs.

I propose we can fix all these issues by implementing a nice way to generate URLs.

  • Introduce a new class, UrlFor, which is pydantic-compatible (i.e. can be serialised). This would accept the same arguments as Request.url_for, i.e. an endpoint name and keyword arguments. When a UrlFor object is serialised, it would call Request.url_for to generate the URL in the request where the object gets returned so it's always correct.
  • Add a piece of middleware that sets a context variable, to make url_for available to the deserialiser of UrlFor on every HTTP request. This avoids the need to use a specific dependency/context manager and should ensure we can always serialise a UrlFor object whenever one is returned.

This way, our application code need only ever handle endpoint names and not URLs, and we needn't worry about providing context explicitly.

After implementing this, we probably need to improve the endpoint names to make them predictable, so it's easy to use UrlFor instead of hard-coding URLs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions