接上篇

HTTP-API-DESIGN 怎样设计一个合理的 HTTP API (一)

整个 ppt 可以去这里下载。

这一篇主要从服务端应该如何返回合理的返回值的角度,讨论如何设计一个合理的 HTTP-API;

主要有以下几个方面:

  • 为每个资源,分配一个 Resource ID(UUID)
  • 使用统一的时间戳
  • 正确地使用外键
  • 将错误响应信息标准化
  • 对客户端进行流量控制
  • 将发返回的 JSON “最小化”

为每个资源,分配一个 Resource ID(UUID)

返回的结果中,需要为每一个“资源”(用户、消息、评论、私信等等)分配一个唯一的 ID(UUID)。 推荐使用 “8-4-4-4-12” 格式的 UUID,一定不要使用数字,尤其是自增 ID。

避免使用自增 ID 主要从以下几个方面考虑:

  • 数字 ID 会暴露总体用户量
  • 数字 ID 会使数据抓取变得更容易
  • 数字 ID 会有溢出的潜在风险
  • 数字 ID 会(不自觉地)使你的代码和 DB 耦合

使用统一的时间戳

继续“资源” 的话题,当我们创建、修改资源时,都需要记录下操作对应的时间。应该在 DB 中,为每一个资源,提供“created_at”', “updated_at”' 信息; 存储、传输时间信息时,应该使用 “ISO8601”格式化过的 “UTC”'(only), 不应该使用其他格式存储时间。

有些人(比如我)更喜欢用unix 时间戳,其实这些习惯,更多的出于对 datetime 库的不熟悉导致的。使用 UTC 的优点还是很多的:

  • 为什么不使用 UNIX 时间戳? 不可读,不方便
  • 除了这点呢?后台调试不方便(sql select)
  • 会有性能问题吗?不会大到影响你的程序
  • 我不会用? 找对应语言的 lib

正确使用外键

在 API 返回的结果中,如果某个结果中涉及到了其他“资源”,应该独立标识出它的外键。

比如这样:

    {
      "name": "service-production",
      "owner": {
        "id": "5d8201b0-xxx"
      }
    }

下面的方式是错误的:

    {
      "name": "service-production",
      "owner_id": "5d8201b0-xxx"
    }

上面两种方式有什么区别呢? 假设有一天,由于业务需要,你想在结果中,增加一些额外的信息,独立外键的方式,可以很清晰地、不影响原有结果格式地完成任务:

    {
      "name": "service-production",
      "owner": {
        "id": "5d8201b0...",
        "name": "Alice",
        "email": "alice@heroku.com"
      }
    }

而非独立外键,要么需要增加好多不明的key;要么需要修改原有的数据格式。

将错误响应信息标准化

当某次请求出现错我的时候,需要同时在 header、body 中附上必要的信息,方便API 的调用者清楚问题在哪里。

一般在 header中,返回 resource uri; 在 body 中,要明确标识出错误的 id、提示信息以及请求的 url。

    {
      "id":      "rate_limit",
      "message": "Account reached its API rate limit.",
      "url":     "https://docs.service.com/rate-limits"
    }

流量控制

随着用户逐渐增多,一定会出现,客户端请求量变大导致服务器无法响应的情形,此时维护服务的稳定,就变成了服务端、客户端共同的责任。需要约定一套机制,让客户端能够感知到服务端目前的状况,合理安排自身逻辑。 一个合理的解决方案是:利用“RateLimit-Remaining”。

服务端返回“RateLimit-Remaining” 相关信息,客户端根据“RateLimit-Remaining” 的结果,来延长或缩短某些请求的间隔。

Keep JSON minified

为了流量考虑,应该将生成的JSON,剔除空格、换行后返回给客户端。

比如这样:

