Query parameters


Time to expand our knowledge of API parameters and go one step further than path parameters by looking at query parameters.

Query Parameters

When you declare other function parameters that are not part of the path parameters, they are automatically interpreted as "query" parameters.

from fastapi import FastAPI

app = FastAPI()

fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]


@app.get("/items/")
async def read_item(skip: int = 0, limit: int = 10):
    return fake_items_db[skip : skip + limit]








 

The query is the set of key-value pairs that go after the ? in a URL, separated by & characters.

For example, in the URL:

127.0.0.1:8000/items/?skip=0&limit=10

...the query parameters are:

  • skip: with a value of 0
  • limit: with a value of 10

Both parameters come in as strings, but when you have declared them with Python types in your code (in the example above, as int), they are automatically converted to that type and validated against it.

All the same process that applied for path parameters also applies for query parameters:

  • Editor support (obviously)
  • Data parsing
  • Data validation
  • Automatic documentation

Default values

As query parameters are not a fixed part of a path, they can be optional and can have default values.

In the example they have default values of skip=0 and limit=10.

async def read_item(skip: int = 0, limit: int = 10):

So, going to the URL:

127.0.0.1:8000/items/

would be the same as going to:

127.0.0.1:8000/items/?skip=0&limit=10

But if you go to, for example:

127.0.0.1:8000/items/?skip=20

The parameter values in your function will be:

  • skip=20: because you set it in the URL
  • limit=10: because that was the default value

Optional parameters

The same way, you can declare optional query parameters:

from fastapi import FastAPI

app = FastAPI()


@app.get("/items/{item_id}")
async def read_item(item_id: str, q: str | None = None):
    if q:
        return {"item_id": item_id, "q": q}
    return {"item_id": item_id}






 



In this case, the function parameter q will be optional, and as such will be None by default. FastAPI is smart enough to notice that item_id is a path parameter and q is not, thus making it a query parameter.

Note

Please note that the code above only applies for Python 3.10 and above. During the course API Development, we will only see code examples compatible with Python 3.10 (older versions of Python might not support this syntax)!

When you declare a default value for non-path parameters you automatically make it optional as well. So if you don't want to add a default value but still make it optional you use | None = None. Later on we will replace the second None in this code by more information and validation for the parameters.

When you want to make a query parameter required, simply don't declare any default value:

from fastapi import FastAPI

app = FastAPI()


@app.get("/items/{item_id}")
async def read_user_item(item_id: str, needy: str):
    item = {"item_id": item_id, "needy": needy}
    return item





 
 


Here the query parameter needy is a required query parameter of type str.

If you open in your browser a URL like:

http://127.0.0.1:8000/items/foo-item

...without adding the required parameter needy, you will see an error like:

{
    "detail": [
        {
            "loc": [
                "query",
                "needy"
            ],
            "msg": "field required",
            "type": "value_error.missing"
        }
    ]
}

As needy is a required parameter, you would need to set it in the URL:

127.0.0.1:8000/items/foo-item?needy=sooooneedy

Giving you the response:

{
    "item_id": "foo-item",
    "needy": "sooooneedy"
}

Other type conversions

You can also declare bool types, and they will be converted as well:

from fastapi import FastAPI

app = FastAPI()


@app.get("/items/{item_id}")
async def read_item(item_id: str, q: str | None = None, short: bool = False):
    item = {"item_id": item_id}
    if q:
        item.update({"q": q})
    if not short:
        item.update(
            {"description": "This is an amazing item that has a long description"}
        )
    return item






 








In this case, if you go to:

127.0.0.1:8000/items/foo?short=1

127.0.0.1:8000/items/foo?short=True

127.0.0.1:8000/items/foo?short=true

127.0.0.1:8000/items/foo?short=on

127.0.0.1:8000/items/foo?short=yes

or any other case variation (uppercase, first letter in uppercase, etc), your function will see the parameter short with a bool value of True. Otherwise as False.

Multiple path and query parameters

You can declare multiple path parameters and query parameters at the same time, FastAPI knows which is which. And you don't have to declare them in any specific order.

They will be detected by name:

from fastapi import FastAPI

app = FastAPI()


@app.get("/users/{user_id}/items/{item_id}")
async def read_user_item(
    user_id: int, item_id: str, q: str | None = None, short: bool = False
):
    item = {"item_id": item_id, "owner_id": user_id}
    if q:
        item.update({"q": q})
    if not short:
        item.update(
            {"description": "This is an amazing item that has a long description"}
        )
    return item





 

 









And of course, you can define some parameters as required, some as having a default value, and some entirely optional:

from fastapi import FastAPI

app = FastAPI()


@app.get("/items/{item_id}")
async def read_user_item(
    item_id: str, needy: str, skip: int = 0, limit: int | None = None
):
    item = {"item_id": item_id, "needy": needy, "skip": skip, "limit": limit}
    return item







 



In this case, there are 3 query parameters:

  • needy, a required str.
  • skip, an int with a default value of 0.
  • limit, an optional int.
Last update: 10/3/2022, 11:03:33 PM