Last mod: 2025.02.04

Raspberry Pi - REST API based on FastAPI

REST APIs play a crucial role in IoT devices like the Raspberry Pi, enabling seamless communication between embedded systems and external applications. They allow sensors and actuators to send and receive data efficiently, making IoT deployments more scalable and flexible. While Flask and Flask-RESTX have been popular choices for building APIs, FastAPI offers a modern alternative with better performance, automatic data validation, and asynchronous support. Its speed and ease of use make it ideal for resource-constrained IoT environments, improving response times and reducing overhead. As IoT continues to evolve, leveraging FastAPI can lead to more efficient and responsive device interactions.

Introduction

In my opinion, Python is the best language for building REST APIs for small portable systems like the Raspberry Pi. This is determined by several elements:

  • Most of the IoT devices communicates have written libraries in Python
  • Python allows you to create lightweight applications
  • Python is a high-level language where we do not need to focus on implementation details
  • We can use the FastAPI library to easily create web applications with a REST API with self-documentation by Swagger

Software

Any OS for the Rapsberry Pi should have Python installed by default. Let's verify this:

python -V

python -V

Install virtual environments venv:

sudo apt update
sudo apt install python3-venv -y

Create and run virtual environment:

python -m venv ~/.venv
source ~/.venv/bin/activate

Install FastAPI and Uvicorn:

pip install fastapi uvicorn

"Hello World" app example

Create first web app "Hello World". Write file app_fastapi_helloworld.py with body:

from fastapi import FastAPI

app = FastAPI()
@app.get("/")
def index():
    return "Hello World"

And run:

uvicorn app_fastapi_helloworld:app --host 0.0.0.0 --port 8000

uvicorn app_fastapi_helloworld:app --host 0.0.0.0 --port 8000 --reload

Open in browser http://RASPBERRY_PI_IP:8000:

http://RASPBERRY_PI_IP:8000

REST API method

Now let's write a real REST API method, create file app_fastapi_time.py:

from fastapi import APIRouter, FastAPI
from datetime import datetime

app = FastAPI()
router = APIRouter(prefix='/api')

@router.get("/get_time")
def get_time():
    return {"current_time": datetime.now().isoformat()}

app.include_router(router)

Run:

uvicorn app_fastapi_time:app --host 0.0.0.0 --port 8000

Open in browser http://RASPBERRY_PI_IP:8000/api/get_time:

http://RASPBERRY_PI_IP:8000/api/get_time

POST request and defining request structure

We can define a JSON format in the request and in the response. Create new app app_fastapi_post.py with POST method:

from fastapi import APIRouter, FastAPI, Response
from pydantic import BaseModel, Field

app = FastAPI()
router = APIRouter(prefix='/api')

class MotorsDto(BaseModel):
    left: int = Field(ge=-100, le=100, description="The left motor can have values from -100 to 100.")
    right: int = Field(ge=-100, le=100, description="The right motor can have values from -100 to 100.")

@router.post("/motors")
def motors_set(data: MotorsDto):
    print("Left:", data.left)
    print("Right: ", data.right)
    return Response(status_code=200)

app.include_router(router)

Run:

uvicorn app_fastapi_post:app --host 0.0.0.0 --port 8000

Call POST method:

curl -X POST http://192.168.3.106:8000/api/motors -H "Content-Type: application/json" -d '{"left": 35, "right" : 90}'

Server side result:

curl -X POST http://RASPBERRY_PI_IP:8000/api/motors -H "Content-Type: application/json" -d '{"left": 35, "right" : 90}'

We used the curl tool to make the call. However, the FastAPI framework has another feature that makes building REST APIs easier, it has a built-in Swagger library. When you type http://RASPBERRY_PI_IP:8000/docs into your browser, you will get a page with the HTTP methods available in our application. There are also structures defined to handle requests and responses, built-in and ours.

http://RASPBERRY_PI_IP:8000/docs

From this interface, we can call any available REST API method with parameters of our choice:

REST API Swagger screen

Uvicorn

We can simplify the way applications run on the Uvicorn server. Let's add a line at the end of our application:

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

Now instead of a command:

uvicorn application_file_name:app --host 0.0.0.0 --port 8000

we can start the application by calling:

python application_file_name.py

Links

https://www.python.org/
https://docs.python.org/3/library/venv.html
https://fastapi.tiangolo.com/
https://pypi.org/project/uvicorn/
https://restfulapi.net/
https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
https://pypi.org/project/psutil/
https://swagger.io/