穷人的 API

2025-06-04

穷人的 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
Enter fullscreen mode Exit fullscreen mode
  1. 从最新的 Debian 开始
  2. 参数化构建
  3. 获取档案
  4. 安装依赖项并解压

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
Enter fullscreen mode Exit fullscreen mode
  1. 构建上述内容Dockerfile
  2. 共享配置文件
  3. 运行postgrest可执行文件
  4. 使用配置文件
  5. 初始化架构、权限和数据

此时,我们可以查询该product表:

curl localhost:3000/product
Enter fullscreen mode Exit fullscreen mode

我们立即得到结果:

[{"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}]
Enter fullscreen mode Exit fullscreen mode

这真是一场速胜!

改进解决方案

虽然该解决方案有效,但仍有很大改进空间。例如,数据库用户无法更改数据,但实际上每个人都可以访问。对于产品相关的数据来说,这可能不是什么大问题,但对于医疗数据呢?

PostgREST 文档意识到了这一点,并明确建议使用反向代理:

PostgREST 是构建 RESTful API 的快捷方式。它的默认行为非常适合在开发阶段搭建脚手架。在投入生产时,只要采取预防措施,它也能很好地工作。PostgREST 是一款小巧灵活的工具,专注于执行 API 到数据库的映射。我们依靠 Nginx 这样的反向代理来提供额外的安全保障。

--强化 PostgREST

除了 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"
Enter fullscreen mode Exit fullscreen mode
  1. 使用 Apache APISIX
  2. 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
}'
Enter fullscreen mode Exit fullscreen mode
  1. 应该在某个 Docker 节点上运行,因此请使用 Docker 镜像的名称。或者,使用以下命令,localhost但请确保暴露端口
  2. 创建可重用的上游
  3. 指向PostgREST节点
  4. 创建到已创建的上游的路由

我们现在可以通过 APISIX 查询端点:

curl localhost:9080/product
Enter fullscreen mode Exit fullscreen mode

它返回与上面相同的结果。

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
    }
  }
}'
Enter fullscreen mode Exit fullscreen mode
  1. limit-count限制时间窗口内的呼叫次数
  2. 每 5 秒限制 1 次调用;这仅用于演示目的
  3. 返回429 Too Many Requests;默认是503

现在,如果我们执行太多请求,Apache APISIX 会保护上游:

curl localhost:9080/product
Enter fullscreen mode Exit fullscreen mode
<html>
<head><title>429 Too Many Requests</title></head>
<body>
<center><h1>429 Too Many Requests</h1></center>
<hr><center>openresty</center>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

每条路线授权

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
    }
  }
}'
Enter fullscreen mode Exit fullscreen mode
  1. 创建新消费者
  2. 消费者姓名
  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
    }
  }
}'
Enter fullscreen mode Exit fullscreen mode
  1. 创建新路线
  2. 使用key-authconsumer-restriction插件
  3. 只有admin经过身份验证的请求才能调用该路由

让我们尝试以下操作:

curl localhost:9080
Enter fullscreen mode Exit fullscreen mode

它不起作用,因为我们没有通过 API 密钥标头进行身份验证。

{"message":"Missing API key found in request"}
Enter fullscreen mode Exit fullscreen mode
curl -H "apikey: user" localhost:9080
Enter fullscreen mode Exit fullscreen mode

它不起作用,因为我们已通过身份验证user,但该路线未获得授权,user而是获得授权admin

{"message":"The consumer_name is forbidden."}
Enter fullscreen mode Exit fullscreen mode
curl -H "apikey: admin" localhost:9080
Enter fullscreen mode Exit fullscreen mode

这次,它按预期返回了 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
Enter fullscreen mode Exit fullscreen mode
  1. 普罗米修斯图像
  2. Prometheus 配置用于抓取 Apache APISIX 数据。完整文件请见此处
  3. Grafana 镜像
  4. Grafana 配置。大部分来自APISIX提供的配置。
  5. 将默认端口从更改为,30003001避免与 PostgREST 服务冲突

一旦监控基础设施到位,我们只需要指示 APISIX 以 Prometheus 期望的格式提供数据。我们可以通过配置和新的全局规则来实现:

plugin_attr:
  prometheus:
    export_addr:
      ip: "0.0.0.0"             #1
      port: 9091                #2
Enter fullscreen mode Exit fullscreen mode
  1. 绑定到任意地址
  2. 绑定到端口9091。Prometheus 指标可在http://apisix:9091/apisix/prometheus/metricsDocker 网络上获取

我们可以创建全局规则:

curl http://apisix:9080/apisix/admin/global_rules/2 -H 'X-API-KEY: 123xyz' -X PUT -d '
{
  "plugins": {
    "prometheus": {}
  }
}'
Enter fullscreen mode Exit fullscreen mode

发送几个查询并打开 Grafana 仪表板。它应该看起来类似于以下内容:

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
PREV
使用 API 管理和计费提供商实现 API 货币化
NEXT
如何以 10 倍更快的速度构建前端应用程序!