FastAPI是一个用于构建高性能Web应用程序的Python框架。它基于Python 3.7+的新特性,如类型注释、异步I/O和API路由等,提供了一种快速、简单和易于使用的方法来构建Web API。
在这篇文章中,将介绍FastAPI及其主要特点和性能,以及Python与其他流行框架相比较的应用实例。
什么是FastAPI?
FastAPI是由Sebastián Ramírez在2018年发布的。他创建FastAPI的想法来自于在使用当时存在的框架来执行开发API的任务时所遇到的一些困难。
FastAPI号称是目前最快的Python框架之一,可将开发速度提高多达300%并具有高性能。这个框架使用了Python最新版本中增加的功能,创造了一个用于构建API的现代工具。此外,FastAPI使用scarlett
、Pydantic
和OpenAPI
等工具,以寻求高性能、低学习曲线和易于应用程序编码。
技术交流
技术要学会分享、交流,不建议闭门造车。一个人可以走的很快、一堆人可以走的更远。
技术交流、资料干货、数据&源码,均可加交流群获取,群友已超过2000人,添加时最好的备注方式为:来源+兴趣方向,方便找到志同道合的朋友。
方式①、微信搜索公众号:Python学习与数据挖掘,后台回复: 交流
方式②、添加微信号:dkl88194,备注:来自CSDN +交流
毕设/大作业系列
毕设/大作业:基于Python+Flask+MySQL的豆瓣电影可视化系统毕设/大作业:搭建基于 Python+Flask+MySQL 的学生培养计划管理系统(附源码)毕设/大作业:一款基于 Python+flask 的态势感知系统(附完整源码)毕设/大作业:基于 Python 的 Flask 框架开发的在线电影网站系统(附完整源码)毕设/大作业:基于 Echarts + Python Flask 动态实时大屏轻松可以实现毕设/大作业:基于 Python+Django 构建智能互动拍照系统毕设/大作业:基于 Python+Flask+SQLite 的网易云音乐评论情感分析系统毕设/大作业:基于 Python 和Surprise库,新手轻松搭建推荐系统毕设/大作业:基于 Python+Django+MySQL 数据库的租房数据可视化系统主要特点:
性能
毋庸置疑,FastAPI最吸引人的是它的性能测试结果。与其他更传统的框架如Django
和Flask
相比,FastAPI的性能更强。这是由于该框架是使用Starlette
构建的,Starlette
是一个轻量级的ASGI
框架/工具,是在Python中构建异步Web服务的理想选择。
在下面的图片中,可以看到各种框架之间的性能比较。FastAPI在这个测试中的表现比Django
和Flask
好,仅次于Uvicorn
和Starlette
,在查看其性能时是由于Uvicorn
和Starlette
更适合,因为它们是针对这一特定情况的更具体的框架,然而FastAPI和其他框架相比有更多的功能。
并发和异步/等待
FastAPI实现的本地异步支持也支持应用程序的性能。与其他未实现异步编程的基于Python 2的框架相比,这是一个优势。
快速编码
由于使用了Type Hints
和Pydantic
(一种简单的声明性语法),FastAPI被认为是一个非常精简的框架,并且像Flask
一样,它使用模块化的概念来增加新功能。
自动文档
只需几行代码,FastAPI就能使用OpenAPI生成其端点的文档。将在下面的例子中看到这个功能。
安装
要求
Python 3.7以上使用如下的命令安装FastAPI。
pip install fastapi
还需要一个ASGI
服务器,用于生产目的,如Uvicorn
或Hypercorn
。
pip install "uvicorn[standard]"
在这个例子中也将使用SQLAlchemy ORM
。
pip install SQLAlchemy
电影CRUD API
接下来,将创建一个简单的应用程序,其中包括一个API,用于CRUD一个名为Movies
的表。
在安装了FastAPI、Uvicorn
和SQLAlquemy
之后,将创建以下文件结构。
数据库
开始创建管理数据库的模块。在这个模块中,将使用SQLAlchemy ORM
来管理SQLite
数据库,创建电影模型并访问数据。
src/db/database.py
文件将负责创建数据库连接和管理会话。
from sqlalchemy import create_enginefrom sqlalchemy.ext.declarative import declarative_basefrom sqlalchemy.orm import sessionmakerSQLALCHEMY_DATABASE_URL = "sqlite:///db/db.sqlite3"engine = create_engine( SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)Base = declarative_base()def get_db(): db = SessionLocal() try: yield db finally: db.close()
在src/db/models.py
文件中,将创建Movies
表,它将包含属性id
、title
、director
、duration_in_minutes
和rating
。
from sqlalchemy import Column, Integer, Stringfrom db.database import Baseclass Movies(Base): __tablename__ = "Movies" id: int = Column(Integer, primary_key=True, index=True) title: str = Column(String(100), nullable=False) director: str = Column(String(255), nullable=False) duration_in_minutes: int = Column(Integer, nullable=False) rating: int = Column(Integer, nullable=False)
最后,将创建src/db/repositories.py
文件,它将作为一个接口,使API层能够访问数据库资源。
from sqlalchemy.orm import Sessionfrom .models import Moviesclass MovieRepository: @staticmethod def find_all(db: Session) -> list: return db.query(Movies).all() @staticmethod def save(db: Session, movie: Movies) -> Movies: if movie.id: db.merge(movie) else: db.add(movie) db.commit() return movie @staticmethod def find_by_id(db: Session, id: int) -> Movies: return db.query(Movies).filter(Movies.id == id).first() @staticmethod def exists_by_id(db: Session, id: int) -> bool: return db.query(Movies).filter(Movies.id == id).first() is not None @staticmethod def delete_by_id(db: Session, id: int) -> None: movie = db.query(Movies).filter(Movies.id == id).first() if movie is not None: db.delete(movie) db.commit()
模式
src/schemas.py
文件将包含表示将在HTTP
请求或响应的主体中接收和返回的数据的类。为了创建这些类,将使用Pydantic
,这是一个安装FastAPI时附带的库。Pydantic
旨在通过使用Python的Type Hints
功能,提供一种更简单、更直接的方式来执行数据验证。
在MovieBase
类中,拥有在请求和API响应中都存在的基本属性。创建这个类是为了减少代码的重复。请注意,除了使用Type Hints
之外,duration_in_minutes
和rating
属性也使用了Pydantic
验证。
另外,在MovieResponse
类中创建了一个叫做Config
(配置)的不同的类,用于向我们的Pydantic
模型传递额外的配置。所做的配置将orm_mode
选项设置为True
,从而使类中的一个静态方法称为from_orm
。这个类允许从ORM
的一个模型类中创建一个Pydantic
模型的实例。
from pydantic import BaseModel, Fieldclass MovieBase(BaseModel): title: str director: str duration_in_minutes: int = Field(ge=0) rating: int = Field(ge=1, le=5)class MovieRequest(MovieBase): passclass MovieResponse(MovieBase): id: int class Config: orm_mode = True
FastAPIs CRUD
现在准备创建src/main.py
文件,在该文件中将实例化FastApi应用程序。除了FastAPI文件外,还将SQLAlchemy
的元素导入该文件,以建立与数据库的连接、先前创建的模式类以及用于数据类型的类。
第一个函数是创建函数,它负责在数据库中注册电影。这个函数使用@app.post
装饰器,这样路由就被解释为POST
。在这个装饰器中,告知路由端点response_model
,告知响应体中会包含什么类型的数据,最后是status_code
,定义了成功请求后的预期HTTP
状态。
在创建方法中,定义了一个叫做request
的参数,它是MovieRequest
的类型。这个参数接收在请求正文中传递的数据。还有一个名为db
的第二个参数,其类型为Session
,其默认值为Depends(get_db)
指令。此刻正在执行依赖注入,FastAPI将执行get_db
函数。这将返回一个LocalSession
类的实例,它是数据库会话;然后它将把这个会话传递给创建函数。
列出所有电影、通过ID搜索电影、更新电影和删除电影的其他端点与创建端点的模式相同。所有的端点都有一个路由和一个HTTP
动词,此外还有一些响应,例如在没有找到电影ID的情况下,会有一个失败的状态。
from fastapi import FastAPI, Depends, HTTPException, status, Responsefrom sqlalchemy.orm import Sessionfrom db.models import Moviesfrom db.database import engine, Base, get_dbfrom db.repositories import MovieRepositoryfrom schemas import MovieRequest, MovieResponseBase.metadata.create_all(bind=engine)app = FastAPI()@app.post( "/api/movies", response_model=MovieResponse, status_code=status.HTTP_201_CREATED)def create(request: MovieRequest, db: Session = Depends(get_db)): movie = MovieRepository.save(db, Movies(**request.dict())) return MovieResponse.from_orm(movie)@app.get("/api/movies", response_model=list)def find_all(db: Session = Depends(get_db)): movies = MovieRepository.find_all(db) return [MovieResponse.from_orm(movie) for movie in movies]@app.get("/api/movies/{id}", response_model=MovieResponse)def find_by_id(id: int, db: Session = Depends(get_db)): movie = MovieRepository.find_by_id(db, id) if not movie: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="movie not found" ) return MovieResponse.from_orm(movie)@app.delete("/api/movies/{id}", status_code=status.HTTP_204_NO_CONTENT)def delete_by_id(id: int, db: Session = Depends(get_db)): if not MovieRepository.exists_by_id(db, id): raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="movie not found" ) MovieRepository.delete_by_id(db, id) return Response(status_code=status.HTTP_204_NO_CONTENT)@app.put("/api/movies/{id}", response_model=MovieResponse)def update(id: int, request: MovieRequest, db: Session = Depends(get_db)): if not MovieRepository.exists_by_id(db, id): raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="movie not found" ) movie = MovieRepository.save(db, Movies(id=id, **request.dict())) return MovieResponse.from_orm(movie)
运行应用程序
随着所有代码的准备就绪,现在可以运行应用程序。
uvicorn main:app --reload
自动文档
正如之前所看到的,FastAPI的主要功能之一是用OpenAPI
轻松创建自动文档。在对应用程序进行本地部署之后,访问http://localhost:8000/docs route
,可以找到一个包含所有端点、模型和验证的交互式文档,所有这些都是只用Pydantic
和Type Hints
创建的。
FastAPI vs. Flask vs. Django
当谈论用Python开发Web应用时,最流行的框架是Django
和Flask
。
Django
于2005年发布,直到今天它都是最常用的框架,有大量的学习资料、库和活跃的社区。Django
遵循单体结构,有自己的ORM
,也有DRF
等流行框架。由于它的结构,Django
被认为是一个完整的框架,推荐用于复杂的应用程序。
另一方面,Flask
被认为是与Django
相反的。它被归类为一个微框架,使用模块化结构,可以使用不同的库和框架来构建应用程序。由于Flask
的简单性和快速开发,它被推荐用于小型应用。
最终,FastAPI试图在关注性能的同时,在简单性和更多的本地功能之间取得平衡。该框架因使用了其他框架因过时而没有的较新功能而获得欢迎。建议在需要高性能、低延迟和高开发速度的工具中使用FastAPI。然而,人们应该考虑到,由于它是一个相对较新的框架,除了有一个较小的社区外,它没有如此大量的库。
结论
总之,FastAPI有几个优点,包括容易编码的应用程序,使用简单,学习迅速,有一个用户友好的界面,并与大多数Python库和工具兼容。
然而,像任何技术一样,它也有其局限性,例如,与Flask
和Django
等更成熟的框架相比,社区相对较小,教程和资源数量有限。最终,使用FastAPI的决定将取决于项目的具体需求和开发团队的经验。然而,凭借其速度和易用性,FastAPI肯定值得在未来的任何API开发项目中考虑。