FastAPI Object Lookups: Flexible URL Parameter-Based Retrieval¶
FastAPI Mason offers a flexible object lookup system that controls how items are retrieved from URL parameters. Supporting multiple strategies including int, string, UUID, and custom methods, it enables customizable and precise REST API routing.
Overview¶
The lookup system consists of:
- Lookup Classes — define how to extract and validate lookup values from the URL
- Automatic Resolution — seamless integration with ViewSets for object retrieval
- Custom Lookups — ability to create your own lookup logic
Basic Usage¶
By default, a ViewSet uses IntegerLookup
to retrieve objects by integer ID:
from fastapi_mason.viewsets import ModelViewSet
@viewset(router)
class CompanyViewSet(ModelViewSet[Company]):
model = Company
read_schema = CompanyReadSchema
create_schema = CompanyCreateSchema
# lookup_class = IntegerLookup (default)
This creates routes like /companies/{item_id}/
, where item_id
is an integer.
Built-in Lookup Classes¶
- IntegerLookup — lookup by integer (default)
- StringLookup — lookup by string
- UUIDLookup — lookup by UUID
Example of explicitly setting a lookup class:
from fastapi_mason.lookups import StringLookup
@viewset(router)
class CompanyViewSet(ModelViewSet[Company]):
model = Company
read_schema = CompanyReadSchema
create_schema = CompanyCreateSchema
lookup_class = StringLookup
lookup_field = 'slug' # model field to search by
Now the route will be /companies/{item_id}/
, where item_id
is a string (e.g., a slug).
Custom Lookup Classes¶
You can create your own lookup class to support special strategies or parameter names:
from fastapi_mason.lookups import build_lookup_class
from uuid import UUID
# Create a lookup by UUID with a custom parameter name
CustomUUIDLookup = build_lookup_class('CustomUUIDLookup', 'company_uuid', UUID)
@viewset(router)
class CompanyViewSet(ModelViewSet[Company]):
model = Company
read_schema = CompanyReadSchema
create_schema = CompanyCreateSchema
lookup_class = CustomUUIDLookup
lookup_field = 'uuid' # model field
Now the route will be /companies/{company_uuid}/
, where company_uuid
is a UUID.
Defining a Custom Lookup Class (Subclassing)¶
In addition to using the build_lookup_class
factory, you can define your own lookup class by subclassing BaseLookup
. This is useful if you need custom validation or decoding logic.
For example, let's create a lookup that decodes a base64-encoded token from the URL:
import base64
from fastapi import Path, HTTPException
from fastapi_mason.lookups import BaseLookup
class TokenLookup(BaseLookup):
lookup_url_kwarg = 'token'
@classmethod
def build(cls, token: str = Path(..., alias='token')):
try:
decoded_bytes = base64.urlsafe_b64decode(token)
return cls(value=decoded_bytes)
except Exception:
raise HTTPException(detail='Invalid base64 token', status_code=400)
You can then use this lookup in your ViewSet:
@viewset(router)
class SecureResourceViewSet(ModelViewSet[SecureResource]):
model = SecureResource
read_schema = SecureResourceReadSchema
create_schema = SecureResourceCreateSchema
lookup_class = TokenLookup
lookup_field = 'token_bytes' # or whatever field you use
This will create a route like /resources/{token}/
, where token
is a base64-encoded string that will be decoded before lookup.
Usage in Custom Actions¶
The lookup class can also be used in custom detail actions to preserve API consistency and ensure uniform object retrieval handling:
from fastapi_mason.decorators import action
from fastapi_mason.lookups import IntegerLookup
@viewset(router)
class CompanyViewSet(ModelViewSet[Company]):
# ...
@action(methods=["POST"], detail=True)
async def activate(self, lookup: IntegerLookup = Depends(IntegerLookup.build)):
company = await self.get_object(lookup.value)
company.is_active = True
await company.save()
return {"message": "Company activated"}
If you use a custom lookup class, the parameter will match its type and name.
How It Works¶
- All lookup classes inherit from
BaseLookup
, which defines the common interface. - To create a lookup class, use the
build_lookup_class
factory, which lets you specify the parameter name and value type. - The ViewSet uses the
lookup_class
(lookup type) andlookup_field
(model field to search by) attributes.
Recommendations¶
- Use
IntegerLookup
for standard integer IDs - Use
StringLookup
or a custom lookup for string-based fields (slug, username, etc.) - Use
UUIDLookup
or a custom lookup for UUID fields - For complex cases (composite keys, advanced validation), create your own lookup class with
build_lookup_class