Query parameters
When you declare other function parameters that are not part of the path parameters, they are automatically interpreted as "query" parameters.
from typing import Annotated
from hattori import Response
weapons = ["Ninjato", "Shuriken", "Katana", "Kama", "Kunai", "Naginata", "Yari"]
@api.get("/weapons")
def list_weapons(
request, limit: int = 10, offset: int = 0
) -> Annotated[Response[list[str]], 200]:
return Response(200, weapons[offset : offset + limit])
To query this operation, you use a URL like:
http://localhost:8000/api/weapons?offset=0&limit=10
The same benefits that apply to path parameters also apply to query parameters:
- Editor support (obviously)
- Data "parsing"
- Data validation
- Automatic documentation
Note
if you do not annotate your arguments, they will be treated as str types
@api.get("/weapons")
def list_weapons(request, limit, offset):
# type(limit) == str
# type(offset) == str
Defaults
As query parameters are not a fixed part of a path, they are optional and can have default values:
@api.get("/weapons")
def list_weapons(request, limit: int = 10, offset: int = 0):
return weapons[offset : offset + limit]
In the example above we set default values of offset=0 and limit=10.
So, going to the URL:
http://localhost:8000/api/weapons
http://localhost:8000/api/weapons?offset=0&limit=10
http://localhost:8000/api/weapons?offset=20
the parameter values in your function will be:
offset=20(because you set it in the URL)limit=10(because that was the default value)
Required and optional parameters
You can declare required or optional GET parameters in the same way as declaring Python function arguments:
from typing import Annotated
from hattori import Response
weapons = ["Ninjato", "Shuriken", "Katana", "Kama", "Kunai", "Naginata", "Yari"]
@api.get("/weapons/search")
def search_weapons(request, q: str, offset: int = 0) -> Annotated[Response[list[str]], 200]:
results = [w for w in weapons if q in w.lower()]
return Response(200, results[offset : offset + 10])
In this case, Django Ninja will always validate that you pass the q param in the GET, and the offset param is an optional integer.
GET parameters type conversion
Let's declare multiple type arguments:
from datetime import date
from typing import Annotated
from hattori import Response
@api.get("/example")
def example(
request, s: str = None, b: bool = None, d: date = None, i: int = None
) -> Annotated[Response[list[str | bool | date | int | None]], 200]:
return Response(200, [s, b, d, i])
str type is passed as is.
For the bool type, all the following:
http://localhost:8000/api/example?b=1
http://localhost:8000/api/example?b=True
http://localhost:8000/api/example?b=true
http://localhost:8000/api/example?b=on
http://localhost:8000/api/example?b=yes
b with a bool value of True, otherwise as False.
Date can be both date string and integer (unix timestamp):
http://localhost:8000/api/example?d=1577836800 # same as 2020-01-01
http://localhost:8000/api/example?d=2020-01-01
Using Schema
You can also use Schema to encapsulate GET parameters:
from typing import Annotated
from hattori import Query, Response, Schema
class Filters(Schema):
limit: int = 100
offset: int | None = None
query: str | None = None
categories: list[str] | None = None
class FilterResponse(Schema):
filters: Filters
@api.get("/filter")
def events(request, filters: Query[Filters]) -> Annotated[Response[FilterResponse], 200]:
return Response(200, {"filters": filters})
For more complex filtering scenarios please refer to filtering.