Specificație API JSON este o modalitate puternică de a permite comunicarea între client și server. Specifică structura cererilor și răspunsurilor trimise între cele două, utilizând formatul JSON.

Ca format de date, JSON are avantajele de a fi ușor și lizibil. Acest lucru face foarte ușor să lucrați rapid și productiv. Specificația este concepută pentru a minimiza numărul de solicitări și cantitatea de date care trebuie trimise între client și server.

Aici puteți afla cum să creați un API JSON de bază folosind Python și Flask. Apoi, restul articolului vă va arăta cum să încercați unele dintre caracteristicile pe care le poate oferi specificațiile API JSON.

Flask este o bibliotecă Python care oferă un „micro-cadru” pentru dezvoltarea web. Este excelent pentru o dezvoltare rapidă, deoarece vine cu o funcționalitate de bază simplă, dar extensibilă.

Un exemplu cu adevărat de bază despre cum să trimiteți un răspuns de tip JSON folosind Flask este prezentat mai jos:

from flask import Flask

app = Flask(__name__)

@app.route('/')
def example():
   return '{"name":"Bob"}'

if __name__ == '__main__':
    app.run()

Acest articol va folosi două suplimente pentru Flask:

  • Flask-REST-JSONAPI va ajuta la dezvoltarea unui API care urmează îndeaproape specificațiile API JSON.
  • Flask-SQLAlchemy voi folosi SQLAlchimie pentru a face crearea și interacțiunea cu o bază de date simplă foarte simplă.

Imaginea de ansamblu

Scopul final este de a crea un API care să permită interacțiunea client-parte cu o bază de date subiacentă. Vor exista câteva straturi între baza de date și client – un strat de abstractizare a datelor și un strat de manager de resurse.

Cum se construieste un API JSON cu Python

Iată o prezentare generală a pașilor implicați:

  1. Definiți o bază de date utilizând Flask-SQLAlchemy
  2. Creați o abstractizare a datelor cu Marshmallow-JSONAPI
  3. Creați administratori de resurse cu Flask-REST-JSONAPI
  4. Creați puncte finale URL și porniți serverul cu Flask

Acest exemplu va folosi o schemă simplă care descrie artiști moderni și relațiile lor cu diferite opere de artă.

Instalați totul

Înainte de a începe, va trebui să configurați proiectul. Aceasta implică crearea unui spațiu de lucru și a unui mediu virtual, instalarea modulelor necesare și crearea fișierelor principale Python și a bazei de date pentru proiect.

Din linia de comandă creați un nou director și navigați în interior.

$ mkdir flask-jsonapi-demo
$ cd flask-jsonapi-demo/

Este o bună practică creați medii virtuale pentru fiecare proiect Python. Puteți sări peste acest pas, dar este foarte recomandat.

$ python -m venv .venv
$ source .venv/bin/activate

Odată ce mediul dvs. virtual a fost creat și activat, puteți instala modulele necesare pentru acest proiect.

$ pip install flask-rest-jsonapi flask-sqlalchemy

Tot ce veți avea nevoie va fi instalat ca cerințe pentru aceste două extensii. Aceasta include Flask în sine și SQLAlchemy.

Următorul pas este de a crea un fișier Python și o bază de date pentru proiect.

$ touch application.py artists.db

Creați schema bazei de date

Aici, veți începe modificarea application.py pentru a defini și a crea schema bazei de date pentru proiect.

Deschis application.py în editorul de text preferat. Începeți prin importul unor module. Pentru claritate, modulele vor fi importate pe măsură ce mergeți.

Apoi, creați un obiect numit app ca o instanță a clasei Flask.

După aceea, utilizați SQLAlchemy pentru a vă conecta la fișierul bazei de date pe care l-ați creat. Etapa finală este definirea și crearea unui tabel numit artists.

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

# Create a new Flask application
app = Flask(__name__)

# Set up SQLAlchemy
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////artists.db'
db = SQLAlchemy(app)

# Define a class for the Artist table
class Artist(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String)
    birth_year = db.Column(db.Integer)
    genre = db.Column(db.String)

# Create the table
db.create_all()

Crearea unui strat de abstractizare

Următorul pas folosește Marshmallow-JSONAPI modul pentru a crea o abstractizare logică a datelor peste tabelele tocmai definite.

Motivul pentru a crea acest strat de abstractizare este simplu. Vă oferă mai mult control asupra modului în care datele dvs. subiacente sunt expuse prin intermediul API-ului. Gândiți-vă la acest strat ca la un obiectiv prin care clientul API poate vizualiza în mod clar datele subiacente și numai biții pe care trebuie să le vadă.

