FastAPI 依赖注入详解:概念
FastAPI得力于Typing、Pydantic以及Inspect,强大的类型库和反射库,给与了其进行类型检测和依赖注入的能力。
为什么可以进行类型检测
endpoint 指的是我们所编写的,处理request请求的函数。而我们会将希望从HTTP报文中获取的参数,填写在endpoint参数的位置。
Inspect库是Python强大的反射库,它可以实现自省,对函数的参数进行检测,得到它们的信息。包括参数名,标注的类型,默认值,允许的传值方式。
def test(a: int, b: str = "b_str"):
pass
sig = inspect.signature(test)
params = dict(sig.parameters)
参数字典
我们可以看到,每个参数会被解析为一个Parameter对象,里面记录了参数的各种信息。
annotation
,default
代表着类型注解和默认值,kind
表示允许何种方式传参。
empty
是用来做判断的工具,我们可以看到当annotation
,default
未标注时,其类型是<class 'inspect._empty'>
,当我们想判断是否有标注时,就需要与其做比较,为了方便,empty用来代表<class 'inspect._empty'>
。只需要与他进行判断即可。
这样,一个函数的参数信息便是已知的,进而,一个endpoint所需要的参数信息也是已知的。框架知道我们的endpoint需要什么样的参数。
为什么需要类型检测
FastAPI高度集成OpenAPI(即SwaggerUI),参数类型检测,可以生成信息更加明确和丰富的API文档。这对于效率上来说是飞跃性的提升。后端只需要把endpoint写出来,框架就会将信息丰富的API文档自动生成出来。
另一方面,就是为依赖注入提供了基础。
为什么需要依赖注入
如果你了解spring的话,你一定知道spring的核心技术是IOC和AOP,IOC是DI的前提,DI是IOC的一种实现。
FastAPI的依赖注入,主要是为了解决两个问题。
- 在endpoint之前执行一些逻辑,这更加符合依赖的字面意思,本件事(endpoint)必须依赖于某些事(依赖项)的成功执行。并获取他们的返回值
- 智能的依赖项填充,我们接收的request可能包含大量字段,我们也可能需要他们作为参数,生成各种对象。例如我的request中包含
name, age, email, token, count, title, article
我需要让他们满足
(User(name, age, email), Depend(verify_token), count, Article(title, article))
等一系列参数,正常情况下我们只能自己手动实例化或调用这些内容。但是依赖注入帮我们将这些步骤都完成了,这得利于inspect的反射,可以检测每个角色都需要什么样的参数。
从广义上来讲,endpoint执行前所需要准备的所有项,都属于依赖系统的范畴。FastAPI的依赖系统,负责为endpoint准备“环境”。
那么,这些项都是指的哪些?
- 普通参数
- 参数校验 Path(),Query()
- 额外参数 Header(),Cookie(),Body(),Form(),File()
- 依赖项 Depends(),Security()
重点在于Depnds()
Depends()可以携带一个函数,或者一个类。返回的结果是其result,或者实例。
所有依赖项都可以有自己的参数,这些参数是从报文中拦截。
这就像派发快递的小哥,而依赖项是走在你前面的人。快递小哥会优先将他需要的快递派发给他,在剩余的快递中寻找你所需的。如果有差错,那就说明出了大问题,你们之间的所需起了冲突。
- Depends()有两个参数,
dependency
和use_cache
,前者是我们的依赖项,而后者,代表的是是否使用缓存。
缓存的意义在于,假设在解决依赖的过程中,有一个依赖项不止执行一次,他可能被多次需求。但我们不希望多次执行它。我们便可以使用缓存来解决。
缓存默认置为True,我们不需要手动开启它,但是某些情况下,我们希望同一个依赖项多次执行,那么便可以手动置为False - 依赖项可以写在装饰器的dependencies参数中,例如:
@app.get("/items/", dependencies=[Depends(verify_token), Depends(verify_key)])
这代表着我们不需要这个依赖项的结果,只需要其顺利执行。 - 依赖项中可以使用 yield 和 context,例如获取数据库session的依赖项,我们可能只需要其不断产生session,而不是将整个函数重新执行一次,便可以用yield不断为所有需求方提供yield。而context可以帮我们更好的管理生成的依赖项
参考官方文档:https://fastapi.tiangolo.com/zh/tutorial/dependencies/dependencies-with-yield/