Il miglior modo per capire è fare. E quindi, proviamo a costruire da zero la nostra Web API con Python

La volta scorsa abbiamo parlato della teoria – tutto quello che avresti voluto sapere sulle API ma non hai mai osato chiedere (qui l’articolo). Oggi ci addentriamo nella parte pratica, sviluppando da zero un’API con Python.

Un progetto che ci permette di capire meglio come funziona realmente il backstage (o meglio, il backend) di una API.

Cosa facciamo

Costruiremo una Web API collegata ad un database SQL esterno, una home page web in HTML, e un backend in Python per connettere il tutto.
Quindi sebbene in modo semplice, costruiremo da zero un ambiente full-stack utilizzando diversi linguaggi. Un’ottima palestra per prendere confidenza con le nostre API!

Visto che ci vogliamo anche divertire, non creeremo un noioso progetto che parlerà di mele, pere, banane, ma creeremo un database bello cattivo pieno di album metal con informazioni sull’artista e sul genere, e permetteremo di eseguire chiamate API su questi parametri.

Premesse

Per mantenere questo tutorial snello abbiamo apportato alcune semplificazioni rispetto a quelle che sono le best practice dello sviluppo con Python e di API.

  • Pur riprendendo alcuni concetti REST, l’API che svilupperemo non rientra in questa classificazione. Per questo motivo parliamo genericamente di Web API.
  • Non utilizzeremo ambienti virtuali (si, dovresti sempre usare ambienti virtuali per ogni progetto!).
  • Utilizzeremo un unico file che conterrà funzioni, HTML e la nostra app Flask. A discapito di eleganza, leggibilità e guideline, ma mantenendo maggiore semplicità.
  • Non utilizzeremo alcun elemento di stile (CSS). Produrremo quindi una semplice Home Page testuale, elementare.
  • Sorvoleremo ogni accenno alla documentazione, testing, sicurezza, e tutto il protocollo che andrebbe seguito naturalmente in un progetto nel mondo reale.

Installiamo Python

Se vuoi replicare questo progetto in locale sul tuo computer, ti serve un’installazione di Python 3.x.x.

Python è un linguaggio di programmazione Open Source, liberamente distribuito. Puoi scaricare l’ultima versione, adatta al tuo sistema operativo, dal sito ufficiale. Se hai Windows, puoi anche usare il Microsoft Store e seguire il processo guidato.

Una piccola curiosità: il creatore di Python, Guido Van Rossum, è attualmente un impiegato Microsoft. E proprio Microsoft è oggi il maggior sostenitore finanziario del progetto Python.

Anaconda

In alternativa, se vuoi provare una distro più completa puoi passare subito ad Anaconda. Anaconda è la distribuzione di Python più usata al mondo con oltre  25 milioni di utenze globali. Il download include oltre a Python, anche un gran numero di librerie, focalizzate in particolare sull’attività di Data Science, un ambiente di sviluppo integrato (Integrated Development Environment, o IDE), un package manager con ambienti virtuali, una User Interface e diverse altre amenità. É un’installazione bella corposa, molto comoda se intendi utilizzare Python per un po’ e non limitarti solo a fare questo piccolo progetto. É la mia scelta d’elezione, ma non necessaria per quel che vedremo oggi.

Replit

In ultimo se invece non vuoi installare nulla puoi provare Replit.com. Questa startup offre un ambiente di sviluppo online gratuito per moltissimi linguaggi di programmazione e non richiede altro che la creazione di un account. Utilizzo le loro feature da diversi anni e con piacere vedo che finalmente stiano ottenendo il riscontro che meritano. É una soluzione molto snella e light per provare “alla veloce” senza doversi curare di installare nulla sulla propria macchina. Comunque in questo tutorial consideriamo un ambiente di sviluppo locale, quindi non tratteremo nello specifico l’utilizzo di Replit.

Installiamo Flask

Una volta ottenuto Python ti serve Flask, il micro-framework che utilizzeremo per la creazione del nostro mini-portale. É sufficiente digitare in una shell Python:

pip install flask

Come sempre, suggerisco di partire dalla documentazione per evitare di procedere a tentoni. Anche se tutto sarà spiegato passo-passo.

Costruiamo il nostro database

Dobbiamo costruire tutto da zero, e quindi anche il database va creato e popolato.

Abbiamo molti modi di costruire un database. Potremmo utilizzare Python, che offre nativamente questa possibilità. Potremmo usare Access. Potremmo usare un client SQL installato localmente. Ma in questo tutorial preferisco semplificare e usare un utile tool 100% web-based, SQL Online IDE.

SQL Online è un ambiente di sviluppo online interamente gratuito e che non necessita di login. Ottimo per prendere confidenza con le basi del linguaggio SQL. Il portale integra SQLite, MariaDB, PostgreSQL, MS SQL, Oracle, e permette anche di creare immagini Docker. Comodissimo.

