A JSON API specifikáció hatékony módszer a kliens és szerver közötti kommunikáció lehetővé tételére. Megadja a kettő között küldött kérések és válaszok felépítését a JSON formátum használatával.
Adatformátumként a JSON előnye, hogy könnyű és olvasható. Ez megkönnyíti a gyors és eredményes munkát. A specifikációt úgy alakították ki, hogy minimalizálja a kérések számát és az ügyfél és a szerver között küldendő adatok mennyiségét.
Itt megtudhatja, hogyan hozhat létre egy alapvető JSON API-t Python és Flask használatával. Ezután a cikk többi része bemutatja, hogyan lehet kipróbálni a JSON API specifikáció által kínált néhány funkciót.
A Flask egy Python könyvtár, amely „mikrokeretet” biztosít a webfejlesztéshez. Nagyszerű a gyors fejlődéshez, mivel egyszerű, mégis kibővíthető alapvető funkcióval rendelkezik.
Az alábbiakban bemutatunk egy nagyon egyszerű példát arra, hogyan lehet JSON-szerű választ küldeni a lombik segítségével:
from flask import Flask app = Flask(__name__) @app.route('/') def example(): return '{"name":"Bob"}' if __name__ == '__main__': app.run()
Ez a cikk két kiegészítőt fog használni a Lombikhoz:
- A Flask-REST-JSONAPI segít egy olyan API fejlesztésében, amely szorosan követi a JSON API specifikációt.
- A Flask-SQLAlchemy az SQLAlchemy használatával egyszerűvé teszi az egyszerű adatbázis létrehozását és az azzal való interakciót.
A nagy kép
A végső cél egy olyan API létrehozása, amely lehetővé teszi az ügyféloldali interakciót egy mögöttes adatbázissal. Pár réteg lesz az adatbázis és az ügyfél között - egy adatkivonási és egy erőforrás-kezelő réteg.

Itt van egy áttekintés az érintett lépésekről:
- Adjon meg egy adatbázist a Flask-SQLAlchemy használatával
- Hozzon létre egy adatkivonatot a Marshmallow-JSONAPI alkalmazással
- Hozzon létre erőforrás-kezelőket a Flask-REST-JSONAPI segítségével
- Hozzon létre URL-végpontokat, és indítsa el a kiszolgálót a Lombikkal
Ez a példa egy egyszerű sémát fog használni, amely leírja a modern művészeket és kapcsolatukat a különböző műalkotásokkal.
Telepítsen mindent
Mielőtt elkezdené, be kell állítania a projektet. Ez magában foglalja a munkaterület és a virtuális környezet létrehozását, a szükséges modulok telepítését, valamint a fő Python és adatbázis fájlok létrehozását a projekthez.
A parancssorból hozzon létre egy új könyvtárat, és navigáljon benne.
$ mkdir flask-jsonapi-demo $ cd flask-jsonapi-demo/
Jó gyakorlat virtuális környezetek létrehozása az egyes Python-projektekhez. Ezt a lépést kihagyhatja, de erősen ajánlott.
$ python -m venv .venv $ source .venv/bin/activate
A virtuális környezet létrehozása és aktiválása után telepítheti a projekthez szükséges modulokat.
$ pip install flask-rest-jsonapi flask-sqlalchemy
A két kiterjesztés követelményeként minden szükséges telepítésre kerül. Ide tartozik maga a lombik és az SQLAlchemy.
A következő lépés egy Python fájl és adatbázis létrehozása a projekthez.
$ touch application.py artists.db
Hozzon létre egy adatbázis-sémát
Itt elkezdi módosítani application.py
a projekt adatbázis sémájának meghatározását és létrehozását.
Nyissa application.py
meg a kívánt szövegszerkesztőben. Kezdje néhány modul importálásával. Az egyértelműség kedvéért a modulokat importálás közben importáljuk.
Ezután hozzon létre egy objektumot, amelyet app
a Lombik osztály példányának hívnak .
Ezt követően az SQLAlchemy segítségével csatlakozzon a létrehozott adatbázis fájlhoz. Az utolsó lépés az úgynevezett tábla meghatározása és létrehozása 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()
Absztrakciós réteg létrehozása
A következő lépés a Marshmallow-JSONAPI modullal hozza létre a logikai adatok absztrakcióját az imént definiált táblák felett.
Ennek az absztrakciós rétegnek az létrehozása egyszerű. Jobban szabályozhatja, hogy az alapul szolgáló adatok hogyan vannak kitéve az API-n keresztül. Gondoljon erre a rétegre, mint olyan objektívre, amelyen keresztül az API kliens tisztán megtekintheti az alapul szolgáló adatokat, és csak azokat a biteket, amelyeket látnia kell.

