Query Parameters¶
You can declare "query" parameters by defining function parameters with Query()
.
from typing import Annotated
from nexify import Nexify, Query
app = Nexify()
fake_items_db = [{"name": "Foo"}, {"name": "Bar"}, {"name": "Baz"}]
@app.get("/items")
def read_items(skip: Annotated[int, Query()] = 0, limit: Annotated[int, Query()] = 10):
return fake_items_db[skip : skip + limit]
A query parameter is a key-value pair appended to a URL after a question mark (?
).
Multiple query parameters can be included by separating them with an ampersand (&), forming a single string.
For example, in the following URL:
예를 들어, 아래의 URL에서
/items?skip=0&limit=10
The query parameters are:
- skip: with a value of
0
- limit: with a value of
10
As they are part of the URL, they are "naturally" strings.
But when you declare them with Python types (in the example above, as int
), they are converted to that type and validated against it.
All the same process that applied for path parameters also applies for query parameters:
- Editor support: error checks, autocompletion, etc.
- Data "parsing"
- Data validation
- API annotation and automatic documentation
Default Values¶
Query parameters are not fixed parts of the path, meaning they can be optional and have default values.
Info
Unlike query parameters, path parameters cannot be optional or have default values.
In this case, skip
has a default value of 0
, and limit
has a default value of 10
.
So, going to /items
would be teh same as going to /items?skip=0&limit=10
.
But if you go to /items?skip=20
The query parameter values in your function will be:
skip=20
: because you set it in the URLlimit=10
: because that was the default value
Declaring Default Values in Different Ways¶
You can also set default values by passing the default parameter inside Query()
within Annotated
.
from typing import Annotated
from nexify import Nexify, Query
app = Nexify()
fake_items_db = [{"name": "Foo"}, {"name": "Bar"}, {"name": "Baz"}]
@app.get("/items")
def read_items(skip: Annotated[int, Query(default=0)], limit: Annotated[int, Query(default=10)]):
return fake_items_db[skip : skip + limit]
In this case, skip
defaults to 0
, and limit
defaults to 10
.
Using this way allows you to bypass Python's restriction that parameters without default values must precede those with default values, which can be useful in some situations.
Alternatively, you can set default values using the default_factory
parameter inside Query()
within Annotated
.
from datetime import datetime
from typing import Annotated
from nexify import Nexify, Query
app = Nexify()
def default_date():
return datetime.now().isoformat()
@app.get("/logs")
def get_logs(
start_date: Annotated[str, Query(default_factory=default_date)],
end_date: Annotated[str, Query(default_factory=default_date)],
):
return {"start_date": start_date, "end_date": end_date}
The default_factory
is extremely useful in various situations:
- When a dynamic value is needed for each request: for example,
datetime.now()
returns a different value each time it is called. - When using mutable objects as default values: instead of manually checking for None, you can set
default_factory=list
ordefault_factory=dict
to ensure a new list or dictionary is created for each request. - When providing computed default values: if a default value needs to be derived from logic, wrapping it in a function and passing it to
default_factory
keeps the code clean.
Data Validation¶
from typing import Annotated
from nexify import Nexify, Query
app = Nexify()
fake_items_db = [{"name": "Foo"}, {"name": "Bar"}, {"name": "Baz"}]
@app.get("/items")
def read_items(skip: Annotated[int, Query()] = 0, limit: Annotated[int, Query()] = 10):
return fake_items_db[skip : skip + limit]
If you go to /items?skip=foo
, you will see a 422
response like this:
{
"detail": [
{
"type": "int_parsing",
"loc": [
"query",
"skip"
],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "foo"
}
]
}
Just like in the path parameters tutorial, since "foo"
cannot be converted to an int
, an internal Pydantic-based validation error occurs, and Nexify returns a 422 response with a detailed error message.
Documentation¶
And go to /docs
, you will see the following Swagger UI:
확인
Since Nexify automatically generates API documentation based on Python type hints, you can see that the path parameter is correctly documented as an int
type. Their default values are also clearly displayed as 0 and 10.
Required Query Parameters¶
Query parameters with default values are always "optional". To make a query parameter "required", simply do not provide a default value.
from typing import Annotated
from nexify import Nexify, Query
app = Nexify()
fake_items_db = [{"name": "Foo"}, {"name": "Bar"}, {"name": "Baz"}]
@app.get("/items")
def read_items(skip: Annotated[int, Query()], limit: Annotated[int, Query()]):
return fake_items_db[skip : skip + limit]
if you go to /items
without query parameters, you will receive a 422 response like this:
{
"detail": [
{
"loc": ["query", "skip"],
"msg": "Field required",
"type": "missing",
"input": null
},
{
"loc": ["query", "limit"],
"msg": "Field required",
"type": "missing",
"input": null
}
]
}
Since no default values are provided, skip and limit are "required" query parameters, and their absence triggers a validation error.
Additionally, the documentation clearly indicates that these parameters are "required".