Skip to content
Thomas Pollet edited this page Dec 5, 2020 · 25 revisions

Overview

This wiki describes how to use and customize safrs.

The github repository contains an examples directory where much of the functionality is demonstrated.

The sidebar contains an index with links to the implementation instructions →

API Usage

The exposed API implements all JSON:API functionality:

In addition, this functionality can be refined and extended in many different ways.

CRUD

The main purpose for a database-driven API is to provide CRUD operations for database objects. Exposed resource objects can be queried using the JSON:API format. The API supports following HTTP operations:

  • GET : Retrieve an object or a list of objects
  • PATCH : Update an object.
  • DELETE: Delete an object.
  • POST : Create an object.

Please check the JSON:API spec for more in-depth information. You may also take a look at the live demo to get an idea of what the operations and format looks like.

Exposed models are declared as SQLAlchemy classes, for example:

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

    __tablename__ = "Users"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String)
    email = db.Column(db.String)

By exposing this class, the corresponding CRUD endpoints are created, allowing you to retrieve the information from the database in jsonapi format.

Relationships

Database object such as the User class from the demo.py example can be extended to include relationships with other objects. The demo_relationship.py contains following extension of the User class where a relationship with the Book class is implemented:

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")
...

A many-to-one database association is declared by the back_populates relationship argument. The Book class is simply another subclass of SAFRSBase and db.Model, similar to the previous User class:

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')

The User.book relationship can be queried in the API through the following endpoints: Relations Swagger

  • POST adds an item to the relationship
  • DELETE removes an item from the relationship
  • GET retrieves a list of item ids

The relationship API endpoints work similarly for one-to-many relationships.

Relationship members can also be included in the response when querying an instance, by specifying the relationship name in the include query argument.

For example, to retrieve all items in the books_read relationship from the People endpoint, you may add the include=books_read url parameter:

relationship include swagger

http://thomaxxl.pythonanywhere.com/api/People/?include=books_read

To retrieve nested relationship items, you can specify the nested relationship name after the '.', to retrieve the authors of the books_read instances for instance, you can use

http://thomaxxl.pythonanywhere.com/api/People/?include=books_read.author

Filtering

The jsonapi base specification is agnostic about filtering strategies supported by a server. The filter query parameter family is reserved to be used as the basis for any filtering strategy (https://jsonapi.org/recommendations/#filtering).

The default filtering scheme makes it possible to retrieve items based on the exact value of one of the attributes. For example, if you want to retrieve all People that have an attribute name equal to "Benny", you provide this as an argument to the filter[name] url query parameter:

/People/?filter[name]=Benny

It is possible to implement your own filtering strategy by overriding the SAFRSBase._s_filter classmethod. The default filtering strategy is documented in the section about Json:Api Filtering

Sorting

Collection responses can be sorted on the attribute (or attribute csv list) specified in the "sort" url query argument.

e.g.

http://thomaxxl.pythonanywhere.com/api/People/?sort=name,id

Reverse sort is also possible by using a - in front of the attribute you want to sort:

http://thomaxxl.pythonanywhere.com/api/People/?sort=-name