Fast coding, perfect function. From startup to deployment, explain why an asynchronous PY3 framework chose FastAPI.
FastAPI introduction
FastAPI differs from other Python-Web frameworks
Before FastAPI, Python Web frameworks used Django, Flask, and Tornado.
-
Django comes with admin and is fast to build, but cumbersome. If you’re developing in MVC style, a lot of it is already packaged, which is pretty good. But if django is designed restful, it can be a little clunky.
-
Flask builds quickly and has a high degree of freedom. Because it’s lightweight and plug-and-play, it’s great for restful design
-
Tornado Python Web Framework and Asynchronous network library, which performs non-blocking I/O and has no built-in support for REST apis, but can be implemented manually by users.
-
FastAPI fast build, asynchronous IO, built-in Swagger as API document, do not need to embed Swagger-Ui later
In my opinion, FastAPI is a Web backend framework designed specifically for the restful style and fully serviced in the form of API.
FastAPI official location
In the official FastAPI documentation, you can see the official position of FastAPI:
-
Fast: Very high performance, on par with NodeJS and Go (thanks Starlette and Pydantic)
-
Fast coding: Speed up feature development by about 200% to 300%.
-
Fewer errors: approximately 40% fewer human errors (developers). * (FastAPI has a lot of Python higher-level syntax built in, such as type comments, typing library, etc., so the required Python version is 3.6+)
-
Simplicity: Designed to be easy to use and learn. Reduce the time you spend reading documents.
-
Features: Swagger as API documentation
Framework Benchmarks
www.techempower.com/benchmarks/…
The chart above shows how the four frameworks rank at high concurrency. In terms of pure performance, Web frameworks are number one. When choosing a framework, performance is one thing, but we also need to look at the business needs and usage scenarios, and the best fit is the best.
Here’s a quick look at some of the uses and features of FastAPI.
Start the FastAPI
1 # pip install fastapi 2 # pip install uvicorn 3 from fastapi import FastAPI 4 app = FastAPI() 5 @app.get(“/”) 6 def read_root(): 7 return {“Hello”: “World”} 8 @app.get(“/items/{item_id}”) 0 def read_item(item_id: int, q: str = None): 10 return {“item_id”: item_id, “q”: 13 # uvicorn main:app –host 0.0.0.0 –port 8889 –reload # Custom IP+ port 14
FastAPI supports asynchronous requests
1 from fastapi import FastAPI 2 app = FastAPI() 3 @app.get(“/”) 4 async def read_root(): 5 return {“Hello”: “World”} 6 7 @app.get(“/items/{item_id}”) 8 async def read_item(item_id: int, q: str = None): 9 return {“item_id”: item_id, “q”: q} 10
Excellent support for THE API interface
Setting the root Directory
1 # main.py 2 from fastapi import FastAPI 3 import users 4 app = FastAPI() 5 app.include_router( 6 users.router, 7 prefix=”/fastapi/play/v1/users”, Py 10 # routers/users.py 11 from FastAPI import FastAPI,APIRouter 12 from datetime import datetime,timedelta 13 router = APIRouter() 14 @router.get(“/get/users/”) 15 async def get_users(): 16 return { 17 “desc”:”Return to user list” 18 } 19
Restrict path parameters
@router.get(“/get/user/{username}”) 3 async def get_user_by_username(username: STR): 4 “”” Username 6 “”” 7 return {8 “desc”:”this username is “+ username 9} 10
Restrict query parameters
Async def get_friends_by_id(id :int=None): async def get_friends_by_id(id :int=None) 5 for item in test_json[‘friends’]: 6 if item[‘id’] == id: 7 return item 8 else: 9 return { 10 “desc”: “No this ID” 11} 12 # typing import List 14 @router.get(“/items/”) 15 async def read_items(q: List[str] = Query([“foo”, “bar”])): 16 query_items = {“q”: q} 17 return query_items 18
Set the request body
From pydantic import BaseModel,Field 3 class requestModel(BaseModel): 4 name: STR 5 age: int = Field(… , gt=0, description=”The age must be greater than zero”) 6 desc: str 7 8 9 @router.post(“/post/UserInfo/”) 10 async def post_UserInfo(item: requestModel): 11 return item 12
Request body nesting
1 from pydantic import BaseModel,Field 2 class levelInfoModel(BaseModel): 3 id:int = None 4 info: str = None 5 6 class ClassInfo(BaseModel): 7 id: int = None 8 name: str = Field(… , max_length=20, min_length=10, 9 description=”The necessary fields”) 10 desc: str = Field(None, max_length=30, min_length=10) 11 levelInfo: List[levelInfoModel] 12 13 class Config: 14 schema_extra = { 15 “example”: { 16 “id”: 1, 17 “name”: “Foo”, 18 “desc”: “A very nice Item”, 19 “levelInfo”: [{20 “id”: 1, 21 “info”: “ClassInfo” 22}] 23} 24} 25 26 @router.post(“/info/”) 27 async def get_classInfo(item:ClassInfo): 28 return item 29
Customize the response code
1 @router.post(“/items/”, status_code=201) 2 async def create_item(name: str): 3 return {“name”: name} 4 5 from fastapi import FastAPI, status 6 7 8 @app.post(“/items/”, status_code=status.HTTP_201_CREATED) 9 async def create_item(name: str): 10 return {“name”: name} 11
Dependency injection
1 from fastapi import Depends, FastAPI 2 3 async def common_parameters(q: str = None, skip: int = 0, limit: int = 100): 4 return {“q”: q, “skip”: skip, “limit”: limit} 5 6 @router.get(“/items/”) 7 async def read_items(commons: dict = Depends(common_parameters)): 8 return commons 9 10 @router.get(“/users/”) 11 async def read_users(commons: dict = Depends(common_parameters)): 12 return commons 13
The FastAPI framework supports multiple layers of nested dependency injection
Log in the demo
4 git clone 4 source env/bin/activate 5 Github.com/hzjsea/Base… 11 # uvicorn main:app –reload 12 # uvicorn main:app –host 0.0.0.0 –port 80 –reload 13
conclusion
FastAPI is designed to be restful, using many of the new technologies without abandoning some of the previously useful content, including type annotations, dependency injection, Websocket, SwaggerUI, etc., and other annotations such as GraphQL.
Database and ORM selection
-
Sqlalchemy does not support async, but it looks like it could be extended to async.
-
Tortoise – ORm is an asynchronous ORM like Django-ORm, but it’s getting started and some features aren’t finished yet.
Sqlalchemy instance
1 from typing import List 2 import databases 3 import sqlalchemy 4 from fastapi import FastAPI 5 from pydantic import BaseModel 6 # SQLAlchemy specific code, as with any other app 7 DATABASE_URL = “sqlite:///./test.db” 8 # DATABASE_URL = “postgresql://user:password@postgresserver/db” 9 database = databases.Database(DATABASE_URL) 10 metadata = sqlalchemy.MetaData() 11 notes = sqlalchemy.Table( 12 “notes”, 13 metadata, 14 sqlalchemy.Column(“id”, sqlalchemy.Integer, primary_key=True), 15 sqlalchemy.Column(“text”, sqlalchemy.String), 16 sqlalchemy.Column(“completed”, sqlalchemy.Boolean), 17 ) 18 engine = sqlalchemy.create_engine( 19 DATABASE_URL, connect_args={“check_same_thread”: False} 20 ) 21 metadata.create_all(engine) 22 23 24 class NoteIn(BaseModel): 25 text: str 26 completed: bool 27 28 29 class Note(BaseModel): 30 id: int 31 text: str 32 completed: bool 33 34 35 app = FastAPI() 36 37 38 @app.on_event(“startup”) 39 async def startup(): 40 await database.connect() 41 42 43 @app.on_event(“shutdown”) 44 async def shutdown(): 45 await database.disconnect() 46 47 48 @app.get(“/notes/”, response_model=List[Note]) 49 async def read_notes(): 50 query = notes.select() 51 return await database.fetch_all(query) 52 53 54 @app.post(“/notes/”, response_model=Note) 55 async def create_note(note: NoteIn): 56 query = notes.insert().values(text=note.text, completed=note.completed) 57 last_record_id = await database.execute(query) 58 return {**note.dict(), “id”: last_record_id} 59
The tortoise – orm example
1 # main.py 2 from tortoise.contrib.fastapi import HTTPNotFoundError, Models = [5 “app.users. Models “, 6″ app.face. models”, 7 “app.roster. Models “, 8 “app.Statistical.models”, 9 “app.pay.models” 10 ] 11 12 register_tortoise( 13 app, 14 db_url=”mysql://username:password@ip:port/yydb”, 15 modules={“models”: models}, 16 generate_schemas=True, 17 add_exception_handlers=True, 18 ) 19 20 # models.py 21 from tortoise import fields,models 22 from tortoise.contrib.pydantic import pydantic_queryset_creator 23 from pydantic import BaseModel 24 class RosterGroupTable(models.Model): 25 id = fields.IntField(pk=True) 26 phone = fields.CharField(max_length=20,blank=True,null=True) 27 name = fields.CharField(max_length=20) 28 29 class Meta: 30 db = “RosterGroupTable” 31 32 class RosterTabel(models.Model): 33 id = fields.IntField(pk=True) 34 phone = fields.CharField(max_length=20,blank=True,null=True) 35 name = fields.CharField(max_length=20) 36 group_id = fields.ForeignKeyField(model_name=’models.RosterGroupTable’,on_delete=fields.CASCADE,related_name=”events”,blank=True,nu ll=True) 37 38 class Meta: 39 db = “RosterTabel” 40 41 RosterGroupTable_desc = pydantic_queryset_creator(RosterGroupTable) 42 RosterTabel_desc = pydantic_queryset_creator(RosterTabel) 43 44 45 46 # roster.py 47 @router.post(“/roster_statistics/add”) 48 async def roster_add_statics(*,item:RosterItem,token :str): 49 res = await RosterTabel.filter(id=item[‘memberId’]).first() 50 if res: 51 await StatisticalRosterTable.create( 52 phone = current_user.Phone, 53 date = item[‘date’], 54 time = item[‘time’], 55 data = item[‘data’], 56 name_id_id = item[‘memberId’], 57 temp_type = item[‘tm_type’], 58 today_num = item[‘todayNum’], 59 group_id_id = res.group_id_id, 60 name = res.name 61 ) 62 else: 63 Return rp_faildMessage(MSG =” List not found “,code=-1) 64 Return rp_successMessage(MSG =” List created successfully “,code=0) 65
The deployment of
dockerfile
1 # = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 2 # # fastAPI + Python3.7 + Guvicorn 4 # = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 5 6 the FROM Python: 3.7 7 LABEL Version =”v1″ 8 Description =” FastAPI “9 Maintainer =” hzjSEA” 10 using=” FastAPI & Python3.7 Office Image & Gunicorn “11 WORKDIR /root/code 12 COPY . . 13 RUN pip install -r requirements.txt 14 EXPOSE 8889 15 CMD [“gunicorn”,”-c”,”guvicorn.conf”,”main:app”] 16
Supervisor project hosting
1 [program:webserver] 2 directory=/root/hzj/fastapi_play 3 command=/root/hzj/pro_env_all/venv/bin/uvicorn main:app –host 0.0.0.0 –port 8888 4 autostart = true 5
Complete deployment example
FastAPI officially provides a complete example of a front and back end separation project github.com/tiangolo/fu…
Document and Project Address:
Documentation: fastapi.tiangolo.com
Recommended reading
Jump to 301 and talk about the tricks of the edge rule
Starting from COVID-19, Gossip protocol