How it works

Introduction This project management api provides the interface to manage projects and their tasks. It is built on top of the FastApi framework.

Routers Routers modules define the endpoints for the api. Four routers are defined: main, projects, douments, msprojects

@router.get('/{path_param}')
def router(path_param):
    ...

Dependencies This project uses FastApi’s dependency injection to perform a series of checks before executing the request. The following checks are currently implemented:

  • Authentication check

The dependency checks if the user is authenticated and returns the associated object. If the user isn’t authenticated, raises a 401 unauthorized http error

@router.get("/{project_name}")
def get_project_by_name(user: User = Depends(get_current_active_user))
  • Authorization check and user retrieval

This dependency checks if the user has the argument permission on the selected resource, if not it raises a 401 unauthorized error

@router.post("/", dependencies=[Depends(require_project_permission(Permissions.create))])
  • Input validation and retrieval

It checks that the request body is either a JSON or YAML document, then returns the parsed Dictionary. If the request body is not valid, it raises a 400 bad request error

@router.post("/", ...)
async def add_document_schema_to_project(request_body: Dict = Depends(get_request_body), ...)
  • Resource retrieval

Resource retrieval methods (get_project, get_document, …) read the path string and return the resource, raising 404 not found if the resource is not in the database

@router.get("/{project_name}", ...)
def get_project_by_name(..., db_project: Project = Depends(get_project)):
    ...
  • Database session retrieval

Getting the database session from dependencies ensures that all dependencies use the same sessions, enabling object edit compatibility between the various methods

@router.put("/{document_name}", ...)
async def put_document_to_project(..., session: Session = Depends(get_session)):

Models SQLModel is used to define the database structure. In order to increase code readability, all models have a Fields subclass to associate the field name with its string representation

class Document(SQLModel, table=True):
# field name   | type | options
project_name   : str  = Field(default=None, primary_key=True, foreign_key=Project.Fields.project_name)
document_name  : str  = Field(default=None, primary_key=True)
author_name    : str  = Field(default=None,                   foreign_key=User.Fields.user_name)
...

    class Fields(metaclass=StringFields):
        table_name      = "document"
        project_name    = "project_name"
        document_name   = "document_name"
        author_name     = "author_name"
        ...

Security Security has been implemented using bearer token authentication