项目开发--fastapi框架入门

##背景
1、fastapi的同步和异步是如何进行控制的?
2、主要的参数有哪些?
3、RESTful的API设计规范是什么?
4、什么是路由?
5、关于序列化和反序列化如何才能像java一样便捷?
6、HTTP cookies有什么设计规范?
7、FastAPI的特性?
8、依赖注入是什么?
9、什么叫依赖倒置原则?
10、Fastapi当中的中间件有哪些?作用是什么?
11、fastapi的主要http请求有哪几个?分别作用是什么?

框架对比

一个轻量级的Web应用框架,是基于Werkzeug WSGI工具箱和Jinja2模板引擎而开发出来的。Flask自己也宣称是一个Micro Framework的框架。Flask之所以比Bottle更加受欢迎,是因为它自身的设计非常好,对于一些功能插件也保留了弹性扩展,而且它是持续更新维护的。从这一点上,就足以让更多的人愿意使用它。Flask框架的插件生态也非常好,有非常多的可用第三方插件,开箱即用。

Django是一个大而全的框架,是一个完整的Web开发框架。对于小业务场景来说,使用Django框架会过于笨重,部分模块也无法进行定制。但是Django仍然是Python Web框架中非常流行的框架之一,国内外的一些大企业都是其用户,如国内腾讯的蓝鲸智云PaaS平台,国外则有图片分享社交应用Instagram、Pinterest等。如果需要构建健壮的全栈式网站,那么Django框架是比较好的选择

FastAPI框架不仅具有Flask或Django的Web核心功能,还兼具异步特性,可以同时兼容同步和异步这两种模式的运行。也就是说,用户可以使用同步的方式编写API,也可以使用异步的方式来编写API。不仅如此,它对于一些插件的自定义扩展相当简单,插件间可以相互独立。用户可以根据实际业务需求来定义不同的组件或插件来扩展并集成到FastAPI中。

问题笔记

APIRouter

基于APIRouter实例的路由注册
我们已经学过如何进行一个简单API端点路由的注册,这里补充介绍对其他路由添加注册的实现方式以及注册过程中需要注意的细节问题。
API端点路由注册方式大致可以分为3种:
❑基于app实例对象提供的装饰器或函数进行注册。
❑基于FastAPI提供的APIRouter类的实例对象提供的装饰器或函数进行注册。
❑通过直接实例化APIRoute对象且添加的方式进行注册。
注意
这里的APIRouter和APIRoute是不一样的。APIRouter主要用于定义路由组,可以理解为一个路由组的根路由,而APIRoute则表示具体路由节点对象。APIRouter可以实现的功能类似Flask框架中提供的一种蓝图模式的加载。如果读者没有使用Flask框架的经验,则可以认为蓝图模式就是路由分组。在大型的项目开发中,通常需要针对不同业务进行不同API的分组,此时如果单纯基于app实例对象来实现分组,那么相对来说比较麻烦,所以引入APIRouter类来实现路由嵌套和分组。

问题3

RESTful API常用的HTTP方法主要有如下几个:
❑GET:读取数据库信息。
❑POST:创建新增数据。
❑PUT:更新已有数据。
❑PATCH:更新数据,通常仅更新部分数据。
❑DELETE:删除数据信息。

问题4

“我们知道,在FastAPI框架中,所有的注册路由都会统一保存到app.routes中。app.routes保存了所有的路由注册信息。如果需要查看当前应用注册的所有路由信息,那么在启动服务后打印输出app.routes值即可。”

在 FastAPI 框架中,当你定义路由(即指定某个 URL 路径和 HTTP 方法应该由哪个函数处理)时,这些路由信息会被存储在 FastAPI 应用实例的内部数据结构中。这个数据结构通常被称为 routes,它保存了所有注册路由的详细信息。

什么是路由?
在 Web 应用中,路由是 URL 与应用中处理函数之间的映射。当你访问某个 URL 时,路由决定了哪个函数(通常称为“视图函数”或“处理函数”)会被调用来处理这个请求。

FastAPI 中的 app.routes
在 FastAPI 应用中,每个路由都是通过装饰器(如 @app.get, @app.post 等)注册到应用实例的。这些路由信息包括:

