FastAPI Code Sample
FastAPI Code Sample
• Download : https://www.python.org/downloads/
• Check by going to terminal and typing python
• Install data science friendly environment such as Anaconda (https://www.anaconda.com/products/distribution)
• create an application directory called FARM ( only an example). Inside it, we will create a virtual environment
• A virtual environment is an isolated Python environment that includes a copy of the Python interpreter, which we can use to install the desired packages and only the needed packages – in our case,
FastAPI, the Uvicorn web server, and additional packages like FastAPI dependency called Pydantic
• think of a virtual environment as a directory tree of Python executable files and packages that allow us to have different versions of Python and the various third-party packages together on a single
machine, without them interfering with each other.
• NOTE : pipenv (https://pipenv.pypa.io/en/latest/), pyenv (https://github.com/pyenv/pyenv) is another way of creating a virtual environment
• After installing python go to directory apps and in command prompt type : python –m venv venv
• This command should download a new Python executable and create a new directory named venv – it is the second argument in the command ( venv is used because many git download will have
venv)
• Go to scripts folder and type activate (to activate the newly created environment. The prompt should change and be prepended with the name of the active environment in parenthesis – that
is, $(venv).)
• Install git (https://git-scm.com/downloads)
• you should have installed a shell program – if you are working on Linux or Mac, you should be fine. On Windows, you can use Windows PowerShell or something such as Commander
(https://cmder.app), a console emulator for Windows that has some nice features baked in.
• Use visual studio code for development
• Finally, to be able to test our REST API, we need a REST client. Postman (https://www.postman.com/) is arguably the most sophisticated and customizable program for testing APIs, but there are several
very viable alternatives. This is simple : Insomnia (https://insomnia.rest/), a GUI REST client with a very clean and simple interface, and HTTPie (https://httpie.io/), a command-line REST API client that
allows us to quickly test our endpoints without leaving the shell. HTTPie provides other nice features such as an expressive and simple syntax, handling of forms and uploads, sessions, and so on.
Moreover, HTTPie is probably the easiest REST client when it comes to installation – you can install the Python version just like any other Python package, using pip or some other option, such as
choco, apt (for Linux), brew, and so on.
• E.g. pip install httpie and test using the command : (venv) > http GET https://jsonplaceholder.typicode.com/todos/1 . You will get an output :HTTP/1.1 200 OK
• FastAPI exposes an asynchronous server gateway interface (ASGI – https://asgi.readthedocs.io/)-compatible web application but doesn’t provide us with a built-in server
• There are 3 servers listed on FastAPI : three compatible Python ASGI-compatible servers – Uvicorn, Hypercorn, and Daphne
• pip install fastapi uvicorn
• FASTAPI is a mix of Starlette (provides webSocket support, events on startup and shutdown, session and cookie support, background tasks, middleware implementations, templates, and many more)
and Pydantic (Python library for data validation – it enforces type hints at runtime and provides user-friendly errors, allowing us to catch invalid data as soon as possible – that is, before they make it
deep into the system and cause havoc. Although it is a parsing library and not a validation tool, it achieves validation by catching invalid data.)
• NOTE: Learn Pydantic , starlette and Python Type hinting
Pydantic
• Start with BaseModel class • (venv) > python pydantic-examples.py
from enum import Enum • {"brand": "Lancia", "model": "Musa", "year": 2006, "fuel": "PETROL",
"countries": ["Italy", "France"], "note": "No note"}
from typing import List
• Use dict() for returning python dictionary
from pydantic import BaseModel, ValidationError
• Copy() for creating copy of the model
class Fuel(str, Enum):
• Pydantic offers individual field validations and with some additional
PETROL = 'PETROL' packages installed, we can perform email validations, URL validations, and
anything else that comes to mind. Validation is available at the field level,
but also at the object level – when you need to combine different field
DIESEL = 'DIESEL'
values into a single condition – for example, to check that two passwords
have been entered in two fields on a registration page match.
LPG = 'LPG'
• A pattern that is pretty common when working with Pydantic is the model’s
class Car(BaseModel):
inheritance. You may, for instance, define a basic car model with just the
bare minimum fields and then derive, via inheritance, different car models
brand: str
for editing, for showcasing in an endpoint that will feed an image gallery
model: str
year: int
fuel: Fuel
countries: List[str]
note:str=”No note”
car = Car(
brand="Lancia",
model="Musa",
fuel="PETROL",
year="2006",
countries=["Italy","France"]
print(car.json())
Asynchronous I/O
• FastAPI structures endpoints. Endpoint is a unique combination of URL e.g.
localhost:8000, a path (the part after the slash) , and an HTTP method
• E.g. first_endpoint.py
from fastapi import FastAPI
• Asynchronous programming paradigm : The idea is to make operations that
are slow compared to others – such as hefty network calls, reading files from app = FastAPI()
a disk, and similar – run, but at the same time allow the system to respond
to other calls and then return the appropriate response of the long-running @app.get("/")
process, while not blocking the other, less time-consuming responses. This is async def root():
achieved by using an event loop – a manager of asynchronous tasks that
receives requests and can move to the next one, even though the previous return {"message": "Hello FastAPI"}
one hasn’t finished and yielded a response.
• Then run : uvicorn first_endpoint:app --reload
• functions with the async keyword prepended are coroutines – that is, they
run on the event loop • we imported the FastAPI class from the fastapi package. Then, we instantiated an
application object (we called it app since that is considered a good practice, but we
could have chosen any name). This is passed to the uvicorn server
• The basis of any REST API communication is the relevant URLs and paths.
The URL for our local web development server will • we used the @get decorator, which corresponds to the GET method, and we
be http://localhost:8000 since 8000 is the default port that Uvicorn uses. passed a URL – in our case, we used /, which is the root path.
The path part (optional) of an endpoint could be /cars, while http is
the scheme. • The decorated function is called root, another convention, but it could be
called whatever we wanted (any valid Python function name)
• FastAPI encourages the proper use of HTTP verbs concerning the data-
resource operations that they perform, so you should always use POST (or • It is responsible for accepting any arguments (in our case, there aren’t any) and
the @post decorator) when creating new resources responding. The value that’s returned by the function, which in our case is a
simple Python dictionary, will then be transformed into a JSON response and
• HTTP messages consist of a request/status line, headers, and, optionally, returned by the ASGI server as an HTTP response.
body data. Again, FastAPI offers us tools to easily create and modify headers,
set response codes, and do pretty much anything that we please with the
request and response body. • (venv) > http "http://localhost:8000/"
HTTP/1.1 200 OK
content-length: 27
}
HTTPie should show the following output:
FastAPI automatically lists all the endpoints that we define and provides information about the
expected inputs and responses. The documentation is based on the OpenAPI specification and
relies heavily on Python hints and the parsing and validation library Pydantic
More code
• The raw request object in FastAPI is Starlette’s request object and it can be
accessed in our functions once it’s been imported from FastAPI directly.
from fastapi import FastAPI, Request
app = FastAPI()
• Retrieving path and query parameters @app.get("/cars")
return {"car_id":id} • Header: Header parameters are handled in a similar way to query and path
parameters and, as we will see later, cookies. We can collect them, so to
speak, using the Header function. Headers are essential in topics such as
authentication and authorization as they often carry JSON Web
• Output : Tokens (JWTs), which are used for identifying users and their permissions.
(venv) > http "http://localhost:8000/car/1" from fastapi import FastAPI, Header
HTTP/1.1 200 OK app = FastAPI()
content-length: 14 @app.get("/headers")
content-type: application/json async def read_headers(user_agent: str | None =
date: Mon, 28 Mar 2022 20:31:58 GMT Header(None)):
server: uvicorn return {"User-Agent": user_agent}
{ • Cookies : Cookies work in a very similar way and although they can be
"car_id": "1" extracted manually from the Cookies header, the framework offers a utility
function, conveniently named Cookie, that does all the work in a way similar
} to Query, Path, and Header
• Combining • Forms and files – If we have situation where we are not handling JSON, there
are cases that require a different data encoding – forms might be processed
(venv) > http "http://localhost:8000/car/1" by your API, with data encoded as multipart/form-data or form-
urlencoded.
HTTP/1.1 200 OK
• Notice that although we can have multiple Form parameters in a path
content-length: 14 operation, we cannot declare Body fields that we expect to be in JSON. The
HTTP request will have the body encoded using only application/x-www-
content-type: application/json form-urlencoded instead of application/json. This limitation is part of the
HTTP protocol and has nothing to do with FastAPI itself
date: Mon, 28 Mar 2022 20:31:58 GMT
• The simplest way to cover both form cases – with and without including files
server: uvicorn for upload – is to start by installing python-multipart, a streaming multipart
parser for Python. Stop your server and use pip to install it:
{
pip install python-multipart
"car_id": "1"
}
More code
• Response customization:
• FastAPI’s response objects : In all the cases seen till now, a python dictionary was
returned after it was serialized into JSON by FastAPI
• Let us assume status code has to be changed in the response object. For e.g. error
• Another example of FORM function: codes have to be made meaningful. Let us say you do not want to pass 200 OK
from fastapi import FastAPI, status
from fastapi import FastAPI, Form, File, UploadFile
app = FastAPI()
app = FastAPI() @app.get("/", status_code=status.HTTP_208_ALREADY_REPORTED)
"brand": brand, • Pydantic can be used for response modeling as well – we can limit or otherwise
modify the fields that should appear in the response and perform similar checks that
it does for the request body by using the response_model argument
"model": model,
• HTTP errors: FastAPI uses a Python exception, aptly called HTTPExeption, to raise
"file_name":file.filename} HTTP errors. This class allows us to set a status code and set an error message.