A comprehensive CRUD API generator for SQLALchemy.

Overview

FastAPI Quick CRUD

Codacy Badge Coverage Status CircleCI PyPidownload SupportedVersion develop dtatus


docs page

Introduction

I believe that everyone who's working with FastApi and building some RESTful of CRUD services, wastes the time to writing similar code for simple CRUD every time

FastAPI Quick CRUD can generate CRUD in FastApi with SQLAlchemy schema of PostgreSQL Database.

  • Get one
  • Get many
  • Update one
  • Update many
  • Patch one
  • Patch many
  • Create/Upsert one
  • Create/Upsert many
  • Delete One
  • Delete Many
  • Post Redirect Get

FastAPI Quick CRUDis developed based on SQLAlchemy 1.4.23 version and supports sync and async.

Advantage

  • Support SQLAlchemy 1.4 - Allow you build a fully asynchronous python service, also supports synchronization.

  • Support Pagination - Get many API support order by offset limit field in API

  • Rich FastAPI CRUD router generation - Many operations of CRUD are implemented to complete the development and coverage of all aspects of basic CRUD.

  • CRUD route automatically generated - Support Declarative class definitions and Imperative table

  • Flexible API request - UPDATE ONE/MANY FIND ONE/MANY PATCH ONE/MANY DELETE ONE/MANY supports Path Parameters (primary key) and Query Parameters as a command to the resource to filter and limit the scope of the scope of data in request.

Constraint

  • Only Support PostgreSQL yet (support MongoDB,MSSQL in schedule)
  • If there are multiple unique constraints, please use composite unique constraints instead
  • Composite primary key is not support
  • Not Support API requests with specific resource xxx/{primary key} when table have not primary key;
    • UPDATE ONE
    • FIND ONE
    • PATCH ONE
    • DELETE ONE
  • Alias is not support for imperative table yet
  • Some types of columns are not supported as query parameter
    • INTERVAL
    • JSON
    • JSONB
    • H-STORE
    • ARRAY
    • BYTE
    • Geography
    • box
    • line
    • point
    • lseg
    • polygon
    • inet
    • macaddr

Getting started

Installation

pip install fastapi-quickcrud

Usage

Start PostgreSQL using:

docker run -d -p 5432:5432 --name mypostgres --restart always -v postgresql-data:/var/lib/postgresql/data -e POSTGRES_PASSWORD=1234 postgres

Simple Code (get more example from ./example)

from datetime import datetime, timezone

import uvicorn
from fastapi import FastAPI
from sqlalchemy import Column, Integer, \
    String, Table, ForeignKey
from sqlalchemy.orm import declarative_base, sessionmaker

from fastapi_quickcrud import CrudMethods
from fastapi_quickcrud import crud_router_builder
from fastapi_quickcrud import sqlalchemy_table_to_pydantic
from fastapi_quickcrud import sqlalchemy_to_pydantic

app = FastAPI()

Base = declarative_base()
metadata = Base.metadata

from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession

engine = create_async_engine('postgresql+asyncpg://postgres:[email protected]:5432/postgres', future=True, echo=True,
                             pool_use_lifo=True, pool_pre_ping=True, pool_recycle=7200)
async_session = sessionmaker(bind=engine, class_=AsyncSession)


async def get_transaction_session() -> AsyncSession:
    async with async_session() as session:
        async with session.begin():
            yield session


class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True, autoincrement=True, unique=True)
    name = Column(String, nullable=False)
    email = Column(String, nullable=False, default=datetime.now(timezone.utc).strftime('%H:%M:%S%z'))


friend = Table(
    'friend', metadata,
    Column('id', ForeignKey('users.id', ondelete='CASCADE', onupdate='CASCADE'), nullable=False),
    Column('friend_name', String, nullable=False)
)

user_model_set = sqlalchemy_to_pydantic(db_model=User,
                                        crud_methods=[
                                            CrudMethods.FIND_MANY,
                                            CrudMethods.FIND_ONE,
                                            CrudMethods.UPSERT_ONE,
                                            CrudMethods.UPDATE_MANY,
                                            CrudMethods.UPDATE_ONE,
                                            CrudMethods.DELETE_ONE,
                                            CrudMethods.DELETE_MANY,
                                            CrudMethods.PATCH_MANY,

                                        ],
                                        exclude_columns=[])

