Logical data abstraction
The first thing to do in FastAPI-JSONAPI is to create a logical data abstraction. This part of the API describes schemas of resources exposed by the API that are not an exact mapping of the data architecture. Pydantic is a very popular serialization/deserialization library that offers a lot of features to abstract your data architecture. Moreover there is another library called pydantic that fits the JSON:API 1.0 specification and provides FastAPI integration.
Example:
In this example, let’s assume that we have two legacy models, User and Computer, and we want to create an abstraction on top of them.
from sqlalchemy import Column, String, Integer, ForeignKey
from sqlalchemy.orm import relationship, backref
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class User(Base):
id = Column(Integer, primary_key=True)
name = Column(String)
email = Column(String)
birth_date = Column(String)
password = Column(String)
class Computer(Base):
computer_id = Column(Integer, primary_key=True)
serial = Column(String)
user_id = Column(Integer, ForeignKey('user.id'))
user = relationship('User', backref=backref('computers'))
Now let’s create the logical abstraction to illustrate this concept.
from pydantic import (
BaseModel,
Field,
)
from typing import List
from datetime import datetime
class UserSchema(BaseModel):
class Config:
orm_mode = True
id: int
name: str
email: str
birth_date: datetime
computers: List['ComputerSchema']
class ComputerSchema(BaseModel):
class Config:
orm_mode = True
id: int
serial: str
owner: UserSchema
You can see several differences between models and schemas exposed by the API.
First, take a look at the User compared to UserSchema:
We can see that User has an attribute named “password” and we don’t want to expose it through the api so it is not set in UserSchema
UserSchema has an attribute named “display_name” that is the result of concatenation of name and email
In the “computers” Relationship() defined on UserSchema we have set the id_field to “computer_id” as that is the primary key on the Computer(db.model). Without setting id_field the relationship looks for a field called “id”.
Second, take a look at the Computer compared to ComputerSchema:
The attribute computer_id is exposed as id for consistency of the api
The user relationship between Computer and User is exposed in ComputerSchema as owner because it is more explicit
As a result you can see that you can expose your data in a very flexible way to create the API of your choice on top of your data architecture.