关于api设计:译文-A-poor-mans-API

3次阅读

共计 7228 个字符,预计需要花费 19 分钟才能阅读完成。

作者:Nicolas Fränkel
翻译:Sylvia
https://blog.frankel.ch/poor-man-api/

在 API 日渐风行的年代,越来越多的非技术人员也心愿能从 API 的应用中获利,而创立一套成熟的 API 计划须要工夫老本和金钱两方面的资源加持。在这个过程中,你须要思考模型、设计、REST 准则等,而不仅仅是编写一行代码。

如何打造一个具备高性价比且能继续迭代的产品,成为越来越多技术团队的指标。本文将展现如何在不编写任何代码的状况下,简略实现一个 API 实际。

计划初试

该解决方案次要应用的是 PostgreSQL 数据库,PostgreSQL 是一个开源 SQL 数据库。同时咱们没有编写 REST API,而是应用了 PostgREST 组件。

PostgREST 是一个独立的 Web 服务器,它能够将 PostgreSQL 数据库间接转换为 RESTful API。如果你想理解 PostgREST 的应用办法,能够参考入门指南文档,内容十分全面且开箱即用。

接下来,咱们将它利用到一个简略的示例中。

具体步骤

以下过程你能够在 GitHub 上找到残缺源代码。
下方展现了一个通过 CRUD API 公开的 product 表。

因为我没有找到任何现成的 Docker 镜像,所以我独自创立了一份新的 Dockerfile。其中次要波及依赖项的装置和参数化数据生成。

Dockerfile

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 镜像在 /postgrest 文件夹中会蕴含一个名为 postgrest 的可执行文件。这里能够通过 Docker Compose 来部署:

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

接下来能够执行以下命令,查问前文提到的 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 的官网应用文档中提到了这一点,并明确提出:倡议用户应用反向代理。

提到反向代理,就不得不将眼光转向到 API 网关行列。与 NGINX 不同,这里我选取了 开源畛域十分沉闷的 API 网关产品 — Apache APISIX。APISIX 是一个动静、实时、高性能的 API 网关,提供了负载平衡、动静上游、灰度公布、精细化路由、限流限速、服务降级、服务熔断、身份认证、可观测性等数百项性能。

首先,咱们能够在 Docker Compose 文件中补充 APISIX 相干信息,包含 APISIX 及其依赖的存储 etcd,而 etcd 次要用于存储 APISIX 的路由、插件等配置信息。

docker-compose.yml

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"

而后将 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
}

当初再来查问端点,会失去与上文统一的返回后果。

curl localhost:9080/product

添砖加瓦

尽管到目前为止,咱们还没有增加任何理论我的项目,但筹备工作曾经全副就绪了。接下来就让咱们为这个 API 增加一些其余性能,让其更平安无效,易于追踪。

DDoS 爱护

API 作为一个连贯属性的组件,必然要保障其过程中的传输平安。因而,在这里咱们对 API 减少一些防护,让其免受 DDoS 攻打。APISIX 提供了十分多的官网插件,波及鉴权、流量解决、监控等等。为了避免 DDoS,咱们能够应用 APISIX 的 limit-count 插件。

在 APISIX 中应用插件时,你能够在创立特定路由时在每个路由上设置某个插件。如果你想让某个插件在每个路由上都失效,则能够应用全局规定。如下方所示,咱们心愿在默认状况下能够爱护每个路由,所以应用全局规定设定 limit-count 插件。

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}
  }
}'

当初,如果咱们执行太多的申请,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 还在根端提供了一个 OpenAPI endpoint。因而,咱们当初有两条路由:/(管制 Open API 标准)和 /product(管制产品)。

假如咱们当初须要制订一套限度拜访的操作,即不容许未经受权的人拜访数据。普通用户能够拜访产品端信息,而管理员用户能够拜访 Open API 标准和产品端信息。

APISIX 提供了几种身份验证办法,这些身份认证形式都能够通过插件进行实现。这里咱们选取 APISIX 中最罕用也是最简略的认证插件 key-auth,它依赖于 Consumer(消费者)形象。key-auth 插件的应用中须要一个特定的 header,这样插件就能够依据值数据进行反向查找,并找到其对应的 Consumer。

以下代码展现了如何新建一个 Consumer:

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

同样的,咱们须要对 Consumer user 和 Key user   进行相干操作。当初能够创立一个专用路由来配置它们,以便只有来自 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"]                                                  
    }
  }
}'

而后应用以下命令测试一下:

curl localhost:9080

发现并没有起作用。这是因为咱们没有通过 API 密钥的 header 进行身份验证。

{"message":"Missing API key found in request"}

增加 header 后再次进行测试:

curl -H "apikey: user" localhost:9080

{"message":"The consumer_name is forbidden."}

发现依然没有成果。这是因为这里 API key 为 user,咱们前边仅为 admin 也就是管理员设置了相干权限。所以如果更换为 admin,就会如期返回 Open API 标准的相干信息。

配置监控

在软件系统中,总有一个被人们低估重要性的性能 —— 可观测性。在生产环境中部署了任何组件,都须要监控其运行状况。

现在,很多服务都提供了可观测性的性能,比方 Prometheus。得益于 Prometheus 的开源属性,它被广泛应用于实际中。因而,这里咱们也选用 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:3000"
    depends_on:
      - prometheus

以上操作需注意:APISIX 的默认监控计划中自带 Grafana,因而只需从 APISIX 中获取相干配置 即可。同时将默认端口从 3000 更改为 3001 是为了防止与 PostgREST 服务发生冲突。

一旦监控基础设施到位,咱们只须要批示 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": {}
  }
}'

此时发送几个查问申请,并关上 Grafana 仪表板,可看到相似数据。如果运行较多申请,则会呈现更丰盛的数据仪表。

总结

创立一个成熟的 RESTful API 是一项微小的投资。你能够通过 PostgREST 将数据库裸露在 CRUD API 中来疾速测试一个简略的 API。然而,这样的体系结构不适用于理论生产。要想使其更具实践性,就须要在 PostgREST 前设置一个 facade、一个反向代理,或者更好的 API 网关。

Apache APISIX 作为云原生 API 网关,提供了宽泛的个性,从流量解决到认证受权和可观测性等。有了 APISIX,你就能够用较低的老本疾速验证你的 API 需要。精益求精的是,当你验证需要实现之后,还能够保留现有的 facade,并用自定义开发的 API 来替换 PostgREST。

正文完
 0