Pythonium

Python, What else ?

Build a REST API with FastAPI

Let he who has never coded an API cast the first stone. Indeed, APIs have been everywhere for quite a few years. In this tutorial, we will explore the basic concepts of FastAPI and how to use it to quickly create REST APIs.

By the end of this tutorial, you will be able to create production-ready APIs (getting a bit ahead of myself here...) and will have the necessary knowledge to dive deeper into your specific use cases (But later on, AI can assist you).

FastAPI: What is it?

FastAPI is a modern, fast, and high-performance framework for building APIs in Python, based on standard Python type annotations.

Basically, when you want to build an API in Python, there's a good chance you'll use FastAPI (Well, there are alternatives: Flask, Django Rest Framework, Tornado, ...).

FastAPI offers high performance, comparable to NodeJS and Go. It speeds up development, reduces human errors, and provides great editor support with auto-completion, minimizing debugging time. The framework is easy to learn, reduces code duplication, and ensures production-ready code with automatic interactive documentation. Based on open standards like OpenAPI and JSON Schema, FastAPI simplifies the process of building robust and efficient APIs.

Install FastAPI

Like any Python project, it's best to start by creating a virtual environment (optional), and then install FastAPI

$ python -m pip install fastapi[standard] uvicorn[standard]

Your first API: Just the basics

In this tutorial, we’ll see how to create a simple "products" API and cover the basics of retrieving and updating products. This is a fake API — we won’t be handling data persistence, as that’s beyond the scope of this FastAPI introduction.

FastAPI is very intuitive: it provides a decorator for each HTTP method. Here’s a summary table:

HTTP methodFastAPI Decorator
GET@app.get()
POST@app.post()
PUT@app.put()
DELETE@app.delete()
PATCH@app.patch()
OPTIONS@app.options()
TRACE@app.trace()

Get

Create a file main.py with the following basic FastAPI content:

from typing import Union
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"msg": "Hello !"}

Run it

fastapi dev main.py

Open your browser at http://127.0.0.1:8000

{"msg":"Hello !"}

And there you go, your API is now available and already returns a JSON object. For now, it doesn't do much — but we’re about to start building our products API:

from typing import Union
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"msg": "Hello !"}

@app.get("/products/{product_id}")
def read_product(product_id: int, name: Union[str, None] = None):
    return {"id": product_id, "name": name}

Here's a bit of explanation:

  • product_id is a path parameter and gets passed to the function as the product_id argument.
  • name is a query parameter. Any function parameter that isn’t in the path is treated as a query parameter by default.
    Since we set it to None, it’s optional!

Open your browser at http://127.0.0.1:8000/products/5?name=T-shirt.

{"id":5,"name":"T-shirt"}

And there you go, we've already implemented our products API for the GET endpoint. (As mentioned before, I'm not handling where the data is stored — that's up to you!)

Update

Now, let's move on to the update part:

from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel

class Product(BaseModel):
    name: str
    price: float
    is_offer: Union[bool, None] = None

app = FastAPI()

@app.put("/products/{product_id}")
def update_product(product_id: int, product: Product):
    return {"id": product_id, "name": product.name, "price": 10.5}

Here's a bit of explanation:

  • product (Product) the product itself. We directly use the class that represents the resource! It's handy!

Execute the following request:

PUT /products/5 HTTP/1.1
Host: 127.0.0.1:8000
Content-Type: application/json

The response is:

{
    "id": 5,
    "name": "new name",
    "price": 10.5
}

A few more things

Data Validation

If you point your browser to http://127.0.0.1:8000/products/one, then you’ll see a nice HTTP error:

{"detail":[{"type":"int_parsing","loc":["path","product_id"],"msg":"Input should be a valid integer, unable to parse string as an integer","input":"one"}]}

FastAPI takes care of the validation right away.

Filtering

from typing import Union, List
from fastapi import FastAPI, Query
from pydantic import BaseModel

class Product(BaseModel):
    name: str
    price: float
    is_offer: Union[bool, None] = None

app = FastAPI()

# Simulated in-memory database
fake_items_db = [
    {"product_id": 1, "name": "Item A", "price": 25.5, "is_offer": False},
    {"product_id": 2, "name": "Item B", "price": 35.0, "is_offer": True},
    {"product_id": 3, "name": "Item C", "price": 45.0, "is_offer": None},
    {"product_id": 4, "name": "Item D", "price": 55.5, "is_offer": False},
]

@app.get("/products")
def get_products(
    name: Union[str, None] = None,
    min_price: Union[float, None] = None,
    max_price: Union[float, None] = None,
    is_offer: Union[bool, None] = None,
    page: int = 1,
    page_size: int = 10
):
    # Filtering based on query parameters
    results = fake_items_db
    if name:
        results = [for product in results if name.lower() in product["name"].lower()]
    if min_price is not None:
        results = [for product in results if product["price"] >= min_price]
    if max_price is not None:
        results = [for product in results if product["price"] <= max_price]
    if is_offer is not None:
        results = [for product in results if product["is_offer"] == is_offer]

    # Pagination
    start = (page - 1) * page_size
    end = start + page_size
    paginated_results = results[start:end]
    
    return {"products": paginated_results, "total": len(results), "page": page, "page_size": page_size}

Nothing fancy here — just a few optional query parameters for filtering.

Open your browser at http://127.0.0.1:8000/products/?name=Item A.

{"products":[{"product_id":1,"name":"Item A","price":25.5,"is_offer":false}],"total":1,"page":1,"page_size":10}

API docs

Documentation… what a chore to write it. You'll love FastAPI — it's auto-generated, which makes life so much better!

Open your browser at http://127.0.0.1:8000/docs, you will see the automatic interactive API documentation (provided by Swagger UI):

Alternative provided by ReDoc: http://127.0.0.1:8000/redoc.

Conclusion

As we've just seen, it's quick and easy to create an API with FastAPI. In just a few lines of code, our API is already up and running!

We haven't covered everything, but we’ve gone trough the basic principles. If you want to dive deeper, you can check out the FastAPI documentation:

https://fastapi.tiangolo.com/




Laisser un commentaire