穷人的 API
创建一个功能齐全的 API 需要投入大量资源,包括时间和金钱。您需要思考模型、设计、REST 原则等等,而不需要编写任何代码。大多数情况下,您并不确定这样做是否值得:您只想提供一个最小可行产品 (MVP),然后在此基础上进行迭代。我想向您展示如何在不编写任何代码的情况下实现这一点。
解决方案
该解决方案的主要要求是使用PostgreSQL 数据库。它是一个成熟的开源 SQL 数据库。
我们不需要编写 REST API,而是使用 PostgREST 组件:
PostgREST 是一个独立的 Web 服务器,可将您的 PostgreSQL 数据库直接转换为 RESTful API。数据库中的结构约束和权限决定了 API 的端点和操作。
-- PostgREST
让我们将其应用于一个简单的用例。这是product
我想通过 CRUD API 公开的表:
请注意,您可以在GitHub上找到完整的源代码以供参考。
PostgREST 的入门指南非常完整,开箱即用。但是,我没有找到任何现成的 Docker 镜像,所以我创建了自己的:
FROM debian:bookworm-slim #1
ARG POSTGREST_VERSION=v10.1.1 #2
ARG POSTGREST_FILE=postgrest-$POSTGREST_VERSION-linux-static-x64.tar.xz #2
RUN mkdir postgrest
WORKDIR postgrest
ADD https://github.com/PostgREST/postgrest/releases/download/$POSTGREST_VERSION/$POSTGREST_FILE \
. #3
RUN apt-get update && \
apt-get install -y libpq-dev xz-utils && \
tar xvf $POSTGREST_FILE && \
rm $POSTGREST_FILE #4
- 从最新的 Debian 开始
- 参数化构建
- 获取档案
- 安装依赖项并解压
Docker 镜像文件夹postgrest
中包含一个可执行文件/postgrest
。我们可以通过 Docker Compose 来“部署”该架构:
version: "3"
services:
postgrest:
build: ./postgrest #1
volumes:
- ./postgrest/product.conf:/etc/product.conf:ro #2
ports:
- "3000:3000"
entrypoint: ["/postgrest/postgrest"] #3
command: ["/etc/product.conf"] #4
depends_on:
- postgres
postgres:
image: postgres:15-alpine
environment:
POSTGRES_PASSWORD: "root"
volumes:
- ./postgres:/docker-entrypoint-initdb.d:ro #5
- 构建上述内容
Dockerfile
- 共享配置文件
- 运行
postgrest
可执行文件 - 使用配置文件
- 初始化架构、权限和数据
此时,我们可以查询该product
表:
curl localhost:3000/product
我们立即得到结果:
[{"id":1,"name":"Stickers pack","description":"A pack of rad stickers to display on your laptop or wherever you feel like. Show your love for Apache APISIX","price":0.49,"hero":false},
{"id":2,"name":"Lapel pin","description":"With this \"Powered by Apache APISIX\" lapel pin, support your favorite API Gateway and let everybody know about it.","price":1.49,"hero":false},
{"id":3,"name":"Tee-Shirt","description":"The classic geek product! At a conference, at home, at work, this tee-shirt will be your best friend.","price":9.99,"hero":true}]
这真是一场速胜!
改进解决方案
虽然该解决方案有效,但仍有很大改进空间。例如,数据库用户无法更改数据,但实际上每个人都可以访问。对于产品相关的数据来说,这可能不是什么大问题,但对于医疗数据呢?
PostgREST 文档意识到了这一点,并明确建议使用反向代理:
PostgREST 是构建 RESTful API 的快捷方式。它的默认行为非常适合在开发阶段搭建脚手架。在投入生产时,只要采取预防措施,它也能很好地工作。PostgREST 是一款小巧灵活的工具,专注于执行 API 到数据库的映射。我们依靠 Nginx 这样的反向代理来提供额外的安全保障。
除了 Nginx,我们更需要一个功能齐全的 API 网关:Apache APISIX。我们将把它添加到我们的 Docker Compose 中:
version: "3"
services:
apisix:
image: apache/apisix:2.15.0-alpine #1
volumes:
- ./apisix/config.yml:/usr/local/apisix/conf/config.yaml:ro
ports:
- "9080:9080"
restart: always
depends_on:
- etcd
- postgrest
etcd:
image: bitnami/etcd:3.5.2 #2
environment:
ETCD_ENABLE_V2: "true"
ALLOW_NONE_AUTHENTICATION: "yes"
ETCD_ADVERTISE_CLIENT_URLS: "http://0.0.0.0:2397"
ETCD_LISTEN_CLIENT_URLS: "http://0.0.0.0:2397"
- 使用 Apache APISIX
- APISIX 将其配置存储在etcd中
我们首先要配置 Apache APISIX 来代理以下调用postgrest
:
curl http://apisix:9080/apisix/admin/upstreams/1 -H 'X-API-KEY: 123xyz' -X PUT -d ' #1-2
{
"type": "roundrobin",
"nodes": {
"postgrest:3000": 1 #1-3
}
}'
curl http://apisix:9080/apisix/admin/routes/1 -H 'X-API-KEY: 123xyz' -X PUT -d ' #4
{
"uri": "/*",
"upstream_id": 1
}'
- 应该在某个 Docker 节点上运行,因此请使用 Docker 镜像的名称。或者,使用以下命令,
localhost
但请确保暴露端口 - 创建可重用的上游
- 指向PostgREST节点
- 创建到已创建的上游的路由
我们现在可以通过 APISIX 查询端点:
curl localhost:9080/product
它返回与上面相同的结果。
DDoS 保护
我们还没有添加任何内容,但我们已经准备好开始工作了。首先,让我们保护我们的 API 免受DDoS攻击。Apache APISIX 是围绕插件架构设计的。为了防御 DDoS,我们将使用插件。我们可以在创建特定路由时为其设置插件,也可以在每个路由上设置插件;在后一种情况下,它是一个全局规则。我们希望默认保护每条路由,因此我们将使用一个全局规则。
curl http://apisix:9080/apisix/admin/global_rules/1 -H 'X-API-KEY: 123xyz' -X PUT -d '
{
"plugins": {
"limit-count": { #1
"count": 1, #2
"time_window": 5, #2
"rejected_code": 429 #3
}
}
}'
limit-count
限制时间窗口内的呼叫次数- 每 5 秒限制 1 次调用;这仅用于演示目的
- 返回
429 Too Many Requests
;默认是503
现在,如果我们执行太多请求,Apache APISIX 会保护上游:
curl localhost:9080/product
<html>
<head><title>429 Too Many Requests</title></head>
<body>
<center><h1>429 Too Many Requests</h1></center>
<hr><center>openresty</center>
</body>
</html>
每条路线授权
PostgREST 还在根目录下提供了一个 Open API 端点。因此,我们有两个路由:一个/
用于访问 Open API 规范,另一个/product
用于访问产品。假设我们想要禁止未经授权的人员访问我们的数据:普通用户可以访问产品,而管理员用户可以同时访问 Open API 规范和产品。
APISIX 提供了多种身份验证方法。我们将使用最简单的一种,key-auth。它依赖于Consumer抽象。key-auth
需要一个特定的 header:插件会对 value 进行反向查找,并找到 key 对应的 consumer。
创建消费者的方法如下:
curl http://apisix:9080/apisix/admin/consumers -H 'X-API-KEY: 123xyz' -X PUT -d ' #1
{
"username": "admin", #2
"plugins": {
"key-auth": {
"key": "admin" #3
}
}
}'
- 创建新消费者
- 消费者姓名
- 消费者的关键价值
我们对 consumeruser
和 key执行相同的操作user
。现在,我们可以创建一个专用路由并进行配置,以便只有来自admin
以下地址的请求才能通过:
curl http://apisix:9080/apisix/admin/routes -H 'X-API-KEY: 123xyz' -X POST -d ' #1
{
"uri": "/",
"upstream_id": 1,
"plugins": {
"key-auth": {}, #2
"consumer-restriction": { #2
"whitelist": [ "admin" ] #3
}
}
}'
- 创建新路线
- 使用
key-auth
和consumer-restriction
插件 - 只有
admin
经过身份验证的请求才能调用该路由
让我们尝试以下操作:
curl localhost:9080
它不起作用,因为我们没有通过 API 密钥标头进行身份验证。
{"message":"Missing API key found in request"}
curl -H "apikey: user" localhost:9080
它不起作用,因为我们已通过身份验证user
,但该路线未获得授权,user
而是获得授权admin
。
{"message":"The consumer_name is forbidden."}
curl -H "apikey: admin" localhost:9080
这次,它按预期返回了 Open API 规范。
监控
任何软件系统都有一个被严重低估的功能——监控。一旦将任何组件部署到生产环境中,就必须监控其健康状况。如今,许多服务都可以监控。我们将使用Prometheus,因为它是开源的、久经考验的、应用广泛的。出于同样的原因,我们将使用Grafana来显示数据。让我们将组件添加到 Docker Compose 文件中:
version: "3"
services:
prometheus:
image: prom/prometheus:v2.40.1 #1
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml #2
depends_on:
- apisix
grafana:
image: grafana/grafana:8.5.15 #3
volumes:
- ./grafana/provisioning:/etc/grafana/provisioning #4
- ./grafana/dashboards:/var/lib/grafana/dashboards #4
- ./grafana/config/grafana.ini:/etc/grafana/grafana.ini #4-5
ports:
- "3001:3001"
depends_on:
- prometheus
- 普罗米修斯图像
- Prometheus 配置用于抓取 Apache APISIX 数据。完整文件请见此处
- Grafana 镜像
- Grafana 配置。大部分来自APISIX提供的配置。
- 将默认端口从更改为,
3000
以3001
避免与 PostgREST 服务冲突
一旦监控基础设施到位,我们只需要指示 APISIX 以 Prometheus 期望的格式提供数据。我们可以通过配置和新的全局规则来实现:
plugin_attr:
prometheus:
export_addr:
ip: "0.0.0.0" #1
port: 9091 #2
- 绑定到任意地址
- 绑定到端口
9091
。Prometheus 指标可在http://apisix:9091/apisix/prometheus/metrics
Docker 网络上获取
我们可以创建全局规则:
curl http://apisix:9080/apisix/admin/global_rules/2 -H 'X-API-KEY: 123xyz' -X PUT -d '
{
"plugins": {
"prometheus": {}
}
}'
发送几个查询并打开 Grafana 仪表板。它应该看起来类似于以下内容:
结论
创建一个功能齐全的 REST API 是一项巨大的投资。您可以通过 PostgREST 将数据库暴露在 CRUD API 中,快速测试一个简单的 API。然而,这样的架构并不适合生产环境。
要解决这个问题,您需要在 PostgREST、反向代理或更好的 API 网关前面设置一个外观层。Apache APISIX 提供了从授权到监控的广泛功能。借助它,您可以以低成本快速验证您的 API 需求。
锦上添花的是:当您验证了需求后,您可以保留现有的外观并用您定制开发的 API 替换 PostgREST。
源代码可以在 GitHub 上找到:
进一步来说:
最初于2022 年11 月 20 日发表于A Java Geek
文章来源:https://dev.to/apisix/a-poor-mans-api-533m