Custom ViewSet actions¶
@action registers an additional HTTP endpoint when its ViewSet is included.
A detail action uses {pk}; a collection action does not. It does not create a
get_object() or get_request_data() helper.
Custom actions use declared HTTP permissions
Route registration evaluates the action's effective permission list before
calling its handler. permission_classes=None inherits the ViewSet list;
an explicit action list replaces it. A denial returns HTTP 403 with the
permission's message and the handler is not called.
A checked detail action¶
In the ticket-desk application, this action returns a summary after the standard retrieve path performs its checks:
from starlette.requests import Request
from aksara import ModelViewSet
from aksara.api import action
from aksara.permissions import IsAuthenticated
from .models import Ticket
class TicketViewSet(ModelViewSet):
model = Ticket
prefix = "/api/tickets"
permission_classes = [IsAuthenticated]
ai_exposed = False
stream_enabled = False
@action(detail=True, methods=["GET"], path="summary", ai_exposed=False)
async def summary(self, pk: str, request: Request):
record = await self.retrieve(pk=pk, request=request)
return {"id": record["id"], "subject": record["subject"]}
Register the ViewSet through the tutorial's include_viewset flow. The added
path is GET /api/tickets/{pk}/summary, without a trailing slash. The handler
receives pk, matching the generated path parameter. A parameter named id
does not automatically rename that path parameter.
The action wrapper checks IsAuthenticated before this handler runs. The
example still delegates to retrieve for the standard object lookup and
serialization path. When an effective permission overrides
has_object_permission, a detail action loads the target and evaluates that
object decision before dispatch. Collection actions still require an
application query scope, and applications still establish identity and tenant
context before permission evaluation.
Decorator arguments¶
| Argument | Contract |
|---|---|
detail |
Required boolean: detail or collection route |
methods |
Required list of HTTP method names; normalized to uppercase |
path |
Optional route segment, default method name |
name |
Optional route name, default method name |
summary, description |
Optional OpenAPI text; otherwise derived from the docstring |
permission_classes |
HTTP and generated-tool permission override; None inherits the ViewSet list |
ai_exposed |
Action exposure metadata, default true; other ViewSet/model/registration conditions still apply |
requires_approval |
MCP signed approval-grant requirement, default false; not an HTTP approval workflow |
The keywords are path and name, not url_path and url_name. There is no
implicit default GET method when methods is omitted.
Inputs, writes, and transactions¶
FastAPI inspects the bound method signature. Annotate request as Request
and define typed body/query parameters for your actual endpoint. A docstring
is not input validation. For writes, validate fields and related objects, apply
current authority and tenant rules, and use a transaction for database changes
that must commit together.
Do not perform a direct ORM update and assume the action decorator applies all CRUD field-write restrictions. Replacing a generated handler with application code means owning those checks. A collection action also needs an explicit query scope; object permission does not filter an entire list automatically.
MCP is a separate execution path¶
Eligible custom actions can appear in generated MCP discovery when the model, ViewSet, action, and application exposure settings permit it. Discovery is permission-filtered, and MCP performs its own execution-time checks before its internal HTTP call reaches the same action permission wrapper.
requires_approval=True concerns signed, bounded MCP grants. It neither stores
a durable approval workflow nor automatically gates direct HTTP calls. For
work that must survive approval delay and worker loss, use
Durable Operations.
Start with the official MCP client tutorial for authenticated tool execution and the permissions guide for synchronous application checks.