HTTP 方法(如 GET, POST, PUT, DELETE 等)
URL 路径
处理函数
额外的元数据(如摘要、描述、响应模型等)
查看注册的路由信息
如果你想查看当前应用中注册的所有路由信息,可以在应用启动之前或在某个路由处理函数中打印 app.routes。这会给你一个列表,其中每个条目都包含了一个路由的详细信息。

例如:

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def read_root():
    return {"Hello": "World"}

@app.get("/items/")
async def read_items():
    return {"items": ["Foo", "Bar"]}

# 打印所有路由信息
print(app.routes)

在上述代码中,app.routes 将输出类似以下内容(具体格式可能略有不同):

[
    Route(path='/', endpoint=read_root, methods=['GET'], ...)
    Route(path='/items/', endpoint=read_items, methods=['GET'], ...)
]

为什么查看路由信息有用?
查看注册的路由信息可以帮助你:

验证你的路由是否正确注册。
理解应用的 URL 结构和处理逻辑。
在开发和调试过程中检查应用的配置。
注意
虽然在开发过程中打印 app.routes 可以提供有用的信息,但在生产环境中通常不需要这样做。此外,打印大量路由信息可能会影响性能,因此在生产环境中应避免这样做。

总之,app.routes 是 FastAPI 应用内部用于存储路由注册信息的数据结构,它可以让你了解应用如何处理不同的 URL 和 HTTP 方法。

问题7

FastAPI之所以能被多数人认可并使用,主要原因与它所具备的一些特性有着极大的关系。FastAPI为了构建快速的API而生。FastAPI的特性主要有:

❑是一个支持ASGI(Asynchronous Server Gateway
Interface)协议的Web应用框架,也就是说,它同时兼容ASGI和WSGI的应用。
❑天然支持异步协程处理,能快速处理更多的HTTP请求。
❑使用了Pydantic类型提示的特性,可以更加高效、快速地进行接口数据类型校验及模型响应等处理。
❑基于Pydantic模型,它还可以自动对响应数据进行格式化和序列化处理。 ❑提供依赖注入系统的实现,它可以让用户更高效地进行代码复用。
❑它支持WebSocket、GraphQL等。 ❑支持异步后台任务,可以方便地对耗时的任务进行异步处理。
❑支持服务进程启动和关闭事件回调监听,可以方便地进行一些插件的扩展初始化。 ❑支持跨域请求CORS、压缩Gzip请求、静态文件、流式响应。
❑支持自定义相关中间件来处理请求及响应。 ❑支持开箱即用OpenAPI(以前被称为Swagger)和JSON
Schema,可以自动生成交互式文档。 ❑使用uvloop模块,让原生标准的asyncio内置的事件循环更快。

ASGI是异步服务器网关接口,和WSGI一样,都是为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口。但是ASGI是WSGI的一种扩展的实现,并且提供异步特性和WebSocket等的支持。同时ASGI也是兼容WSGI的,在某种程度上可以理解为ASGI是WSGI的超集,所以ASGI可以支持同步和异步同时运行,内部可以直接通过一个转换装饰器进行相互切换。
首先从快速特性来说,基于异步协程方式的Web框架目前是多数开发者寻求的一个关键点,在多核CPU下如何更加高效地提高CPU使用效率也是当下众多异步Web框架的关注点,而FastAPI融合原生asyncio异步协程的特性刚好迎合了这个契机。
FastAPI基于Starlette和Pydantic做了很多封装,简化了一些编码工作。如相关的参数类型提示、参数校验、直接输出模型响应报文等,都为开发者提供了很多便利,让程序员可以更加顺畅、快速地进行编码工作。
另外,FastAPI还配备了OpenAPI规范(OAS),它自动生成了OpenAPI模式。基于OpenAPI,用户可以直接、快速地对API文档进行查看和调试,可以让用户使用相同的代码来定义序列化和相关数据验证,这种所见即所得的开箱体验是非常好的。
OpenAPI规范(OAS)是一个定义标准的与具体编程语言无关的RESTful API的规范。
目前在国内,越来越多的后端开发者从使用Flask框架慢慢转移到了FastAPI框架。本书会从FastAPI框架的基础知识到具体项目的实战内容进行叙述。如果读者有Flask框架的使用体验,过渡到FastAPI框架是轻而易举的。如果读者没有任何的Web框架开发经验,那么学习本书可以帮助读者使用FastAPI进行实际项目开发。

问题8

