FastAPI-9 服务层

9 服务层

本章阐述了服务层,即中间层。

9.1 定义服务

服务层是网站的核心,它接收来自多个来源的请求,访问作为网站DNA的数据,并返回响应。
常见的服务模式包括以下组合:

  • 创建/检索/更改(部分或全部)/删除
  • 一件事/多件事
    在 RESTful 路由器层,名词是资源。在本书中,我们的资源最初将包括隐形生物(想象中的生物)和人(隐形生物探险家)。

以后,我们还可以定义类似的相关资源:

  • 地点
  • 事件(如探险、目击等)

9.2 布局

以下是当前的文件和目录布局:

main.py
web
├── __init__.py
├── creature.py
├── explorer.py
service
├── __init__.py
├── creature.py
├── explorer.py
data
├── __init__.py
├── creature.py
├── explorer.py
model
├── __init__.py
├── creature.py
├── explorer.py
fake
├── __init__.py
├── creature.py
├── explorer.py
└── test

9.3 函数

让我们从 creature.py 开始。在这一点上,explorer.py 的需求几乎相同,我们可以借用几乎所有的东西。我们很想编写一个服务文件来处理这两个文件,但几乎不可避免的是,在某些时候我们需要以不同的方式处理它们。
另外,在这一点上,服务文件几乎就是一个直通层。在这种情况下,一开始就增加一些额外的结构,以后就会有所回报。就像第8章中的 web/creature.py和web/explorer.py,我们将为这两个文件定义服务模块,并暂时将它们与相应的假数据模块挂钩。

service/creature.py

from models.creature import Creature
import fake.creature as data

def get_all() -> list[Creature]:
    return data.get_all()

def get_one(name: str) -> Creature | None:
    return data.get(id)

def create(creature: Creature) -> Creature:
    return data.create(creature)

def replace(id, creature: Creature) -> Creature:
    return data.replace(id, creature)

def modify(id, creature: Creature) -> Creature:
    return data.modify(id, creature)

def delete(id, creature: Creature) -> bool:
    return data.delete(id)

service/explorer.py

from models.explorer import Explorer
import fake.explorer as data

def get_all() -> list[Explorer]:
    return data.get_all()

def get_one(name: str) -> Explorer | None:
    return data.get(name)

def create(explorer: Explorer) -> Explorer:
    return data.create(explorer)

def replace(id, explorer: Explorer) -> Explorer:
    return data.replace(id, explorer)

def modify(id, explorer: Explorer) -> Explorer:
    return data.modify(id, explorer)

def delete(id, explorer: Explorer) -> bool:
    return data.delete(id)

9.4 测试

现在,代码库正在逐渐充实,是引入自动测试的好时机,让我们创建一些目录:

  • test:顶级目录,与web, service, data和model目录并列。
    • unit: 测试单个函数,但不跨层。
      • web: 网络层单元测试。
      • service: 服务层单元测试。
      • data:数据层单元测试。
  • full: 也称为端到端或合约测试,这些测试同时跨越所有层。它们涉及网络层的 API 端点。

这些目录有test_前缀或_test 后缀,供pytest使用 。
在测试之前,需要对 API 的设计做出一些选择。如果找不到匹配的 Creature 或 Explorer,get_one() 函数应该返回什么?可以返回 None,或者引发异常。没有一个内置的Python异常类型可以直接处理缺失值:

  • TypeError可能是最接近的,因为 None与Creature 是不同的类型。
  • ValueError 更适用于给定类型的错误值,但我想你也可以说,向 get_one(id)传递一个缺失的字符串 id 也符合条件。
  • 如果你真的需要,也可以定义自己的MissingError。

test/unit/service/test_creature.py

from model.creature import Creature
from service import creature as code

sample = Creature(name="yeti",
        country="CN",
        area="Himalayas",
        description="Hirsute Himalayan",
        aka="Abominable Snowman",
        )

def test_create():
    resp = code.create(sample)
    assert resp == sample

def test_get_exists():
    resp = code.get_one("yeti")
    assert resp == sample

def test_get_missing():
    resp = code.get_one("boxturtle")
    assert data is None

执行:

$ pytest -v test/unit/service/test_creature.py
test_creature.py::test_create PASSED                         [ 16%]
test_creature.py::test_get_exists PASSED                     [ 50%]
test_creature.py::test_get_missing PASSED                    [ 66%]

======================== 3 passed in 0.06s =========================

参考资料

9.5 其他服务层内容

我们现在正处于堆栈的中间部分--真正定义网站目的的部分。到目前为止,我们只用它将网络请求转发到(下一章的)数据层。
到目前为止,本书以迭代的方式开发了网站,为今后的工作打下了最基本的基础。当你对你所拥有的、你所能做的以及用户可能需要的有了更多了解后,你就可以进行扩展和尝试。有些想法可能只对大型网站有益,但这里有一些技术性的网站辅助想法:

  • Logging
  • Metrics
  • Monitoring
  • Tracing

9.5.1 Logging

FastAPI会记录每次对端点的API调用,包括时间戳、方法和 URL,但不会记录通过正文或标头传递的任何数据。

9.5.2 指标、监控和可观察性

如果你运行一个网站,你可能想知道它的运行情况。对于 API 网站,你可能想知道哪些端点正在被访问、有多少人在访问等等。对这些因素的统计称为度量,收集度量是监控或可观察性。
时下流行的度量工具包括用于收集度量数据的Prometheus和用于显示度量数据的Grafana。

9.5.3 跟踪

您的网站性能如何?常见的情况是,度量指标总体良好,但某些地方或某些地方的结果令人失望。或者整个网站一团糟。无论哪种情况,有一个工具可以测量 API 调用从头到尾所需的时间--不仅是整体时间,还包括每个中间步骤的时间,这非常有用。如果某项工作进展缓慢,就可以找到链条中的薄弱环节。这就是跟踪。

一个新的开源项目采用了早期的跟踪产品(如 Jaeger),并将其命名为 OpenTelemetry。它有一个Python API,并至少与FastAPI 进行了一次集成。

9.5.4 其他

除此以外,我们的域密码和与之相关的任何内容又是怎样的呢?除了探索者和生物的基本细节外,你还想做什么?你可能会想出需要修改模型和其他层的新想法。以下是一些你可以尝试的想法:

  • 探险者与他们寻找的生物的链接
  • 目击数据
  • 探险
  • 照片和视频
  • 大脚野人马克杯和T恤衫

9.6 小结

在本章中,你复制了网络层中的一些函数,并移动了它们所使用的假数据。目的是启动新的服务层。到目前为止,这个过程都是按部就班地进行的,但在此之后,它还会不断发展和变化。下一章将构建最终的数据层,形成一个真正的实时网站。

热门相关:邪王独爱:娘子不准逃跑   腹黑boss霸宠:逃妻,吻我   废材归来:绝色魔君驭兽后   重生八零俏佳妻   逃妻鲜嫩嫩:霸道老公,吻够没