Az alábbi kódban az adat absztrakciós réteget olyan osztályként definiáljuk, amely Marshmallow-JSONAPI Schema
osztályától örököl . Az API-n keresztül hozzáférést biztosít mind az egyes, mind az előadók tábla több rekordjához.
Ebben a blokkban az Meta
osztály meghatároz néhány metaadatot. Pontosabban az egyetlen rekorddal való interakcióhoz használt URL-végpont neve lesz artist_one
, ahol minden előadót egy URL-paraméter azonosít . A sok rekorddal való interakció végpontjának neve az lesz
artist_many
.
A fennmaradó meghatározott attribútumok az előadó táblázat oszlopaihoz kapcsolódnak. Itt az API-n keresztül tovább szabályozhatja mindegyik expozícióját.
Például, amikor POST kéréseket tesz új előadók felvételére az adatbázisba, name
a beállítással ellenőrizheti, hogy a mező kötelező-e required=True
.
És ha valamilyen okból nem szeretné, hogy a birth_year
mező visszatérjen a GET kérések készítésekor, akkor a beállítással megadhatja 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': ''} self_view_many = 'artist_many' id = fields.Integer() name = fields.Str(required=True) birth_year = fields.Integer(load_only=True) genre = fields.Str()
Hozzon létre erőforrás-kezelőket és URL-végpontokat
A rejtvény utolsó része egy erőforrás-kezelő és megfelelő végpont létrehozása az egyes útvonalakhoz / művészekhez és / művészekhez / azonosítókhoz.
Minden erőforrás-kezelőt úgy definiálunk, mint egy osztályt, amely a Flask-REST-JSONAPI osztályokból ResourceList
és ResourceDetail
.
Itt két tulajdonságot vesznek fel. schema
az erőforrás-kezelő által használt adat absztrakciós réteg data_layer
megjelölésére szolgál , és jelzi az adatréteghez használt munkamenetet és adatmodellt.
Ezután definiálja api
a Flask-REST-JSONAPI Api
osztályának példányaként , és ezzel hozza létre az API útvonalait api.route()
. Ehhez a módszerhez három argumentumra van szükség - az adatkivonási réteg osztályára, a végpont nevére és az URL elérési útjára.
The last step is to write a main loop to launch the app in debug mode when the script is run directly. Debug mode is great for development, but it is not suitable for running in production.
# 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/') # main loop to run app in debug mode if __name__ == '__main__': app.run(debug=True)
Make GET and POST requests
Now you can start using the API to make HTTP requests. This could be from a web browser, or from a command line tool like curl, or from within another program (e.g., a Python script using the Requests library).
To launch the server, run the application.py
script with:
$ python application.py
In your browser, navigate to //localhost:5000/artists. You will see a JSON output of all the records in the database so far. Except, there are none.
To start adding records to the database, you can make a POST request. One way of doing this is from the command line using curl. Alternatively, you could use a tool like Insomnia, or perhaps code up a simple HTML user interface that posts data using a form.
With curl, from the command line:
curl -i -X POST -H 'Content-Type: application/json' -d '{"data":{"type":"artist", "attributes":{"name":"Salvador Dali", "birth_year":1904, "genre":"Surrealism"}}}' //localhost:5000/artists
Now if you navigate to //localhost:5000/artists, you will see the record you just added. If you were to add more records, they would all show here as well, as this URL path calls the artists_many
endpoint.
To view just a single artist by their id
number, you can navigate to the relevant URL. For example, to see the first artist, try //localhost:5000/artists/1.
Filtering and sorting
One of the neat features of the JSON API specification is the ability to return the response in more useful ways by defining some parameters in the URL. For instance, you can sort the results according to a chosen field, or filter based on some criteria.
Flask-REST-JSONAPI comes with this built in.
To sort artists in order of birth year, just navigate to //localhost:5000/artists?sort=birth_year. In a web application, this would save you from needing to sort results on the client side, which could be costly in terms of performance and therefore impact the user experience.
Filtering is also easy. You append to the URL the criteria you wish to filter on, contained in square brackets. There are three pieces of information to include:
- "name" - the field you are filtering by (e.g.,
birth_year
) - "op" - the filter operation ("equal to", "greater than", "less than" etc.)
- "val" - the value to filter against (e.g., 1900)
For example, the URL below retrieves artists whose birth year is greater than 1900:
//localhost:5000/artists?filter=[{"name":"birth_year","op":"gt","val":1900}]
This functionality makes it much easier to retrieve only relevant information when calling the API. This is valuable for improving performance, especially when retrieving potentially large volumes of data over a slow connection.
Pagination
Another feature of the JSON API specification that aids performance is pagination. This is when large responses are sent over several "pages", rather than all in one go. You can control the page size and the number of the page you request in the URL.
So, for example, you could receive 100 results over 10 pages instead of loading all 100 in one go. The first page would contain results 1-10, the second page would contain results 11-20, and so on.
To specify the number of results you want to receive per page, you can add the parameter ?page[size]=X to the URL, where X is the number of results. Flask-REST-JSONAPI uses 30 as the default page size.
To request a given page number, you can add the parameter ?page[number]=X, where is the page number. You can combine both parameters as shown below:
//localhost:5000/artists?page[size]=2&page[number]=2
This URL sets the page size to two results per page, and asks for the second page of results. This would return the third and fourth results from the overall response.
Relationships
Almost always, data in one table will be related to data stored in another. For instance, if you have a table of artists, chances are you might also want a table of artworks. Each artwork is related to the artist who created it.
The JSON API specification allows you to work with relational data easily, and the Flask-REST-JSONAPI lets you take advantage of this. Here, this will be demonstrated by adding an artworks table to the database, and including relationships between artist and artwork.
To implement the artworks example, it will be necessary to make a few changes to the code in application.py
.
First, make a couple of extra imports, then create a new table which relates each artwork to an 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'))
Next, rewrite the abstraction layer:
# Create data abstraction class ArtistSchema(Schema): class Meta: type_ = 'artist' self_view = 'artist_one' self_view_kwargs = {'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': ''}, 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': ''} self_view_many = 'artwork_many' id = fields.Integer() title = fields.Str(required=True) artist_id = fields.Integer(required=True)
This defines an abstraction layer for the artwork table, and adds a relationship between artist and artwork to the ArtistSchema
class.
Next, define new resource managers for accessing artworks many at once and one at a time, and also for accessing the relationships between artist and artwork.
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}
Finally, add some new endpoints:
api.route(ArtworkOne, 'artwork_one', '/artworks/') api.route(ArtworkMany, 'artwork_many', '/artworks') api.route(ArtistArtwork, 'artist_artworks', '/artists//relationships/artworks')
Run application.py
and trying posting some data from the command line via curl:
curl -i -X POST -H 'Content-Type: application/json' -d '{"data":{"type":"artwork", "attributes":{"title":"The Persistance of Memory", "artist_id":1}}}' //localhost:5000/artworks
This will create an artwork related to the artist with id=1
.
In the browser, navigate to //localhost:5000/artists/1/relationships/artworks. This should show the artworks related to the artist with id=1
. This saves you from writing a more complex URL with parameters to filter artworks by their artist_id
field. You can quickly list all the relationships between a given artist and their artworks.
Another feature is the ability to include related results in the response to calling the artists_one
endpoint:
//localhost:5000/artists/1?include=artworks
This will return the usual response for the artists endpoint, and also results for each of that artist's artworks.
Sparse Fields
One last feature worth mentioning - sparse fields. When working with large data resources with many complex relationships, the response sizes can blow up real fast. It is helpful to only retrieve the fields you are interested in.
The JSON API specification lets you do this by adding a fields parameter to the URL. For example URL below gets the response for a given artist and their related artworks. However, instead of returning all the fields for the given artwork, it returns only the title.
//localhost:5000/artists/1?include=artworks&fields[artwork]=title
This is again very helpful for improving performance, especially over slow connections. As a general rule, you should only make requests to and from the server with the minimal amount of data required.
Final remarks
The JSON API specification is a very useful framework for sending data between server and client in a clean, flexible format. This article has provided an overview of what you can do with it, with a worked example in Python using the Flask-REST-JSONAPI library.
So what will you do next? There are many possibilities. The example in this article has been a simple proof-of-concept, with just two tables and a single relationship between them. You can develop an application as sophisticated as you like, and create a powerful API to interact with it using all the tools provided here.
Thanks for reading, and keep coding in Python!