依赖注入(Dependency Injection,DI)是一种设计模式,它用于实现软件设计中的依赖倒置原则(Dependency Inversion Principle),这是面向对象设计原则之一,属于 SOLID 原则的一部分。依赖注入的核心思想是将组件的依赖关系由外部传入(注入),而不是由组件自己创建或查找依赖对象,从而实现组件间的松耦合。

依赖注入的主要特点:
解耦合:组件不需要知道其依赖的具体实现,只需要关注依赖的接口或抽象类。这样,组件的实现和依赖的实现就被解耦了。

灵活性:由于依赖是从外部注入的,因此可以在运行时动态地替换依赖的实现,提高了组件的灵活性。

测试性:依赖注入使得在测试时可以轻松地使用模拟对象(Mock)来替代实际的依赖对象,从而更容易编写单元测试。

控制反转:在传统的程序设计中,组件通常自己负责获取或创建其依赖的对象。依赖注入则将这种控制权反转给容器或框架,由它们来负责创建和管理依赖对象。

依赖注入的类型:
构造函数注入:通过构造函数将依赖传递给组件。
设值器注入(Setter Injection):通过 setter 方法将依赖设置到组件中。
接口注入:通过接口方法将依赖传递给组件。
方法注入:直接在方法调用中注入依赖。

在 FastAPI 中的依赖注入:
FastAPI 是一个现代、快速(高性能)的 Web 框架,它使用 Python 3.6 及以上版本的类型提示功能来自动处理依赖注入。在 FastAPI 中,依赖注入通常通过依赖项函数(Dependency Functions)来实现,这些函数返回一个值,该值将被注入到路径操作函数中。

例如,一个依赖项函数可以用于验证用户的身份:

from fastapi import Depends, FastAPI, HTTPException

app = FastAPI()

def get_token_header(x_token: str = Header(None)):
    if x_token not in tokens:
        raise HTTPException(status_code=400, detail="X-Token header invalid")
    return x_token

@app.get("/items/")
async def read_items(token: str = Depends(get_token_header)):
    return {"token": token}

在这个例子中,get_token_header 是一个依赖项函数,它从请求头中获取 X-Token,并验证其有效性。Depends(get_token_header) 用于将这个依赖注入到 read_items 路径操作函数中。

总结来说,依赖注入是一种提高软件设计灵活性和可维护性的重要模式,FastAPI 通过依赖项函数和类型提示功能,使得依赖注入在 Web 应用开发中变得简单而强大。

问题9

依赖倒置原则(Dependency Inversion Principle,DIP)是面向对象设计原则之一,它是 SOLID 原则中的 “D”。依赖倒置原则的核心思想是要依赖于抽象(接口或抽象类),不要依赖于具体实现(具体类)。这个原则有两个主要的指导方针:

高层模块不应该依赖低层模块:系统中的高层策略性业务规则不应该依赖于低层的具体实现细节,两者都应该依赖于抽象。

抽象不应该依赖于细节:抽象不应该依赖于具体实现,具体实现应该依赖于抽象。

依赖倒置原则的目的:
降低耦合度:通过依赖抽象而非具体实现,可以减少模块间的直接依赖关系,使得系统更加灵活和可维护。
提高模块化:模块之间的交互基于抽象接口,这样可以更容易地替换模块的具体实现,而不会影响到其他模块。
增强可扩展性:当需要新增功能或替换现有功能时,可以更容易地进行扩展,而不需要修改依赖于具体实现的高层模块。
依赖倒置原则的实现:
使用接口或抽象类:定义接口或抽象类来表示组件之间的契约,而不是直接使用具体类。
依赖注入:通过依赖注入(DI)技术,将具体实现注入到需要它们的对象中,而不是让对象自己创建或查找它们的依赖。
依赖倒置原则与控制反转(IoC):
依赖倒置原则是控制反转(Inversion of Control,IoC)的一种表现形式。控制反转是一种设计思想,它将对象的创建和它们之间的依赖关系管理从对象本身转移到外部容器或框架。依赖注入是实现控制反转的一种具体技术。

示例:
假设我们有一个 EmailService 类,它负责发送电子邮件。根据依赖倒置原则,我们不应该让 EmailService 直接依赖于一个具体的邮件发送类,而是应该依赖于一个抽象的接口。

