Skip to article frontmatterSkip to article content

Python micro-framework 🐍 - fairly recent (2018);
occupies the same space as

🚧 Micro-framework doesn’t mean not usable on large projects ⚠️


FastAPI

similar on the surface to Flask, but much more modern!


Why FastAPI and not something else

1️⃣ You all more or less know how to do Python 🐍

so we eliminate everything that’s not Python-based

2️⃣ We’ll try to teach you things used elsewhere
And the FastAPI trend indeed seems to be experiencing spectacular growth!


Graphical User Interface

But actually... why are we interested in this?
The GUI is what bridges 🌉 between:

a calculation/data processing code/...
and a graphical interface
so very relevant for the “Computer Science Projects” at the end of S2

Two approaches:

Old school
Using graphical libraries and developing a thick client

New age

Using the browser


FastAPI: we already know a bit

we already vaguely know how to use it, remember, we’ve already seen
how to install FastAPI
and
how to make a minimal server with FastAPI

notice how simple it is to get started 😯
this is an advantage of Flask/FastAPI compared to Django
which requires a more advanced setup to start a project


Quick recap

  • Step 1️⃣:

from fastapi import FastAPI
  • Step 2️⃣

app = FastAPI()

Then we attach Python functions to URL paths
we call these functions route handlers or router functions

@app.get("/a/path/target")
def the_corresponding_function():
  // does very smart things
  return a_result    # which can be data or html or ...

And to start the server?

from the terminal

fastapi dev my_app.py

the server in development mode

fastapi dev my_app.py --port 8080

or on another port

or also

fastapi run my_app.py

in production mode


Parameters in a GET

We can write slightly more sophisticated URLs:

Need to retrieve the arguments in the handler function 🤔


FastAPI has it all figured out

@app.get("/some/route/data")
def get_parameters(
        name: str,
        age: int):
    return {'name': name, 'age': age}

you just need to declare the parameters
with their type
and FastAPI does the rest
and even type conversion

🚧 No notion of type in network exchanges, everything is a string 🚧


Parametric URL

Possibility offered by Flask to define parameters within a URL itself

Special case for /

  • by default a parameter does not contain a slash /

  • but in a route you can declare
    "/my/route/{parameter:path}"

    to allow slashes \ in the parameter

@app.get("/my/route/{parameter}")
def url_parameter(parameter: int):
    return {"square": parameter**2}

and of course you can also receive multiple parameters this way


A random generator (exercise)

in python/random-generator.py

  • read the code

  • start the server

Random number generation API

  • /api/integer: generates integers

  • /api/float: generates floats

from the browser - or the terminal with httpie - query the endpoint /api/integer

# don't hesitate to also see what it gives with the -v option
# which will ALSO show you the request sent
http :8000/api/integer

Exercise solutions

Solution to Exercise 1
  • in the browser:
    http://localhost:8000/api/float?min=10&max=50&count=4

  • it’s important to understand how http works well
    with httpie, it’s simpler:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # long version - watch out for quotes!
    # because of the & which is a special character in bash
    http ":8000/api/float?min=10&max=50&count=4"
    
    # short version, to pass parameters with GET
    # you must use ==
    http :8000/api/float min==10 max==50 count==4
    
    # warning the simple = is for POST requests!
    # if we use = it doesn't do what we want!
    # DON'T DO IT LIKE THIS!
    # http GET :8000/api/float min=10 max=50 count=4
Solution to Exercise 2

as it stands, there is no control on the parameters, so the server calls the random.uniform function with invalid parameters and that generates a 500 error

to address this, several choices are possible:

  • either we add a check in the random_floats function to verify that min < max and if not we raise an HTTP 400 (Bad Request) exception

  • or we use Pydantic’s validation features; but for now that’s premature since we haven’t seen Pydantic yet 😉

so for now we’ll settle for the 1st solution

1
2
3
4
5
6
from fastapi import HTTPException

def random_floats(min: float, max: float) -> float:
    if min >= max:
        raise HTTPException(status_code=400, detail="Invalid range")
    return random.uniform(min, max)

HTTP verbs

Quick reminder from the 1st episode, HTTP different possible requests

These are the main types of requests but there are others, for the complete list you can check here: Hypertext Transfer Protocol.


Parameters in a POST

however for POST, PATCH, DELETE requests, ...
the parameters are passed in the body of the request

Let’s look at an example


the POST request

And to start let’s look at what is sent by httpie when we do a POST

As we can see, the parameters are sent in JSON format
in the Body of the request - i.e. after the headers

Remember this well, it’s important!
This is the process we’ll need to use when we want to send data to the server (and especially when it’s the frontend sending the request via JS)


on the FastAPI side

Here now is the FastAPI code that works well to handle this request

1
2
3
4
5
6
7
from fastapi import Body

@app.post("/api/seed")
# with Body() we indicate that the parameter comes from the request body
def set_seed(seed_value: int=Body(..., embed=True)):
    random.seed(seed_value)
    return {"message": f"Seed set to {seed_value}"}

What’s next

At this point you know how to implement FastAPI endpoints that handle GET and POST requests with parameters

We have many other things to see, including:

We’ll see that in the following episodes...