Arrivati sul portale dobbiamo per prima cosa piazzare un bel drop table per cancellare tutti i dati demo:

DROP TABLE demo;

E poi creare effettivamente il nostro DB e popolarlo:

A questo punto vedremo apparire nel menu la nostra tabella, che possiamo scaricare in formato .db e salvare nel folder dove andremo a creare anche il nostro script Python. Per questo tutorial abbiamo scelto il nome “music.db”.

La query è auto esplicativa pertanto potete inserire campi e contenuti diversi a piacere.

Hello, World!

Ora andiamo nel nostro ambiente di sviluppo o text editor e iniziamo a dare forma al progetto.

Per prendere confidenza con Flask, partiamo con un il classico Hello World

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
    return "<p>Hello, World!</p>"

Eseguiamo questo semplice script e andiamo alla porta di default usata da Flask (port 5000 sul localhost, http://127.0.0.1:5000/). Vedremo proprio una finestra del browser con il nostro “Hello, World!”. Incredibile! in pochi minuti abbiamo già creato la nostra pagina web. Semplice, brutta, ma online!

Qui già intuiamo la potenza di Flask e della logica a micro-servizi propria di questo framework: aggiungendo un mattoncino alla volta, con step tra loro indipendenti, otterremo un prodotto finito completo, un sito web che dialoga con un database esterno. Un’applicativo full-stack, naturalmente basilare, elementare, ridotto ai minimi termini. Complimenti, un inizio!

Iniziamo a costruire la nostra Web API con Python

Diamo uno sguardo al risultato finale, per poi commentarlo passo dopo passo:

Per prima cosa importiamo le librerie necessarie; poche e essenziali, e molto comuni.

import sqlite3
import flask
from flask import request, jsonify

Istanziamo poi la nostra Web App Flask.

# iniating Flask application object
app = flask.Flask(__name__)
app.config["DEBUG"] = True

Ora passiamo a definire la variabile relativa al nostro db “music.db”.

# defining our SQLlite object
DB = "music.db"

Ci serve poi una funzione che trasformi gli elementi che estrarremo dalla nostra tabella in un oggetto dizionario invece che lista. I dizionari sono una tipologia di struttura dati propria di Python. Per semplicità diciamo che prevedono un valore chiave e un valore oggetto da esso indicato, ad esempio {“posizione”: 3}.

Il costrutto con parentesi graffe li fa assomigliare proprio a un file JSON, l’output che useremo per la nostra API. Ecco che, semplificando, abbiamo intuito la nostra necessità.

Per avere una chiara overview sulle strutture dati di Python, il rimando è alla documentazione ufficiale.

def dict_factory(cursor, row):
"""Convert DB items into dictionary objects.

This function convert items from the db in the form of a dictionary instead than of a list. 
It ensure a proper jsonification of the items.
"""
    d = dict()
    for idx, col in enumerate(cursor.description):
    d[col[0]] = row[idx]
    return d

Creiamo la home page e la pagina 404

Ora gettiamo le basi del nostro pur semplicissimo sito web: una home page e una pagina di errore.

# routing home page 
@app.route('/', methods=["GET"])
def home():
    return '''<h1>\m/ Top Metal Album Archive \m/</h1>
    <p> Access the archive with our API └[◍!◎]┘ </p> '''

# routing error page 404
@app.errorhandler(404)
def page_not_found(e):
    return "<h1>OOPS</h1> <p> Page not found </p>", 404

Ecco qui il risultato:

Come detto nelle premesse stiamo lavorando ai minimi termini, in quanto la corretta metodologia di sviluppo web con Flask prevede l’uso di un template master e di diversi template pagina che rimandano allo stesso, salvati in un folder e richiamati dalle funzioni della nostra app. Stessa cosa per eventuali elementi media (immagini e elementi grafici) da mostrare in pagina. Ma tutto questo esula dal nostro tutorial (magari ne parleremo in uno dei prossimi? Facci sapere se la cosa ti interessa!)

Gettiamo le basi della nostra Web API

Ora possiamo occuparci della nostra Web API. Per prima cosa definiamo una URL sensata. Anche se stiamo facendo un semplice applicativo, non trascuriamo gli elementi cardine dell’API design.

Questo l’URL che vogliamo utilizzare: /api/v1/resources/albums/all

  • Contiene l’indicazione che si tratta di un servizio API.
  • Contiene la versione, così possiamo aggiornarla in futuro senza rompere tutto.
  • Contiene la definizione resources e albums. Chiaro quindi che abbiamo una pluralità di oggetti.
  • E infine, all, ossia da qui vediamo tutto il nostro db.

La potenza di tutto ciò? Attraverso una connessione API possiamo dare vista aggiornata in real time ad un DB situato su un nostro server a una pluralità di utenti in modo perfettamente coordinato, seguendo un protocollo ben codificato.

# routing full view of albums list
@app.route('/api/v1/resources/albums/all', methods=["GET"])
def api_all():
    conn = sqlite3.connect(DB)
    conn.row_factory = dict_factory
    cur = conn.cursor()
    all_album = cur.execute("SELECT * FROM album;").fetchall()

    return jsonify(all_album)

Se quindi ci rechiamo alla URL creata, ossia http://127.0.0.1:5000/api/v1/resources/albums/all , vedremo una foto del database creato precedentemente:

Creiamo ora il cuore della nostra Web API con Python

Andiamo ora a implementare la parte più corposa della nostra API. Anche se a prima vista può risultare complessa, questa sezione è comunque molto lineare. Definiamo i parametri della query, che corrispondono ai campi del nostro database.

E poi con Python replichiamo una query SQL che richiama i campi richiesti dalla chiamata API e li ritorna sotto forma di oggetto JSON.

# routing api connection to album db
@app.route("/api/v1/resources/albums", methods=["GET"])
def api_filter():
"""API items available at the date

Currently the following parameters have been instantiated: id_key (primary key), artist, album and genre.
"""
    query_parameters = request.args

    id_key = query_parameters.get("id")
    artist = query_parameters.get("artist")
    album = query_parameters.get("album")
    genre = query_parameters.get("genre")

    #building our SQL query
    query = "SELECT * FROM album WHERE"
    to_filter = []

    if id_key:
        query += ' id=? AND'
        to_filter.append(id_key)
    if artist:
       query += ' artist=? AND'
       to_filter.append(artist)
    if album:
        query += ' album=? AND'
        to_filter.append(album)
    if genre:
        query += ' genre=? AND'
        to_filter.append(genre)
    if not (id_key or artist or album or genre):
        return page_not_found(404)

    # this is needed to clean the SQL query after the last item is added;
    # basically it removes the " AND" and add a ";"
    query = query[:-4] + ";"

    conn = sqlite3.connect(DB)
    conn.row_factory = dict_factory
    cur = conn.cursor()

    results = cur.execute(query, to_filter).fetchall()

    return jsonify(results)

Ora non ci resta che terminare il nostro script e testare!

# run the app
if __name__ == '__main__':
    app.run(use_reloader=False)

Vediamo un caso di test

Ora siamo pronti a fare un caso di test reale. Voglio sapere quali album dei Sepultura abbiamo a disposizione.

Niente di più semplice! L’URL http://127.0.0.1:5000/api/v1/resources/albums?artist=Sepultura

ci ritornerà proprio gli album cercati, con tutti i dettagli a disposizione

[
  {
    "ALBUM": "Roots", 
    "ARTIST": "Sepultura", 
    "GENRE": "Death Metal", 
    "ID": 2
  }, 
  {
    "ALBUM": "Chaos AD", 
    "ARTIST": "Sepultura", 
    "GENRE": "Death Metal", 
    "ID": 6
  }
]

Vogliamo invece scoprire quali album Death Metal abbiamo in casa? Ok andiamo!

http://127.0.0.1:5000/api/v1/resources/albums?genre=Death%20Metal

Ci porta a

[
  {
    "ALBUM": "Roots", 
    "ARTIST": "Sepultura", 
    "GENRE": "Death Metal", 
    "ID": 2
  }, 
  {
    "ALBUM": "Obituary", 
    "ARTIST": "Obituary", 
    "GENRE": "Death Metal", 
    "ID": 3
  }, 
  {
    "ALBUM": "Chaos AD", 
    "ARTIST": "Sepultura", 
    "GENRE": "Death Metal", 
    "ID": 6
  }
]

Sviluppo di una Web API con Python: cosa abbiamo imparato?

Anche se non siamo entrati nei singoli dettagli, abbiamo attraversato diversi punti essenziali:

  • Installazione di Python.
  • Creazione di un database.
  • Creazione di un semplicissimo sito web.
  • Possibilità di dialogare tramite il nostro sito web con il database esterno.
  • Appreso i rudimenti base della creazione di un’API Web con Python.

Il prossimo step potrebbe essere, come accedere sistematicamente alla nostra API dall’esterno, senza dover scrivere manualmente le URL. Magari ne parleremo in uno dei prossimi episodi.

Ah, a proposito, ti piace questo genere di contenuti? Se sì facci sapere il tuo gradimento, ci incoraggerà a crearne altri! E se vuoi puoi seguirci su GitHub! Qui il link a questo progetto.

Per approfondire

Passa dalla teoria alla pratica con i nostri tutorial passo-passo:

E resta aggiornato sulle nuove tecnologie con i nostri consigli di lettura:

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.