[Python] Developing an API with FastAPI
Hey, everyone! This is the first post of the series "API frameworks for Python". We are starting with the framework FastAPI. FastAPI is fast and really easy to use. Let's build a simple API to exemplify its use.
1. Install the library in your environment
pip install fastapi
We are going to need an ASGI to run it:
pip install uvicorn[standard]
2. Create the first endpoint
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def hello_world():
return {"message": "Hello world"}
3. Start the ASGI server
project-root$ uvicorn main:app --reload
If everything goes well, you can now access your app on http://localhost:8000 and see our hello world message. You can access its documentation (swagger) on http://localhost:8000/docs
You have a second option of documentation and you can access it on http://localhost:8000/redoc
FastAPI gets a bonus point for having Swagger and ReDoc configured by default.
4. Create the other verbs
We are going to create, update, find and list our resource. Another good thing about FastAPI is that it supports type hints, unlike Flask, that we have to write schemas for validation. So the model we are using here is going to be written with type hints and with Pydantic to perform the data validation.
from pydantic import BaseModel
from typing import Optional
class School(BaseModel):
id: Optional[int]
name: str
4.1 Passing the request body
We pass the request body as argument to the function, for example:
@app.post('/schools')
def save(school: School):
# method implementation
school.id = 1
return school
Here we receive a school object.
Let's test this example:
curl -X POST -H "Content-Type: application/json" \
-d '{"name": "new school"}' \
http://localhost:8000/schools
>> {"id":1,"name":"new school"}
If we don't pass a required parameter or if we pass it as the wrong type, we receive a validation message:
curl -X POST -H "Content-Type: application/json" \
-d '{"namef": "new school"}' \
http://localhost:8000/schools
>> {"detail":[{"loc":["body","name"],"msg":"field required","type":"value_error.missing"}]}r
4.2 Passing path params
We pass the path params between {} in the url and we pass it as an argument to our function using the same name:
@app.get('/schools/{school_id}')
def find_by_id(school_id: int):
# method implementation
return {}
4.3 Passing query params `
We denote the query param by using the keyword Query. The first parameter is the parameter's standard value.
@app.get('/schools')
def search(name: Optional[str] = Query('standard value', max_length=50)):
# method implementation
return {}
4.4 Full example
Here is how our full class would be like:
from fastapi import FastAPI, Query
from model import School
from typing import Optional
app = FastAPI()
@app.post('/schools')
def save(school: School):
# method implementation
school.id = 1
return school
@app.get('/schools')
def search(name: Optional[str] = Query(None, max_length=50)):
# method implementation
return {}
@app.get('/schools/{school_id}')
def find_by_id(school_id: int):
# method implementation
return {}
@app.patch('/schools/{school_id}/name')
def partial_update(name: str, school_id: int):
# method implementation
return {"message": "School updated"}
@app.put('/schools/{school_id}')
def update(school: School, school_id: int):
# method implementation
return {"message": "School updated"}
@app.delete("/schools/{school_id}")
def delete(school_id: int):
# method implementation
return {"message": "School deleted"}
5. Conclusion
FastAPI is very easy to get running and it comes with a lot of useful things by default, like built-in documentation. It has issues like any other framework, but it is being updated and improved, so it seems like a good choice if you need to write an API in Python.