friend_model_set = sqlalchemy_table_to_pydantic(db_model=friend,
                                                crud_methods=[
                                                    CrudMethods.FIND_MANY,
                                                    CrudMethods.UPSERT_MANY,
                                                    CrudMethods.UPDATE_MANY,
                                                    CrudMethods.DELETE_MANY,
                                                    CrudMethods.PATCH_MANY,

                                                ],
                                                exclude_columns=[])


crud_route_1 = crud_router_builder(db_session=get_transaction_session,
                                   crud_models=user_model_set,
                                   db_model=User,
                                   prefix="/user",
                                   dependencies=[],
                                   async_mode=True,
                                   tags=["User"]
                                   )
crud_route_2 = crud_router_builder(db_session=get_transaction_session,
                                   crud_models=friend_model_set,
                                   db_model=friend,
                                   async_mode=True,
                                   prefix="/friend",
                                   dependencies=[],
                                   tags=["Friend"]
                                   )


app.include_router(crud_route_1)
app.include_router(crud_route_2)
uvicorn.run(app, host="0.0.0.0", port=8000, debug=False)

Main module

covert SQLAlchemy to model set

use sqlalchemy_to_pydantic if SQLAlchemy model is Declarative Base Class

use sqlalchemy_table_to_pydantic if SQLAlchemy model is Table

  • argument:
    • db_model: SQLALchemy Declarative Base Class

    • crud_methods: CrudMethods

      • CrudMethods.FIND_ONE
      • CrudMethods.FIND_MANY
      • CrudMethods.UPDATE_ONE
      • CrudMethods.UPDATE_MANY
      • CrudMethods.PATCH_ONE
      • CrudMethods.PATCH_MANY
      • CrudMethods.UPSERT_ONE
      • CrudMethods.UPSERT_MANY
      • CrudMethods.DELETE_ONE
      • CrudMethods.DELETE_MANY
      • CrudMethods.POST_REDIRECT_GET
    • exclude_columns: list

      set the columns that not to be operated but the columns should nullable or set the default value)


Generate CRUD router

crud_router_builder

  • db_session: execute session generator
    • example:
      • sync SQLALchemy:
def get_transaction_session():
    try:
        db = sessionmaker(...)
        yield db
        db.commit()
    except Exception as e:
        db.rollback()
        raise e
    finally:
        db.close()
  • Async SQLALchemy
async def get_transaction_session() -> AsyncSession:
    async with async_session() as session:
        async with session.begin():
            yield session
  • db_model SQLALchemy Declarative Base Class

    Note: There are some constraint in the SQLALchemy Schema

  • async_modebool: if your db session is async

    Note: require async session generator if True

  • autocommitbool: if you don't need to commit by your self

    Note: require handle the commit in your async session generator if False

  • dependencies: API dependency injection of fastapi

    Note: Get the example usage in ./example

  • crud_models sqlalchemy_to_pydantic

  • dynamic argument (prefix, tags): extra argument for APIRouter() of fastapi

Design

In PUT DELETE PATCH, user can use Path Parameters and Query Parameters to limit the scope of the data affected by the operation, and the Query Parameters is same with FIND API

Path Parameter

In the design of this tool, Path Parameters should be a primary key of table, that why limited primary key can only be one.

Query Parameter

  • Query Operation will look like that when python type of column is

    string
    • support Approximate String Matching that require this
      • (<column_name>____str, <column_name>____str_____matching_pattern)
    • support In-place Operation, get the value of column in the list of input
      • (<column_name>____list, <column_name>____list____comparison_operator)
    • preview string
    numeric or datetime
    • support Range Searching from and to
      • (<column_name>____from, <column_name>____from_____comparison_operator)
      • (<column_name>____to, <column_name>____to_____comparison_operator)
    • support In-place Operation, get the value of column in the list of input
      • (<column_name>____list, <column_name>____list____comparison_operator)
    • preview numeric datetime
    uuid

    uuid supports In-place Operation only

    • support In-place Operation, get the value of column in the list of input
      • (<column_name>____list, <column_name>____list____comparison_operator)
  • EXTRA query parameter for GET_MANY:

    Pagination
    • limit
    • offset
    • order by
    • preview Pagination