1611651969 452 Cum se construieste un API JSON cu Python

În codul de mai jos, stratul de abstractizare a datelor este definit ca o clasă care moștenește de la Marshmallow-JSONAPI Schema clasă. Acesta va oferi acces prin API atât la înregistrări individuale, cât și la înregistrări multiple din tabelul artiștilor.

În interiorul acestui bloc, Meta clasa definește unele metadate. Mai exact, numele punctului final URL pentru interacțiunea cu înregistrări individuale va fi artist_one, unde fiecare artist va fi identificat printr-un parametru URL <id>. Numele punctului final pentru interacțiunea cu multe înregistrări va fi artist_many.

Restul atributelor definite se referă la coloanele din tabelul artiștilor. Aici puteți controla în continuare modul în care fiecare este expus prin API.

De exemplu, atunci când faceți cereri POST pentru a adăuga artiști noi la baza de date, vă puteți asigura că name câmpul este obligatoriu prin setare required=True.

Și dacă din orice motiv nu ați dorit birth_year câmp care urmează să fie returnat atunci când faceți cereri GET, puteți specifica acest lucru setând load_only=True.

from marshmallow_jsonapi.flask import Schema
from marshmallow_jsonapi import fields

# Create data abstraction layer
class ArtistSchema(Schema):
    class Meta:
        type_ = 'artist'
        self_view = 'artist_one'
        self_view_kwargs = {'id': '<id>'}
        self_view_many = 'artist_many'

    id = fields.Integer()
    name = fields.Str(required=True)
    birth_year = fields.Integer(load_only=True)
    genre = fields.Str()

Creați administratori de resurse și puncte finale URL

Piesa finală a puzzle-ului este de a crea un manager de resurse și un punct final corespunzător pentru fiecare dintre trasee / artiști și / artiști / id.

Fiecare manager de resurse este definit ca o clasă care moștenește din clasele Flask-REST-JSONAPI ResourceList și ResourceDetail.

Aici iau două atribute. schema este folosit pentru a indica stratul de abstractizare a datelor pe care îl folosește managerul de resurse și data_layer indică sesiunea și modelul de date care vor fi utilizate pentru stratul de date.

Apoi, definiți api ca o instanță a lui Flask-REST-JSONAPI Api și creați rutele pentru API cu api.route(). Această metodă ia trei argumente – clasa stratului de abstractizare a datelor, numele punctului final și calea URL.

Ultimul pas este să scrieți o buclă principală pentru a lansa aplicația în modul de depanare atunci când scriptul este rulat direct. Modul de depanare este excelent pentru dezvoltare, dar nu este potrivit pentru a rula în producție.

# Create resource managers and endpoints

from flask_rest_jsonapi import Api, ResourceDetail, ResourceList

class ArtistMany(ResourceList):
    schema = ArtistSchema
    data_layer = {'session': db.session,
                  'model': Artist}

class ArtistOne(ResourceDetail):
    schema = ArtistSchema
    data_layer = {'session': db.session,
                  'model': Artist}

api = Api(app)
api.route(ArtistMany, 'artist_many', '/artists')
api.route(ArtistOne, 'artist_one', '/artists/<int:id>')

# main loop to run app in debug mode
if __name__ == '__main__':
    app.run(debug=True)

Faceți solicitări GET și POST

Acum puteți începe să utilizați API pentru faceți cereri HTTP. Acest lucru ar putea fi de la un browser web, sau dintr-un instrument de linie de comandă, cum ar fi curl, sau dintr-un alt program (de exemplu, un script Python folosind biblioteca Cereri).

Pentru a lansa serverul, rulați fișierul application.py script cu:

$ python application.py

În browserul dvs., navigați la http: // localhost: 5000 / artiști. Veți vedea o ieșire JSON a tuturor înregistrărilor din baza de date până acum. Cu excepția faptului că nu există.

Pentru a începe să adăugați înregistrări în baza de date, puteți face o cerere POST. Un mod de a face acest lucru este de la linia de comandă folosind curl. Alternativ, puteți utiliza un instrument de genul Insomnie, sau poate codifica o interfață de utilizator HTML simplă care postează date folosind un formular.

Cu răsuci, din linia de comandă:

curl -i -X POST -H 'Content-Type: application/json' -d '{"data":{"type":"artist", "attributes":{"name":"Salvador Dali", "birth_year":1904, "genre":"Surrealism"}}}' http://localhost:5000/artists

Acum, dacă navigați la http: // localhost: 5000 / artiști, veți vedea înregistrarea pe care tocmai ați adăugat-o. Dacă ar fi să adăugați mai multe înregistrări, toate acestea ar apărea și aici, așa cum se numește această cale URL artists_many punctul final.