{"beta":false,"email":"alice@heroku.com","id":"01234567-89ab-cdef-0123-456789abcdef","last_login":"2012-01-01T12:00:00Z","created_at":"2012-01-01T
12:00:00Z","updated_at":"2012-01-01T12:00:00Z"}

那怎么调试呢?可以参考 elastic_search 的实现,让 server 支持一个 pretty 参数,如果在 url 中增加“ pretty=true”, 那么返回的 json 结果将是格式化好、便于阅读的格式。

总结

流水帐似的写了这么多,总结一下吧。

简略地说,作为一个 API 的 Server 端,应该做到:

  • 负责人需要 “头脑清醒考虑之”
  • 撰写清晰的文档,并且需要与服务保持更新
  • 自己负责测试(将测试代码一并提交)
  • 提供良好的联调环境
  • 使用Resource-ID、Status Code、Rate Limit、pretty 等方式方便调试
  • 代码要做到 “宽入严出”

为一个 API 的使用者,应该做到:

  • 读文档,读文档,读文档
  • 先读文档,再找 Server RD
  • 文档中存疑的部分,拒绝猜测的诱惑
  • 按照文档的描述,而不是自己的经验来调用 API
  • 正确地处理各种服务端的异常 case
  • 代码要做到 “宽入严出”

HTTP-API-DESIGN 怎样设计一个合理的 HTTP API (二)的更多相关文章

  1. 使用MATLAB 2019 App Design 工具设计一个 电子日记App

    使用MATLAB 2019 App Design 工具设计一个 电子日记App1.1 前言:由于信号与系统课程需要,因此下载了MATLAB软件,加之对新款的执着追求,通过一些渠道,下载了MATLAB ...

  2. 如何设计一个亿级网关(API Gateway)?

    1.背景 1.1 什么是API网关 API网关可以看做系统与外界联通的入口,我们可以在网关进行处理一些非业务逻辑的逻辑,比如权限验证,监控,缓存,请求路由等等. 1.2 为什么需要API网关 RPC协 ...

  3. 如何设计一个牛逼的API接口

    在日常开发中,总会接触到各种接口.前后端数据传输接口,第三方业务平台接口.一个平台的前后端数据传输接口一般都会在内网环境下通信,而且会使用安全框架,所以安全性可以得到很好的保护.这篇文章重点讨论一下提 ...

  4. 设计一个高质量的API接口

    参考网址:http://url.cn/5UaTeyv 前言 在设计接口时,有很多因素要考虑,如接口的业务定位,接口的安全性,接口的可扩展性.接口的稳定性.接口的跨域性.接口的协议规则.接口的路径规则. ...

  5. HTTP-API-DESIGN 怎样设计一个合理的 HTTP API (一)

    这个附件的幻灯片是我最近给团队分享关于设计 HTTP API 的时候,结合 这篇 和我们团队历史上的一些错误,总结出来一些适合内部的经验. 简介. 这次分享主要关注以下几部分: HTTP + JSON ...

  6. 如何设计一个restful风格的API

    1.API接口应该尽量兼容之前的版本,在URL上应保留版本号,并同时兼容多个版本 2.每一个URI代表一个资源 3.请求方式要与http请求方式一致,GET(获取),POST(新增),PUT(更新全部 ...

  7. 如何一步一步用DDD设计一个电商网站(二)—— 项目架构

    阅读目录 前言 六边形架构 终于开始建项目了 DDD中的3个臭皮匠 CQRS(Command Query Responsibility Segregation) 结语 一.前言 上一篇我们讲了DDD的 ...

  8. 如何设计一个优秀的API

    如何设计一个优秀的API - 文章 - 伯乐在线 http://blog.jobbole.com/42317/ 如何设计一个优秀的API - 标点符 https://www.biaodianfu.co ...

  9. 如何设计一个良好的API接口?

    沟通创造价值,分享带来快乐.这里是程序员阅读时间,每天和你分享读书心得,欢迎您每天和我一起精进.今天和大家一起讨论的话题是如何设计一个良好的API接口? 作者:梁桂钊 解读:张飞洪 挑战 API是软件 ...

随机推荐

  1. 多线程入门-第七章-线程的同步Synchronized

    /* 异步编程模型:两个线程执行自己的,互不影响. 同步编程模型:t1和t2执行,t2必须等t1执行结束之后才能执行. 为什么要线程同步? 1.为了数据的安全,尽管应用程序的使用率降低,但是为了保证数 ...

  2. 用于金融分析的Python包

    1. NumPy:实现各种数组对象函数和傅立叶变换等等科学计算模块.2. SciPy:提供更多科学计算功能,包括矩阵,求解线性方程组,积分运算,优化等.3. matplotlib:一个跨平台的数值绘图 ...

  3. 如何删除Docker中的镜像相关

    1.正常情况下 1.停止所有的container,这样才能够删除其中的images: docker stop $(docker ps -a -q) 如果想要删除所有container的话再加一个指令: ...

  4. 深入浅出java IO模型

    一.同步和异步 同步:一个事件或者任务的执行,会使整个流程暂时等待,也就是说如果有多个任务要执行,必须要逐个进行. 异步:一个事件或者任务的执行,不会使整个流程暂时等待,也就是说如果有多个任务要执行, ...

  5. nodejs 视频教程《一起学nodejs》

    一起学nodejs 讲师:   matthew vscode+nodejs4.6 http://list.youku.com/albumlist/show/id_27966955.html?spm=a ...

  6. Linux下多个.c文件的编译和Makefile文件

    在编程的时候,我们可以把一个完整程序的每个函数分离出来,写成.c文件,最后再一起编译和链接.这样有利于程序功能模块化,也方便检查代码错误. .h文件:里面编辑该程序需要引用的头文件. #ifndef  ...

  7. JS片段大总结

    html中的标签都可以加一个id的属性. <body> <div id="tree" data-leaves="47" data-plant- ...

  8. 随机深林和GBDT

    随机森林(Random Forest): 随机森林是一个最近比较火的算法,它有很多的优点: 在数据集上表现良好 在当前的很多数据集上,相对其他算法有着很大的优势 它能够处理很高维度(feature很多 ...

  9. The Jordan 3lab5 is the perfect sneaker for you

    The Jordan 5 3Lab5 Metallic Silver returns inside a mind-turning new iteration for that Spring/Summe ...

  10. iClap分享:如何优雅的在 APP 中实现测试?

    开发团队常面临的问题有:内测 APP 时测出一堆 bug 写了很多文档,交到下一个人手中时问题总是不够清晰明了;版本发布公测时只能分发原生版本给团队和用户,无法快速反馈测试和体验结果;使用第三方工具, ...