Query to SQL statement example

  • Approximate String Matching

    example
    • request url
      /test_CRUD?
      char_value____str_____matching_pattern=match_regex_with_case_sensitive&
      char_value____str_____matching_pattern=does_not_match_regex_with_case_insensitive&
      char_value____str_____matching_pattern=case_sensitive&
      char_value____str_____matching_pattern=not_case_insensitive&
      char_value____str=a&
      char_value____str=b
      
    • generated sql
        SELECT *
        FROM untitled_table_256 
        WHERE (untitled_table_256.char_value ~ 'a') OR 
        (untitled_table_256.char_value ~ 'b' OR 
        (untitled_table_256.char_value !~* 'a') OR 
        (untitled_table_256.char_value !~* 'b' OR 
        untitled_table_256.char_value LIKE 'a' OR 
        untitled_table_256.char_value LIKE 'b' OR 
        untitled_table_256.char_value NOT ILIKE 'a' 
        OR untitled_table_256.char_value NOT ILIKE 'b'
  • In-place Operation

    example
    • In-place support the following operation

    • generated sql if user select Equal operation and input True and False

    • preview in

    • generated sql

        select * FROM untitled_table_256 
        WHERE untitled_table_256.bool_value = true OR 
        untitled_table_256.bool_value = false
  • Range Searching

    example
    • Range Searching support the following operation

      greater

      less

    • generated sql

        select * from untitled_table_256
        WHERE untitled_table_256.date_value > %(date_value_1)s 
        select * from untitled_table_256
        WHERE untitled_table_256.date_value < %(date_value_1)s 
  • Also support your custom dependency for each api(there is a example in ./example)

Request Body

In the design of this tool, the columns of the table will be used as the fields of request body.

In the basic request body in the api generated by this tool, some fields are optional if :

  • it is primary key with autoincrement is True or the server_default or default is True
  • it is not a primary key, but the server_default or default is True
  • The field is nullable

Upsert

POST API will perform the data insertion action with using the basic Request Body, In addition, it also supports upsert(insert on conflict do)

The operation will use upsert instead if the unique column in the inserted row that is being inserted already exists in the table

The tool uses unique columns in the table as a parameter of on conflict , and you can define which column will be updated

upsert

Alias

Alias is supported already

usage:

id = Column('primary_key',Integer, primary_key=True, server_default=text("nextval('untitled_table_256_id_seq'::regclass)"))

you can use info argument to set the alias name of column, and use synonym to map the column between alias column and original column

id = Column(Integer, info={'alias_name': 'primary_key'}, primary_key=True, server_default=text("nextval('untitled_table_256_id_seq'::regclass)"))
primary_key = synonym('id')

FastAPI_quickcrud Response Status Code standard

When you ask for a specific resource, say a user or with query param, and the user doesn't exist

GET: get one : https://0.0.0.0:8080/api/:userid?xx=xx

UPDATE: update one : https://0.0.0.0:8080/api/:userid?xx=xx

PATCH: patch one : https://0.0.0.0:8080/api/:userid?xx=xx

DELETE: delete one : https://0.0.0.0:8080/api/:userid?xx=xx

then fastapi-qucikcrud should return 404. In this case, the client requested a resource that doesn't exist.


In the other case, you have an api that operate data on batch in the system using the following url:

GET: get many : https://0.0.0.0:8080/api/user?xx=xx

UPDATE: update many : https://0.0.0.0:8080/api/user?xx=xx

DELETE: delete many : https://0.0.0.0:8080/api/user?xx=xx

PATCH: patch many : https://0.0.0.0:8080/api/user?xx=xx

If there are no users in the system, then, in this case, you should return 204.

TODO

  • handle relationship
  • support MYSQL , MSSQL cfand Sqllite
fastapi-admin2 is an upgraded fastapi-admin, that supports ORM dialects, true Dependency Injection and extendability

FastAPI2 Admin Introduction fastapi-admin2 is an upgraded fastapi-admin, that supports ORM dialects, true Dependency Injection and extendability. Now

Glib 14 Dec 05, 2022
A RESTful API for creating and monitoring resource components of a hypothetical build system. Built with FastAPI and pydantic. Complete with testing and CI.

diskspace-monitor-CRUD Background The build system is part of a large environment with a multitude of different components. Many of the components hav

Nick Hopewell 67 Dec 14, 2022
Turns your Python functions into microservices with web API, interactive GUI, and more.

Instantly turn your Python functions into production-ready microservices. Deploy and access your services via HTTP API or interactive UI. Seamlessly export your services into portable, shareable, and

Machine Learning Tooling 2.8k Jan 04, 2023
Cache-house - Caching tool for python, working with Redis single instance and Redis cluster mode

Caching tool for python, working with Redis single instance and Redis cluster mo

Tural 14 Jan 06, 2022
Docker image with Uvicorn managed by Gunicorn for high-performance FastAPI web applications in Python 3.6 and above with performance auto-tuning. Optionally with Alpine Linux.

Supported tags and respective Dockerfile links python3.8, latest (Dockerfile) python3.7, (Dockerfile) python3.6 (Dockerfile) python3.8-slim (Dockerfil

Sebastián Ramírez 2.1k Dec 31, 2022
Пример использования GraphQL Ariadne с FastAPI и сравнение его с GraphQL Graphene FastAPI

FastAPI Ariadne Example Пример использования GraphQL Ariadne с FastAPI и сравнение его с GraphQL Graphene FastAPI - GitHub ###Запуск на локальном окру

ZeBrains Team 9 Nov 10, 2022
Prometheus integration for Starlette.

Starlette Prometheus Introduction Prometheus integration for Starlette. Requirements Python 3.6+ Starlette 0.9+ Installation $ pip install starlette-p

José Antonio Perdiguero 229 Dec 21, 2022
Generate Class & Decorators for your FastAPI project ✨🚀

Classes and Decorators to use FastAPI with class based routing. In particular this allows you to construct an instance of a class and have methods of that instance be route handlers for FastAPI & Pyt

Yasser Tahiri 34 Oct 27, 2022
SQLAlchemy Admin for Starlette/FastAPI

SQLAlchemy Admin for Starlette/FastAPI SQLAdmin is a flexible Admin interface for SQLAlchemy models. Main features include: SQLAlchemy sync/async engi

Amin Alaee 683 Jan 03, 2023
Dead simple CSRF security middleware for Starlette ⭐ and Fast API ⚡

csrf-starlette-fastapi Dead simple CSRF security middleware for Starlette ⭐ and Fast API ⚡ Will work with either a input type="hidden" field or ajax

Nathaniel Sabanski 9 Nov 20, 2022
FastAPI with Docker and Traefik

Dockerizing FastAPI with Postgres, Uvicorn, and Traefik Want to learn how to build this? Check out the post. Want to use this project? Development Bui

51 Jan 06, 2023
Stac-fastapi built on Tile38 and Redis to support caching

stac-fastapi-caching Stac-fastapi built on Tile38 to support caching. This code is built on top of stac-fastapi-elasticsearch 0.1.0 with pyle38, a Pyt

Jonathan Healy 4 Apr 11, 2022
LuSyringe is a documentation injection tool for your classes when using Fast API

LuSyringe LuSyringe is a documentation injection tool for your classes when using Fast API Benefits The main benefit is being able to separate your bu

Enzo Ferrari 2 Sep 06, 2021
Cookiecutter API for creating Custom Skills for Azure Search using Python and Docker

cookiecutter-spacy-fastapi Python cookiecutter API for quick deployments of spaCy models with FastAPI Azure Search The API interface is compatible wit

Microsoft 379 Jan 03, 2023
🔀⏳ Easy throttling with asyncio support

Throttler Zero-dependency Python package for easy throttling with asyncio support. 📝 Table of Contents 🎒 Install 🛠 Usage Examples Throttler and Thr

Ramzan Bekbulatov 80 Dec 07, 2022
FastAPI simple cache

FastAPI Cache Implements simple lightweight cache system as dependencies in FastAPI. Installation pip install fastapi-cache Usage example from fastapi

Ivan Sushkov 188 Dec 29, 2022
Basic fastapi blockchain - An api based blockchain with full functionality

Basic fastapi blockchain - An api based blockchain with full functionality

1 Nov 27, 2021
Mixer -- Is a fixtures replacement. Supported Django, Flask, SqlAlchemy and custom python objects.

The Mixer is a helper to generate instances of Django or SQLAlchemy models. It's useful for testing and fixture replacement. Fast and convenient test-

Kirill Klenov 871 Dec 25, 2022
Fetching Cryptocurrency Prices from Coingecko and Displaying them on Grafana

cryptocurrency-prices-grafana Fetching Cryptocurrency Prices from Coingecko and Displaying them on Grafana About This stack consists of: Prometheus (t

Ruan Bekker 7 Aug 01, 2022
FastAPI Server Session is a dependency-based extension for FastAPI that adds support for server-sided session management

FastAPI Server-sided Session FastAPI Server Session is a dependency-based extension for FastAPI that adds support for server-sided session management.

DevGuyAhnaf 5 Dec 23, 2022