Quarto articolo di approfondimento sul mondo delle API – Application Programming Interfaces

Costruiamo un’API RESTful con FastAPI, un framework Python che sta avendo una grande diffusione

La puntata di oggi è dedicata alla costruzione di una API RESTful da zero, utilizzando il framework Python FastAPI.

Ma prima di partire, facciamo un rapido riassunto del viaggio che ci ha portato hands-on alla scoperta delle API – Application Programming Interfaces.

Oggi ci occuperemo della creazione di una API RESTful e lo faremo usando FastAPI. Per prima cosa quindi scopriamo le caratteristiche di questo framework Python.

FastAPI: cos’è

FastAPI è definito come un framework ad elevate performance pronto per l’utilizzo in produzione.

FastAPI è stato rilasciato nel 2018, parliamo quindi di un framework recente, in senso assoluto ma anche se comparato a Django (2005) o Flask (2010).

Sebbene si sottolinei che FastAPI sia stato possibile grazie ai contributi della community , il suo ideatore è stato Sebastián Ramírez Montaño.

FastAPI è realmente “fast”, non solo nel nome. Secondo i benchmark è infatti oggi uno dei framework Python più veloci, in terza posizione dopo Uvicorn e Starlette (entrambi utilizzati da FastAPI stesso).

Caratteristiche principali

FastAPI nasce come un framework asincrono (ASGI – Asynchronous Server Gateway interface), in contrapposizione a Flask e Django ad esempio, nativamente sincroni (WASGI – Web Server Gateway Interface). Questo aspetto spiega largamente il motivo delle performance nettamente superiori rispetto ai suoi predecessori, comparabili a Node o Go.

Inoltre grazie all’uso di Pydantic, FastAPI permette la definizione esplicita (type hints) della tipologia di dati al momento del runtime (riducendo l’incidenza dei bug di circa il 40%), e permettendo anche check automatici tramite IDE e plugin in esso integrabili, evitando tediosi check in fase di debugging.

FastAPI è definito un framework moderno. Questo significa che si rifà a best practice e conoscenze di uso comune nella industry e non richiede quindi un flusso di apprendimento specifico.

FastAPI è basato su open standards, ossia linee guida che permettono di mantenere la tecnologia accessibile, aperta e trasparente.

FastAPI permette anche la generazione automatica di documentazione, grazie a SwaggerUI e ReDocs.

La popolarità di FastAPI è in costante crescita. Il repository GitHub conta oltre 3.9K fork e circa 50K stelle. É utilizzato da società come Microsoft, Uber, Nexflix.

FastAPI vs Flask

Per via dei casi d’uso similari e della struttura dei due framework, FastAPI è spesso indicato come un’alternativa a Flask.

La risposta non può che provenire dai singoli casi d’uso, ma in linea generale possiamo delineare le caratteristiche principali dei due framework.

Flask

  • Maggiore flessibilità.
  • Ampia community e referenze disponibili.
  • Focus sulla sicurezza con integrazioni consolidate come Flask-Security.
  • Facilmente scalabile.

FastAPI

  • Performance eccezionali.
  • Nativamente asincrono.
  • Rispondente ai più aggiornati standard e best practice.
  • Evoluzione recente e in via di definizione.

Costruiamo la nostra API RESTful con FastAPI

Chiarite queste premesse, mettiamoci ora al lavoro.

Andremo a realizzare un’API RESTful che permetterà di accedere e interagire con un dataset minimale creato contestualmente alla nostra applicazione.

Questa volta parleremo di videogame.

Qui un assaggio del prodotto finito:

Se non hai neppure voglia di mettere mano al codice ma vuoi provare comunque l’applicativo, ne ho creato una versione interattiva su Replit.com.

La trovi qui: https://replit.com/@carlo_/fastapitest#main.py 

Ma ora partiamo con il tutorial passo-passo.

Creazione dell’ambiente

Come usuale, per prima cosa crea un ambiente virtuale:

python3 -m venv my_env

Attiva poi l’ambiente virtuale creato (segui le istruzioni in base al tuo sistema operativo) e dopodiché installa le dipendenze necessarie

pip install wheel
pip install fastapi[all]

In alternativa puoi anche clonare direttamente il repository di questo tutorial:

git clone https://github.com/carloocchiena/fastAPI_RESTful

e installare tutte le dipendenze direttamente dal file requirements.txt.

pip install -r requirements.txt

Import delle librerie necessarie

A questo punto creiamo un file .py e iniziamo la costruzione della nostra API.

Per prima cosa importiamo le librerie necessarie

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Optional
import uvicorn

Creazione del dataset

In modo altrettanto lineare e direi auto esplicativo, instanziamo la nostra app, creiamo il dataset, e definiamo la tipizzazione dei singoli elementi.

# instantiate our FastApi application
app = FastAPI()

# initiate our test dataset
videogames = [
{'title': 'Doom Eternal', 'rating': 4, 'cost': 45},
{'title': 'Days Gone', 'rating': 1, 'cost': 25},
{'title': 'The Last Of Us', 'rating': 3, 'cost': 75},
{'title': 'Detroit:Become Human', 'rating': 5, 'cost': 30},
{'title': 'Cyberpunk 2077', 'rating': 2, 'cost': 5},
]

# define the types of our dataset objects
class Videogame(BaseModel):
title: str
rating: int
cost: int

Creiamo una funzione di controllo

Andremo molte volte a chiamare i nostri oggetti tramite API e vogliamo essere certi che in caso di errore ci venga ritornato uno stato 404. Possiamo agilmente fare ciò con una funzione. Ci assicuriamo che l’oggetto identificato dall’ID proposto sia esistente; se così non è, chiediamo venga ritornato un messaggio di errore.