Pentru a vizualiza doar un singur artist după ei id , puteți naviga la adresa URL relevantă. De exemplu, pentru a vedea primul artist, încercați http: // localhost: 5000 / artisti / 1.

Filtrare și sortare

Una dintre caracteristicile îngrijite ale specificației API JSON este capacitatea de a returna răspunsul în moduri mai utile prin definirea unor parametri în URL. De exemplu, puteți sorta rezultatele în funcție de câmpul ales sau puteți filtra pe baza unor criterii.

Flask-REST-JSONAPI vine cu acest built-in.

Pentru a sorta artiștii în ordinea anului de naștere, navigați la http: // localhost: 5000 / artists? sort = birth_year. Într-o aplicație web, acest lucru vă va scuti de nevoia de a sorta rezultatele din partea clientului, ceea ce ar putea fi costisitor din punct de vedere al performanței și, prin urmare, va afecta experiența utilizatorului.

Filtrarea este, de asemenea, ușoară. Adăugați la adresa URL criteriile pe care doriți să le filtrați, conținute între paranteze drepte. Există trei informații care trebuie incluse:

  • „nume” – câmpul după care filtrați (de exemplu, birth_year)
  • “op” – operațiunea de filtrare (“egal cu”, “mai mare decât”, “mai puțin decât” etc.)
  • “val” – valoarea cu care se filtrează (de exemplu, 1900)

De exemplu, adresa URL de mai jos regăsește artiști al căror an de naștere este mai mare de 1900:

http: // localhost: 5000 / artists? filter =[{“name”:”birth_year”,”op”:”gt”,”val”:1900}]

Această funcționalitate face mult mai ușor să extrageți doar informații relevante atunci când apelați API-ul. Acest lucru este valoros pentru îmbunătățirea performanței, mai ales atunci când se recuperează volume potențial mari de date printr-o conexiune lentă.

Paginare

O altă caracteristică a specificației API JSON care ajută la performanță este paginarea. Acesta este momentul în care răspunsurile mari sunt trimise pe mai multe „pagini”, mai degrabă decât toate dintr-o dată. Puteți controla dimensiunea paginii și numărul paginii pe care o solicitați în adresa URL.

De exemplu, ați putea primi 100 de rezultate pe 10 pagini în loc să le încărcați pe toate 100 dintr-o singură dată. Prima pagină ar conține rezultatele 1-10, a doua pagină ar conține rezultatele 11-20 și așa mai departe.

Pentru a specifica numărul de rezultate pe care doriți să le primiți pe pagină, puteți adăuga parametrul? Pagină[size]= X la adresa URL, unde X este numărul de rezultate. Flask-REST-JSONAPI folosește 30 ca dimensiune implicită a paginii.

Pentru a solicita un anumit număr de pagină, puteți adăuga parametrul? Pagina[number]= X, unde este numărul paginii. Puteți combina ambii parametri așa cum se arată mai jos:

http: // localhost: 5000 / artiști? pagina[size]= 2 & pagină[number]= 2

Această adresă URL setează dimensiunea paginii la două rezultate pe pagină și solicită a doua pagină de rezultate. Aceasta ar întoarce al treilea și al patrulea rezultat din răspunsul general.

Relații

Aproape întotdeauna, datele dintr-un tabel vor fi legate de datele stocate în altul. De exemplu, dacă aveți un tabel de artiști, este posibil să doriți și un tabel de lucrări de artă. Fiecare operă de artă este legată de artistul care a creat-o.

Specificația API JSON vă permite să lucrați cu date relaționale cu ușurință, iar Flask-REST-JSONAPI vă permite să profitați de acest lucru. Aici, acest lucru va fi demonstrat prin adăugarea unui tabel de lucrări de artă în baza de date și includerea relațiilor dintre artist și lucrări de artă.

Pentru a implementa exemplul de lucrări de artă, va fi necesar să faceți câteva modificări la codul din application.py.

Mai întâi, efectuați câteva importuri suplimentare, apoi creați un nou tabel care leagă fiecare opera de artă de un artist:

from marshmallow_jsonapi.flask import Relationship
from flask_rest_jsonapi import ResourceRelationship


# Define the Artwork table
class Artwork(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String)
    artist_id = db.Column(db.Integer, 
        db.ForeignKey('artist.id'))
    artist = db.relationship('Artist',
        backref=db.backref('artworks'))

Apoi, rescrieți stratul de abstractizare:

# Create data abstraction 
class ArtistSchema(Schema):
    class Meta:
        type_ = 'artist'
        self_view = 'artist_one'
        self_view_kwargs = {'id': '<id>'}
        self_view_many = 'artist_many'

    id = fields.Integer()
    name = fields.Str(required=True)
    birth_year = fields.Integer(load_only=True)
    genre = fields.Str()
    artworks = Relationship(self_view = 'artist_artworks',
        self_view_kwargs = {'id': '<id>'},
        related_view = 'artwork_many',
        many = True,
        schema="ArtworkSchema",
        type_ = 'artwork')

class ArtworkSchema(Schema):
    class Meta:
        type_ = 'artwork'
        self_view = 'artwork_one'
        self_view_kwargs = {'id': '<id>'}
        self_view_many = 'artwork_many'

    id = fields.Integer()
    title = fields.Str(required=True)
    artist_id = fields.Integer(required=True)

Aceasta definește un strat de abstractizare pentru tabelul de lucrări și adaugă o relație între artist și lucrare ArtistSchema clasă.

Apoi, definiți noi manageri de resurse pentru accesarea operelor de artă multe simultan și unul câte unul și, de asemenea, pentru accesarea relațiilor dintre artist și lucrări de artă.

class ArtworkMany(ResourceList):
    schema = ArtworkSchema
    data_layer = {'session': db.session,
                  'model': Artwork}

class ArtworkOne(ResourceDetail):
    schema = ArtworkSchema
    data_layer = {'session': db.session,
                  'model': Artwork}

class ArtistArtwork(ResourceRelationship):
    schema = ArtistSchema
    data_layer = {'session': db.session,
                  'model': Artist}

În cele din urmă, adăugați câteva puncte finale noi:

api.route(ArtworkOne, 'artwork_one', '/artworks/<int:id>')
api.route(ArtworkMany, 'artwork_many', '/artworks')
api.route(ArtistArtwork, 'artist_artworks',
    '/artists/<int:id>/relationships/artworks')

Alerga application.py și încercarea de a posta câteva date din linia de comandă prin curl:

curl -i -X POST -H 'Content-Type: application/json' -d '{"data":{"type":"artwork", "attributes":{"title":"The Persistance of Memory", "artist_id":1}}}' http://localhost:5000/artworks

Aceasta va crea o operă de artă legată de artistul cu id=1.

În browser, navigați la http: // localhost: 5000 / artiști / 1 / relații / lucrări de artă. Aceasta ar trebui să arate lucrările de artă legate de artistul cu id=1. Acest lucru vă scutește de a scrie o adresă URL mai complexă cu parametri pentru a filtra lucrările de artă în funcție de acestea artist_id camp. Puteți lista rapid toate relațiile dintre un anumit artist și operele sale de artă.

O altă caracteristică este capacitatea de a include rezultate conexe în răspunsul la apelarea artists_one obiectiv final:

http: // localhost: 5000 / artists / 1? include = opere de artă

Acest lucru va returna răspunsul obișnuit pentru punctul final al artiștilor și, de asemenea, rezultatele pentru fiecare dintre lucrările artistice ale artistului respectiv.

Câmpuri rare

O ultimă caracteristică demnă de menționat – câmpuri rare. Când lucrați cu resurse mari de date cu multe relații complexe, dimensiunile răspunsului pot exploda foarte repede. Este util să preluați doar câmpurile care vă interesează.

Specificația API JSON vă permite să faceți acest lucru adăugând un parametru câmpuri la adresa URL. De exemplu, adresa URL de mai jos primește răspunsul pentru un anumit artist și pentru lucrările de artă aferente. Cu toate acestea, în loc să returneze toate câmpurile pentru opera de artă dată, returnează doar titlul.

http: // localhost: 5000 / artists / 1? include = opere de artă și câmpuri[artwork]= titlu

Acest lucru este din nou foarte util pentru îmbunătățirea performanței, în special în cazul conexiunilor lente. Ca regulă generală, ar trebui să faceți cereri către și de la server numai cu cantitatea minimă de date necesară.

Observații finale

Specificația API JSON este un cadru foarte util pentru trimiterea de date între server și client într-un format curat și flexibil. Acest articol a oferit o prezentare generală a ceea ce puteți face cu el, cu un exemplu lucrat în Python folosind biblioteca Flask-REST-JSONAPI.

Deci, ce vei face în continuare? Există multe posibilități. Exemplul din acest articol a fost o simplă dovadă de concept, cu doar două tabele și o singură relație între ele. Puteți dezvolta o aplicație cât de sofisticată doriți și puteți crea un API puternic pentru a interacționa cu aceasta folosind toate instrumentele furnizate aici.

Vă mulțumim pentru lectură și continuați să codificați în Python!