In this post, we will learn how to perform FastAPI Query Parameter validation. In particular, we will look into the use of Query function that allows us to perform validations in a declarative manner.

If you are not aware of query parameters in FastAPI, you can check out this detailed post about FastAPI Query Parameters. Also, if you are new to FastAPI, you can refer to this detailed post about getting started with FastAPI.

1 – The Simple Query Parameter

Let’s start with a basic example.

from fastapi import FastAPI

from typing import Optional

app = FastAPI()

@app.get("/books")
def read_books(test: Optional[str] = None):
    results = {"books": [{"book_name": "The Great Hunt"}, {"book_name": "The Dragon Reborn"}]}

    if test:
        results.update({"test": test})
    
    return results

Here, the query parameter test is of type Optional[str]. Basically, this means that the data type is str. However, it could also be None. Specifying None means that it is not a mandatory field.

2 – Query Parameter Length Validation

Let us now add another validation. We would like to validate the max length of the query parameter test.

We can do it as below:

from fastapi import FastAPI, Query

from typing import Optional

app = FastAPI()

@app.get("/books")
def read_books(test: Optional[str] = Query(None, max_length=10)):
    results = {"books": [{"book_name": "The Great Hunt"}, {"book_name": "The Dragon Reborn"}]}

    if test:
        results.update({"test": test})
    
    return results

Here, we use the Query function imported from fastapi. The Query(none) keeps the parameter as optional just like before. The additional property max_length specifies the maximum length of the parameter.

This will validate the data and show a clear error message if the value of test exceeds 10 characters. See below:

{
	"detail": [{
		"loc": ["query", "test"],
		"msg": "ensure this value has at most 10 characters",
		"type": "value_error.any_str.max_length",
		"ctx": {
			"limit_value": 10
		}
	}]
}

3 – Query Parameter Validation for Minimum Length

We can also add a check or validation for minimum length of the query parameter test.

See below:

@app.get("/books")
def read_books(test: Optional[str] = Query(None, min_length=3, max_length=10)):
    results = {"books": [{"book_name": "The Great Hunt"}, {"book_name": "The Dragon Reborn"}]}

    if test:
        results.update({"test": test})
    
    return results

If the min length check is violated, we get the below error response.

{
	"detail": [{
		"loc": ["query", "test"],
		"msg": "ensure this value has at least 3 characters",
		"type": "value_error.any_str.min_length",
		"ctx": {
			"limit_value": 3
		}
	}]
}

4 – Regex Validation

We can also validate using a Regex or Regular Expression.

@app.get("/books")
def read_books(test: Optional[str] = Query(None, min_length=3, max_length=10, regex="^testquery$")):
    results = {"books": [{"book_name": "The Great Hunt"}, {"book_name": "The Dragon Reborn"}]}

    if test:
        results.update({"test": test})
    
    return results

Basically, in the above snippet, error response is triggered if the query parameter has value other than testquery.

5 – Query Parameter Default Value

Just like we pass None as the first argument to the Query function, we can also pass an actual default value.

See below example:

@app.get("/books")
def read_books(test: Optional[str] = Query("testquery", min_length=3, max_length=10)):
    results = {"books": [{"book_name": "The Great Hunt"}, {"book_name": "The Dragon Reborn"}]}

    if test:
        results.update({"test": test})
    
    return results

In this case, if we don’t supply an actual value, FastAPI will use the default value for the query parameter.

6 – Mandatory Query Parameter

We can also make the query parameter test as mandatory by not declaring a default value.

See below example:

@app.get("/books")
def read_books(test: Optional[str] = Query(..., min_length=3, max_length=10)):
    results = {"books": [{"book_name": "The Great Hunt"}, {"book_name": "The Dragon Reborn"}]}

    if test:
        results.update({"test": test})
    
    return results

Here, instead of a default value, we use three dots (…). Basically, this signifies that the query parameter is mandatory.

In case we don’t provide a valid value, we get the below error response.

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

7 – Query Parameter List Value

Another use case with query parameters is to be able to process a list of values. In other words, multiple values.

As an example, let’s consider we want to pass the below values for the query parameter test.

http://localhost:8000/items/?test=query1&test=query2

To achieve this, we have to tweak our Query function to accept a list. See below example:

from fastapi import FastAPI, Query

from typing import List, Optional

app = FastAPI()

@app.get("/books")
def read_books(test: Optional[List[str]] = Query(None)):
    results = {"books": [{"book_name": "The Great Hunt"}, {"book_name": "The Dragon Reborn"}]}

    if test:
        results.update({"test": test})
    
    return results

Also, we can supply default values for list query parameters as below:

@app.get("/books")
def read_books(test: Optional[List[str]] = Query(["query1", "query2"])):
    results = {"books": [{"book_name": "The Great Hunt"}, {"book_name": "The Dragon Reborn"}]}

    if test:
        results.update({"test": test})
    
    return results

8 – Query Parameter Additional Metadata

We can also add more metadata about a parameter.

See below example:

@app.get("/books")
def read_books(test: Optional[str] = Query(None, title="Query string", description="Description of Query String", min_length=3)):
    results = {"books": [{"book_name": "The Great Hunt"}, {"book_name": "The Dragon Reborn"}]}

    if test:
        results.update({"test": test})
    
    return results

Here, we have added a title and description property. The same will also be reflected in the interactive API docs as below.

fastapi query parameter validation

9 – Query Parameter Alias

This is another useful feature.

Consider that we wish to call our query parameter test-query. However, test-query is not a valid python variable name. But we have a hard requirement to have our query parameter named as test-query only.

In such a case, we can use the alias property as below:

@app.get("/books")
def read_books(test: Optional[str] = Query(None, alias="test-query")):
    results = {"books": [{"book_name": "The Great Hunt"}, {"book_name": "The Dragon Reborn"}]}

    if test:
        results.update({"test": test})
    
    return results

Conclusion

With this, we have learnt how to perform FastAPI Query Parameter validation using Query function. We looked at various options available as part of the Query function to declaratively provide validations.

If you have any comments or queries, please do mention in the comments section below.

Categories: BlogFastAPI

Saurabh Dashora

Saurabh is a Software Architect with over 12 years of experience. He has worked on large-scale distributed systems across various domains and organizations. He is also a passionate Technical Writer and loves sharing knowledge in the community.

0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *