最小可行产品API的实现 - frankel


不写一行代码的情况下,实现最小可行产品API:无需编写 REST API代码,而是配置使用 PostgREST 组件。
PostgREST 是一个独立的 Web 服务器,可将您的 PostgreSQL 数据库直接转换为 RESTful API。数据库中的结构约束和权限决定了 API 端点和操作。

让我们将它应用到一个简单的用例中:
可以在GitHub 上找到完整的源代码

PostgREST 的入门指南非常完整并且开箱即用。然而,我没有找到任何现成的 Docker 镜像,所以我创建了自己的:

FROM debian:bookworm-slim                                                   

ARG POSTGREST_VERSION=v10.1.1                                               
ARG POSTGREST_FILE=postgrest-$POSTGREST_VERSION-linux-static-x64.tar.xz     

RUN mkdir postgrest

WORKDIR postgrest

ADD https://github.com/PostgREST/postgrest/releases/download/$POSTGREST_VERSION/$POSTGREST_FILE \
    .                                                                       

RUN apt-get update && \
    apt-get install -y libpq-dev xz-utils && \
    tar xvf $POSTGREST_FILE && \
    rm $POSTGREST_FILE                  

docker-compose.yml

version: "3"
services:
  postgrest:
    build: ./postgrest                                   
    volumes:
      - ./postgrest/product.conf:/etc/product.conf:ro    
    ports:
      - "3000:3000"
    entrypoint: ["/postgrest/postgrest"]                 
    command: ["/etc/product.conf"]                       
    depends_on:
      - postgres
  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_PASSWORD: "root"
    volumes:
      - ./postgres:/docker-entrypoint-initdb.d:ro 

查询数据表:

curl localhost:3000/product

增加修改功能
PostgREST 是构建 RESTful API 的快速方法。它的默认行为非常适合开发中的脚手架。当需要投入生产时,只要您采取预防措施,它也能很好地工作。PostgREST 是一个小巧的利器,专注于执行 API 到数据库的映射。我们依靠像 Nginx 这样的反向代理来提供额外的保护。

Apache APISIX替代nginx,我们将把它添加到我们的 Docker Compose 中:

version: "3"
services:
  apisix:
    image: apache/apisix:2.15.0-alpine                              
    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                                       
    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来代理对postgrest的调用:

curl http://apisix:9080/apisix/admin/upstreams/1 -H 'X-API-KEY: 123xyz' -X PUT -d '  
{
  "type": "roundrobin",
  "nodes": {
    "postgrest:3000": 1                                                              
  }
}'

curl http://apisix:9080/apisix/admin/routes/1 -H 'X-API-KEY: 123xyz' -X PUT -d '    
{
  "uri": "/*",
  "upstream_id": 1
}'

我们现在可以通过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": {                 
      "count": 1,                    
      "time_window": 5,              
      "rejected_code": 429           
    }
  }
}'

  • limit-count限制在一个时间窗口中的呼叫次数
  • 限制为每5秒1次呼叫;这是为了演示目的
  • 返回429太多请求;默认是503

每条路由的授权
PostgREST还在根部提供了一个Open API端点。因此,我们有两个路由。/用于开放API规范,
/product用于产品。假设我们想禁止未经授权的人访问我们的数据。普通用户可以访问产品,而管理用户可以同时访问Open API规格和产品。

APISIX提供了几种认证方法。我们将使用最简单的一种,即密钥认证。key-auth需要一个特定的头:该插件对该值进行反向查找,并找到其Key对应的消费者。

curl http://apisix:9080/apisix/admin/consumers -H 'X-API-KEY: 123xyz' -X PUT -d '    
{
  "username": "admin",                                                               
  "plugins": {
    "key-auth": {
      "key": "admin"                                                                 
    }
  }
}'

  • 创建一个新的消费者
  • 消费者的名字
  • 消费者的键值

我们对消费者用户和关键用户做同样的工作。现在,我们可以创建一个专门的路由,并对其进行配置,以便只有来自管理员的请求可以通过。

curl http://apisix:9080/apisix/admin/routes -H 'X-API-KEY: 123xyz' -X POST -d ' 
{
  "uri": "/",
  "upstream_id": 1,
  "plugins": {
    "key-auth": {},                                                             
    "consumer-restriction": {                                                   
      "whitelist": [ "admin" ]                                                  
    }
  }
}'

  • 创建新路由
  • 使用key验证和使用者限制插件
  • 只有经过管理员身份验证的请求才能调用路由

调用:

curl -H "apikey: admin" localhost:9080

监控
任何软件系统的一个被低估的功能就是监控。一旦你在生产中部署了任何组件,你就必须监测其健康状况。现在,有许多服务可以用来监控。我们将使用Prometheus,因为它是开源的、经过实战检验的、广泛的。为了显示数据,我们将依靠Grafana,原因也是如此。让我们把这些组件添加到Docker Compose文件中。

docker-compose.yml

version: "3"
services:
  prometheus:
    image: prom/prometheus:v2.40.1                                    
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml    
    depends_on:
      - apisix
  grafana:
    image: grafana/grafana:8.5.15                                     
    volumes:
      - ./grafana/provisioning:/etc/grafana/provisioning              
      - ./grafana/dashboards:/var/lib/grafana/dashboards              
      - ./grafana/config/grafana.ini:/etc/grafana/grafana.ini          
    ports:
      - "3001:3001"
    depends_on:
      - prometheus


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

plugin_attr:
  prometheus:
    export_addr:
      ip: "0.0.0.0"             
      port: 9091     

我们可以创建全局规则:

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

结论
创建一个成熟的REST(ful)API是一项巨大的投资。人们可以通过PostgREST的CRUD API来快速测试一个简单的API,暴露自己的数据库。然而,这样的架构并不适合在生产中使用。

为了解决这个问题,你需要在PostgREST前面设置一个façade,一个反向代理,或者更好的是一个API网关。Apache APISIX提供了广泛的功能,从授权到监控。有了它,你可以以较低的成本快速验证你的API需求。

锦上添花的是:当你验证了需求后,你可以保留现有的立面,用你定制开发的API取代PostgREST。