接上篇

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. LeetCode—Unique Paths

    题目: A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). ...

  2. LeetCode题目_Reverse Integer

    最近在LeetCode上做题,写点东西记录一下,虽然自己做的都是些很水的题目,但是重在练手. 题号7:Reverse Integer,题目描述: Reverse digits of an intege ...

  3. 【opencv】cv::Mat_ 对单个元素赋值

    创建一个cv::Mat_并赋值 cv::Mat_<,); mat(,)=VIRTUAL_FOCAL; mat(,)=; mat(,)=roiSize_x/; mat(,)=; mat(,)=VI ...

  4. 浅析Linux中的进程调度

    2016-11-22 前面在看软中断的时候,牵扯到不少进程调度的知识,这方面自己确实一直不怎么了解,就趁这个机会好好学习下. 现代的操作系统都是多任务的操作系统,尽管随着科技的发展,硬件的处理器核心越 ...

  5. tornado调用ioloop TracebackFuture实现非堵塞的模块

    转载http://xiaorui.cc/2014/11/26/tornado调用ioloop-tracebackfuture实现非堵塞的模块/ 当然实现的方法,还是存在点问题的, 但是最少流程是跑通了 ...

  6. yii2引入js和css

    assets/AppAsset.php public $css = [ 'css/site.css', 'css/font/css/font-awesome.min.css', 'css/doc.cs ...

  7. 漫谈DOM 事件流的三个阶段

    一丶 流 什么是流? 比如 react 中的单项数据流,Node.js 中的流,或者本文中的 DOM 事件流,都是流的具体体现.专业地讲,流是程序输入或输出的一个连续的字节序列:通俗地讲,流是有方向的 ...

  8. 264. Ugly Number II(丑数 剑指offer 34)

    Write a program to find the n-th ugly number. Ugly numbers are positive numbers whose prime factors ...

  9. Python3 计算城市距离

    利用上一篇得到的城市经纬度算城市距离 import requests from math import radians, cos, sin, asin, sqrt def geocode(addres ...

  10. IDEA创建Spring Boot的项目

    IDEA创建SpringBoot的项目非常的方便智能,可以实现零配置,只需要在创建的时候勾选你需要的功能,比如mybatis,mysql等等,它会帮你自动下载导入响应的jar,不用自己再去手动填写. ...