# 错误的依赖实现
class EmailService:
    def send_email(self, recipient, message):
        # 直接依赖于具体实现
        sender = SMTPSender()
        sender.send(recipient, message)

# 正确的依赖实现
class EmailSender:
    def send(self, recipient, message):
        pass

class EmailService:
    def __init__(self, sender: EmailSender):
        self.sender = sender

    def send_email(self, recipient, message):
        # 依赖于抽象
        self.sender.send(recipient, message)

在这个例子中,EmailService 依赖于 EmailSender 接口,而不是具体的 SMTPSender 类。这样,如果将来需要更换邮件发送的方式,我们只需要提供一个实现了 EmailSender 接口的新类,而不需要修改 EmailService 类的代码。这就体现了依赖倒置原则的精神。

中间件

在 Web 开发中,中间件是一种位于客户端请求和服务器端处理之间的软件组件,它提供了在请求被处理之前或响应发送给客户端之后执行代码的机会。在 FastAPI 框架中,中间件的概念同样适用,并且它们遵循 ASGI(异步服务器网关接口)规范。

FastAPI 的中间件可以用于多种场景,包括但不限于:

请求跨域处理:允许来自不同源的客户端请求访问服务器。
API 限流限速:控制客户端的请求频率,防止滥用。
接口监控:记录请求和响应,用于性能监控和调试。
日志记录:记录请求和响应的详细信息,用于日志分析。
IP 白名单限制:只允许特定 IP 地址的请求访问。
请求权限校验:检查用户是否有权限执行请求。
请求缓存:缓存请求的结果,减少服务器的负载。
认证和授权:验证用户身份和权限。
压缩响应内容:减少发送给客户端的数据量,加快响应速度。
FastAPI 的中间件通常是通过继承 starlette.middleware.base.BaseHTTPMiddleware 类来实现的。中间件类需要实现 dispatch 方法,该方法会在每个请求和响应的生命周期中被调用。

下面是一个简单的 FastAPI 中间件示例,它记录了每个请求的处理时间:

from starlette.middleware.base import BaseHTTPMiddleware
import time

class SimpleMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request, call_next):
        start_time = time.time()
        response = await call_next(request)
        process_time = time.time() - start_time
        print(f"Request {request.url.path} processed in {process_time} seconds")
        return response

在 FastAPI 应用中使用中间件
app.add_middleware(SimpleMiddleware)
在这个例子中,SimpleMiddleware 类记录了处理每个请求之前的时间,然后在请求处理完成后计算出处理时间,并打印出来。

FastAPI 框架本身提供了许多内置的中间件,这些中间件大多数来源于 Starlette 框架,因为 FastAPI 是在 Starlette 之上构建的。开发者可以根据自己的需要选择使用这些中间件,或者自定义中间件来满足特定的需求。

主要http请求

使用 Python 3.6 及以上版本。FastAPI 基于标准 Python 类型提示,并且利用了 Python 类型注解,这使得它非常适合构建 RESTful API。

FastAPI 支持的 HTTP 请求方法主要有以下几种:

GET:用于请求从服务器检索特定资源。
POST:用于向服务器提交要处理的数据(例如,表单提交或 API 调用)。
PUT:用于向服务器发送要替换现有资源的数据。
DELETE:用于删除服务器上的资源。
PATCH:用于对服务器上的资源进行部分修改。
HEAD:与 GET 类似,但只返回 HTTP 头部,不返回响应体。
OPTIONS:用于描述目标资源的通信选项。
CONNECT:用于将连接改为管道方式。

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI()

# 定义数据模型
class Item(BaseModel):
    name: str
    description: str = None
    price: float
    tax: float = None

# 创建一个 GET 路由
@app.get("/items/")
async def read_items():
    return {"message": "List of items"}

# 创建一个 POST 路由
@app.post("/items/")
async def create_item(item: Item):
    if item.name == "Foo":
        raise HTTPException(status_code=400, detail="Item name can't be 'Foo'")
    return {"name": item.name, "price": item.price}

# 运行 uvicorn main:app --reload

GET /items/:当客户端发送 GET 请求到这个端点时,它会返回一个包含消息的 JSON 响应。
POST /items/:当客户端发送 POST 请求到这个端点时,它会接收一个 Item 对象作为 JSON 请求体,并返回一个包含该对象信息的 JSON 响应。如果 name 字段是 “Foo”,则会抛出一个 HTTP 400 错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值