# check existance of the videogame
def videogame_check(videogame_id):
    if not videogames[videogame_id]:
        raise HTTPException(status_code=404, detail='Game Not Found')

Un primo test

Anche se non strettamente necessario ai fini della nostra API, aggiungiamo un percorso per la home page, così da avere un messaggio appena lanciamo la nostra applicazione. Questo ci aiuta a prendere confidenza con la sintassi di FastAPI.

Notiamo da un parte la similitudine con Flask, dall’altra l’utilizzo di una funzione asincrona (in questo caso a scopo meramente illustrativo).

# create our home page route
@app.get('/')
async def root():
   return {'message': 'Hello world'}

Inoltre, dopo il consueto check “if __name__ == ‘__main__'”, che ci permette di eseguire l’applicazione solo se invocata nativamente, e non importata, lanciamo il nostro script.

# launch our application with uvicorn
if __name__ == '__main__':
    uvicorn.run(app,host="0.0.0.0",port="8080")

Giunti fin qui siamo in grado di fare un primo run.

Se tutto funziona, collegandoci al nostro localhost alla porta indicata (http://127.0.0.1:8080), vedremo comparire il messaggio di saluto.

Creiamo i metodi della nostra API

Addentriamoci ora nel vivo della nostra RESTful API, aggiungendo i metodi GET, POST, PUT, DELETE.

GET

Potremmo creare una semplicissima funzione GET, ma già che ci siamo aggiungiamo un pizzico di sapore integrando con un URL parametrizzato che consente di filtrare i videogiochi in base al loro ranking.

Questo ci permette di scoprire sia la sintassi da utilizzare per inserire parametri aggiuntivi, sia la loro opzionalità con il prefisso Optional.

La funzione è parlante: posso inserire nella mia chiamata un valore di max e min rating e, se tali valori sono entrambi valorizzati, avrò in ritorno gli oggetti così selezionati.

Per semplicità, consideriamo sia massimo che minimo senza gestire il caso in cui sia fornito solo uno dei due estremi.

# GET
@app.get('/videogames')
def videogame_list(min_rate:Optional[int]=None, max_rate:Optional[int]=None):

    if min_rate and max_rate:

        filtered_videogames = list(
            filter(lambda rating: (min_rate <= rating['rating'] <= max_rate), videogames)
        )

       return {'videogames': filtered_videogames}

    return {'videogames': videogames}

Voglio poi aggiungere un ulteriore metodo che mi permetta di chiamare direttamente un oggetto nella lista, tramite il suo identificativo. Come abbiamo visto in precedenza, vogliamo che se l’oggetto non esiste, ci venga ritornato un errore, pertanto invochiamo anche la nostra funzione di check.

# check if a videogames is within the list
@app.get('/videogames/{videogame_id}')
def videogame_detail(videogame_id: int):
    videogame_check(videogame_id)
    return {'videogames': videogames[videogame_id]}

A questo punto, possiamo testare questa parte, ad esempio con una chiamata all’URL:

http://127.0.0.1:8080/videogames?min_rate=1&max_rate=2

Avremo indietro i seguenti oggetti:

{"videogames":[{"title":"Days Gone","rating":1,"cost":25},{"title":"Cyberpunk 2077","rating":2,"cost":5}]}
POST

Possiamo dire che giunti fino qui, il resto procede praticamente in automatico. Aggiungiamo una chiamata POST che consenta di aggiungere un videogioco alla nostra lista e ci ritorni proprio l’oggetto aggiunto (ossia l’ultimo della lista).

Come intuibile si segue la stessa struttura precedente, anzi, qui addirittura semplificata.

# POST
@app.post('/videogames')
def videogame_add(videogame: Videogame):
    videogames.append(videogame)

    return {'videogames': videogames[-1]}
PUT

Poi aggiungiamo un metodo PUT per modificare invece il nostro dataset.

# PUT
@app.put('/videogames')
def videogame_update(videogame: Videogame, videogame_id: int):
    videogame_check(videogame_id)
    videogames[videogame_id].update(videogame)

    return {'videogames': videogames[videogame_id]}
DELETE

E infine il metodo delete. Anche qui, tutto lineare:

# DELETE
@app.delete('/videogames')
def videogame_delete(videogame_id: int):
    videogame_check(videogame_id)
    del videogames[videogame_id]

    return {'videogames': videogames}

Il prodotto finito: la nostra RESTful API

Abbiamo creato la nostra RESTful API con FastAPI in poco meno di cento righe di codice. Potremmo già essere soddisfatti così, ma la parte più bella invece deve ancora arrivare.

Proprio per quanto specificato nelle premesse, con FastAPI la documentazione della nostra API ci viene fornita inclusa nel prezzo.

Ecco che quindi chiamando l’endpoint di SwaggerUI otteniamo una dashboard interattiva che permette anche di testare tutti i singoli elementi fin qui creati, con tanto di istruzioni.

Buttiamoci quindi su http://127.0.0.1:8080/docs per ottenere questa dashboard interattiva:

aziona fastAPI API GUI

Il riassunto del nostro viaggio

Giunti fin qui con successo, abbiamo scoperto cosa sia FastAPI, come permetta di creare una API RESTful, e quali siano le caratteristiche principali di questo moderno framework. Non male!

Per approfondire, qui trovi la documentazione ufficiale di FastAPI.

aziona risorse ebook guida al debito tecnico

Scarica l’ebook “La guida definitiva alla comprensione del Debito Tecnico”

Iscriviti alla newsletter e scarica l’ebook.

Ricevi aggiornamenti, tips e approfondimenti su tecnologia, innovazione e imprenditoria.