Understanding FastAPI: The Basics

Rafael de Oliveira Marques
3 min readJun 23, 2024

--

This post lives in:

I’ve been working with FastAPI for a while now, and I decided to start digging a little deeper on it’s internals.

Let’s start from the beginning:

What is FastAPI?

As the docs says:

FastAPI is a modern, fast (high-performance), web framework for building APIs with Python based on standard Python type hints.

So here we have a good idea about what is FastAPI: A web framework for building APIs.

But it’s not a framework built from scratch, it’s a framework that was built on top of another framework: Starlette.

And what is Starlette?

If we go to starlette’s website, we’ll find that:

Starlette is a lightweight ASGI framework/toolkit, which is ideal for building async web services in Python.

And what is ASGI?

ASGI, or Asynchronous Server Gateway Interface is a specification that proposes an interface between web servers and python applications.

When we are running our fastapi application, we’re using an ASGI server that will forward the request to our app.

Some of the most well-known asgi servers are:

Let’s recap

FastAPI is a modern webframework written in python that is built on top Starlette, which in turn is a lightweight ASGI framework that needs an ASGI server to run.

Let’s create a basic ASGI application

So if we want to understand how FastAPI works, we must start from the beginning: a simple asgi application:

async def app(scope, receive, send):
await send({
"type": "http.response.start",
"status": 200,
"headers": [
[b"content-type", b"text/plain"],
],
})
await send({
"type": "http.response.body",
"body": b"Hello, World!",
})

Can you imagine that all features that FastAPI offers you, all middlewares and error handling, OpenAPI docs, etc., starts from this?

That’s how ASGI is specified: a single asynchronous callable that takes a dict and two asynchronous callables as parameters.

And it works, without any webframework installed! Now let’s check if it’s really working:

First, install an ASGI server:

pip install uvicorn

And create a python file called app with the code above.

Let’s run it and see if it’s working:

uvicorn app:app

Now enter http://localhost:8000 in your browser:

INFO:     Started server process [4808]
INFO: Waiting for application startup.
INFO: ASGI 'lifespan' protocol appears unsupported.
INFO: Application startup complete.
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: 127.0.0.1:64045 - "GET / HTTP/1.1" 200 OK

Let’s change to hypercorn to see if we are not tied to uvicorn somehow:

pip install hypercorn

And we can see it still works:

hypercorn app:app
[2024-06-22 19:00:55 -0300] [13008] [WARNING] ASGI Framework Lifespan error, continuing without Lifespan support
[2024-06-22 19:00:55 -0300] [13008] [INFO] Running on http://127.0.0.1:8000 (CTRL + C to quit)

Creating the simplest FastAPI clone ever

Now that we know what’s beneath FastAPI, we can start playing a little bit and create the smallest, simpler ASGI framework ever:

class SimplestFrameworkEver:
async def __call__(self, scope, receive, send):
await send({
"type": "http.response.start",
"status": 200,
"headers": [
[b"content-type", b"text/plain"],
],

})
await send({
"type": "http.response.body",
"body": b"Hello, World!",
})


app = SimplestFrameworkEver()

And you can still run it like before, with:

hypercorn app:app

or

uvicorn app:app

Next steps

Now that we can understand the basics on which FastAPI is made, we can move on to see:

  • how Starllete works
  • how FastAPI extends Starllete

Stay tuned for the next posts ;)

--

--

No responses yet