DEV Community

Thomas Pollet
Thomas Pollet

Posted on

Python JSON API dev

Introduction

I created a library that allows you to easily develop an API using SQLAlchemy models: safrs. In this series I will demonstrate how to use the library to implement an API similar to this live demo. The exposed endpoints are compliant with the json:api specification. This means the API provides all functionality you'd expect from a JSON API, such as relationships, resource linkage, pagination, filtering, sorting, and much more. An OpenAPI (fka swagger) frontend is automatically generated to allow API exploration.

In this first part, I explain how to build a simple API app. The source code of this app can be found here

Installation

The safrs package can be installed by cloning the github repository or by using pip, e.g.:

python3 -m pip install safrs --user

SQLAlchemy Objects

The objects that will be exposed are almost identical to SQLAlchemy models. The following class for example, describes attributes and a relationship for an object called User, based on a Users table.

class User(SAFRSBase, db.Model):
    """
        description: User description
    """

    __tablename__ = "Users"
    id = db.Column(db.String, primary_key=True)
    name = db.Column(db.String, default="")
    email = db.Column(db.String, default="")
    books = db.relationship("Book", back_populates="user", lazy="dynamic")

Similar to the User class, a Book class is created:

class Book(SAFRSBase, db.Model):
    """
        description: Book description
    """

    __tablename__ = "Books"
    id = db.Column(db.String, primary_key=True)
    name = db.Column(db.String, default="")
    user_id = db.Column(db.String, db.ForeignKey("Users.id"))
    user = db.relationship("User", back_populates="books")

API Endpoints

To create Flask API endpoints for these objects, all you have to do is create an API and expose the objects:

def create_api(app, HOST="localhost", PORT=5000, API_PREFIX=""):
    api = SAFRSAPI(app, host=HOST, port=PORT, prefix=API_PREFIX)
    api.expose_object(User)
    api.expose_object(Book)

Flask App

All that is left to do now is creating the Flask app and populate the in-memory sqlite database:

def create_app(config_filename=None, host="localhost"):
    app = Flask("demo_app")
    app.config.update(SQLALCHEMY_DATABASE_URI="sqlite://")
    db.init_app(app)

    with app.app_context():
        db.create_all()
        # Populate the db with users and a books and add the book to the user.books relationship
        for i in range(200):
            user = User(name=f"user{i}", email=f"email{i}@dev.to")
            book = Book(name="test_book")
            user.books.append(book)

        create_api(app, host)
    return app

The API app can be started by calling the flask app.run:

host = "127.0.0.1" # address where the api will be hosted, change this if you're not running the app on localhost!
app = create_app(host=host)

if __name__ == "__main__":
    app.run(host=host)

Dependencies and SQLAlcheymy DB Instance

The app script should start with the imports and SQLAlchemy db:

import sys
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from safrs import SAFRSBase, SAFRSAPI

db = SQLAlchemy()

Running the App

You can start the app from the command line with

python3 demo_devto.py

You can now browse to http://127.0.0.1 to check out the API documentation and use the API. In the swagger UI, you will see the endpoints for the User and Book classes:

Swagger

In the following post I will go into more detail explaining the API functionality and customizations.

Top comments (0)