UrlAdapter

Pluggable URL routing strategy for ApiBackend.

  1. Overview
  2. base_url
  3. url_suffix

Overview

Sits between the high-level CRUD methods (create, update, delete, records) and the actual HTTP request. Its sole responsibility is answering the structural question — what URL should this request go to, and which data keys were consumed as routing parameters?

Every URL method returns a tuple of (url, used_routing_parameters). The second element is a list of parameter names that were absorbed into the URL path. These parameters are then removed from the request body before sending to the API, preventing them from being sent in both the URL path and the request body.

Default behavior

The default implementation generates standard REST-style URLs:

  • GET /resource — via records_url
  • POST /resource — via create_url
  • PATCH /resource/{id} — via update_url
  • DELETE /resource/{id} — via delete_url

It also supports URL parameter substitution using {param} or :param syntax in the base_url. For instance, with a base URL of /api/v1/{tenant_id}, query conditions like model.where("tenant_id=abc") will fill in the parameter automatically.

Implementing a custom adapter

Subclass UrlAdapter and override the methods you need. Each method receives different arguments depending on the operation:

import clearskies


class VersionedUrlAdapter(clearskies.backends.adapters.UrlAdapter):
    def records_url(self, query):
        name = query.model_class.destination_name()
        return (f"/api/v2/{name}", [])

    def create_url(self, data, model):
        return (f"/api/v2/{model.destination_name()}", [])

    def update_url(self, id, data, model):
        return (f"/api/v2/{model.destination_name()}/{id}", [])

    def delete_url(self, id, model):
        return (f"/api/v2/{model.destination_name()}/{id}", [])

Attach it to an ApiBackend:

backend = clearskies.backends.ApiBackend(
    base_url="https://api.example.com",
    url_adapter=VersionedUrlAdapter(),
)

Reporting consumed routing parameters

If your URL absorbs parameters from the save data, return them in the second element of the tuple so they are stripped from the request body:

class TenantUrlAdapter(clearskies.backends.adapters.UrlAdapter):
    def create_url(self, data, model):
        tenant_id = data["tenant_id"]
        url = f"/api/v1/tenants/{tenant_id}/{model.destination_name()}"
        return (url, ["tenant_id"])

Without reporting ["tenant_id"], the tenant_id key would be sent in both the URL path and the JSON request body.

base_url

Optional

Prepended to all generated URLs (e.g. "https://api.example.com/api/v1"). Supports {param} and :param routing parameter syntax.

url_suffix

Optional

Appended to all generated URLs (e.g. ".json").