Path parameters are one of the first things you need to use when building REST APIs. In this post, we will learn how to use FastAPI path parameters with validations.

Validations are a key aspect of any robust application. FastAPI uses Pydantic to handle data validations under the hood. Therefore, we get all the benefits of using Pydantic while not worrying too much about validations. This makes it easy for developers to focus on their application logic.

In case you are new to FastAPI, you can start with this detailed post on getting started with FastAPI.

1 – Path Parameters

We can declare path parameters or variables using Python format string.

See below example:

from fastapi import FastAPI

app = FastAPI()

@app.get("/books/{book_id}")
def get_book_by_id(book_id):
    return {"book_id": book_id}

Here, the value of the book_id is passed to the function as argument. We can run this example and access the endpoint. We get the below output when we hit http://localhost:8000/books/test.

{"book_id":"test"}

2 – Path Parameters with Types

We can also provide data types for our path parameters.

See below example:

@app.get("/authors/{author_id}")
def get_author_by_id(author_id: int):
    return {"author_id": author_id}

Here, we use standard Python annotations to specify that author_id is an integer. If we hit the endpoint http://localhost:8000/authors/test, we get the below error response:

{
	"detail": [{
		"loc": ["path", "author_id"],
		"msg": "value is not a valid integer",
		"type": "type_error.integer"
	}]
}

Basically, the endpoint only expects an integer value for author_id. In other words, FastAPI validates the incoming path parameters and provides an appropriate response.

Even the API documentation reflects the proper data type. See below Swagger screenshot when we access the http://localhost:8000/docs.

fastapi path parameters swagger

Another interesting point to note here is data conversion. When we hit http://localhost:8000/authors/5, we get the below response.

{"author_id":5}

As you can see, the output is a number. In other words, FastAPI converts the string “5” to numeric 5 automatically for us.

3 – Path Order

Often we need to make paths with similar structure. This happens when the fixed path is the same. As an example, consider we have two endpoints as below:

/books/default
/books/{book_id}

The first one returns a default book. The second one returns the book with a particular book_id. In this case, the order of declaring these endpoints is important. The paths are evaluated in order. Therefore, we need to declare /books/default before /books/{book_id}. See below:

@app.get("/books/default")
def get_default_books():
    return {"book_name": "The Eye of the World"}

@app.get("/books/{book_id}")
def get_book_by_id(book_id):
    return {"book_id": book_id}

This arrangement will ensure that both endpoints are properly invoked.

4 – Path Parameter Predefined Values

Many times, the API path parameters have a set of possible values. In this case, we can use an Enum to define such a set and use it in our function declaration.

See below example:

from enum import Enum
from typing import Optional
from fastapi import FastAPI

app = FastAPI()

class BookCode(str, Enum):
    eotw = "eotw"
    tgh = "tgh"
    tdr = "tdr"

movies_db = [{"movie_name": "The Fellowship of the Ring"}, {"movie_name": "The Two Towers"}, {"movie_name": "The Return of the King"}]

@app.get("/books-by-code/{book_code}")
def get_books_by_name(book_code: BookCode):
    if book_code == BookCode.eotw:
        return {"book_code": book_code, "book_name": "Eye of the World"}

    if book_code.value == "tgh":
        return {"book_code": book_code, "book_name": "The Great Hunt"}

    if book_code.value == BookCode.tdr.value:
        return {"book_code": book_code, "book_name": "The Dragon Reborn"}

We first create an enum class by importing Enum library. This is basically a sub class that inherits from str and Enum. Next, we declare three items in the Enum class. By inheriting from the str class, the API docs will know that we expect a string value as input.

Next, we use the new class as annotation for the path parameter book_code. Within the function, we use different approaches to compare the input to our enum class member and return appropriate book details.

We can also check the API docs where the various possible inputs are also present in dropdown format.

fastapi enum path paramet

If we pass any value other than the valid values, we get the below error response.

{
	"detail": [{
		"loc": ["path", "book_code"],
		"msg": "value is not a valid enumeration member; permitted: 'eotw', 'tgh', 'tdr'",
		"type": "type_error.enum",
		"ctx": {
			"enum_values": ["eotw", "tgh", "tdr"]
		}
	}]
}

Conclusion

With this, we have successfully learnt how to use FastAPI Path Parameters with Validations. From a validation perspective, we have considered data types as well as Enum values and how we can configure our endpoint declaration to help with validating the input.

In the next post, we will be looking into FastAPI Query Parameters.

If you have any comments or queries, please feell free to write 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.

2 Comments

Fer_B · March 9, 2022 at 6:00 pm

Excellent article, thanks!

A small correction: on first example, the URL says:
“http://localhost:8000/test”
but should be:
“http://localhost:8000/books/test”

Best regards!

    Saurabh Dashora · March 11, 2022 at 9:49 am

    Thanks for pointing it out! Updated the article.

Leave a Reply

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