目前我已经写了一年多 graphql,也时常思考和 Rest API 的不一样,以及对 API Design 的启发。javascript
他山之石能够攻玉。qraphql 一些自然的设计或者思想对写 Rest API 有很大的借鉴或参考意义。html
这里总结下一些受启发的 API 设计规范。前端
若是你对 graphql 不熟悉,能够先参考 graphql 中文文档java
本文连接 shanyue.tech/post/api-de…node
在 graphql 中,scalar 类型 ID
用来表示资源的全局惟一性。在 apollo-client
中也建议客户端每次请求都把 id 带上。git
在响应中带上 id 至少有两个好处github
query TODO {
todo (id: 10) {
id
name
status
}
}
复制代码
如客户端只须要显示某个 TODO 的状态以及名称,则只须要返回 name 以及 status 字段,大大减小了网络的流量。数据库
另外, graphql server 须要在数据库层面也对字段作按需加载。不然,graphql server 与 database 之间也会形成无用的数据 IO 与流量浪费。json
获取 graphql query 所请求的字段,须要手动解析 GraphQLFieldResolveFn 函数的第四个字段 info,并在每个 field 上自定义一个 directive 标注 Graphql Filed 与 Database Field 的关系后端
在 Rest API 中可使用额外字段作按需加载。 如使用 fields 标记返回须要的字段,若无此字段,默认返回资源的所有字段,在中间件中对 fields 作结构化处理
// 请求 Todo:10,而且只须要 id,name,status 三个字符安
'/api/todos/10?fields=id,name,status'
// 请求 Todo:10 所有资源
'/api/todos/10'
复制代码
这个请求表示一个用户列表,每一个用户须要展现最后一个 Todo 的名称。Todo 须要使用嵌套对象来表示。
query USERS {
users {
id
name
lastTodo {
id
name
}
}
}
复制代码
在 Rest API 设计中常常见到全部数据进行了展开,不只没法定位资源,也很差扩展数据。嵌套数据能够很灵活的扩展数据,另外也能够对嵌套数据进行按需加载
const res0 = {
users: [{
id: 1,
name: "山月",
todoName: "学习"
}]
}
// 修改后
const todoFields = {}
const res = {
users: [{
id: 1,
name: "山月",
todo: {
id: 1,
name: "学习",
...fields
}
}]
}
// 能够这样设计 API
const api = '/api/users?fields=id,name,todo.id,todo.name'
复制代码
在 graphql 中,虽没有一个 scalar 类型来表示时间戳,不过能够自定义 scalar DateTime 来表示时间。关于时间的格式
参考 StackOverflow 上的问题 the-right-json-date-format
const date = new Date()
// 从 toJSON 的输出就知道先后端交互须要使用什么格式了
date.toJSON()
// 2019-03-14T07:41:08.500Z
date.toISOString()
// 2019-03-14T07:41:08.500Z
复制代码
这样返回的格式不只符合规范,并且可读性也比较好。
我见过API中返回的时间戳表示为 unix timestamp,js timestamp, iso8601 三种格式,较为混乱。统一的数据格式有利于先后端的联调,不过这也得益于 graphql 的强类型 schema。
在 graphql 中会返回 { data, errors }
的数据结构,能够在最后结构化错误信息为
{
"code": "InvalidToken",
"message": "Token 失效",
"httpStatus": 401
}
复制代码
message
为可读性的错误信息,能够由前端直接显示,code
为调试用,httpStatus
由下一步的中间件捕捉,设置状态码。
在结构化错误信息后,能够顺带把错误信息发送到报警系统 (如 Sentry)。不过须要分清 WARN 与 ERROR,如 401,403 应当作 WARN 处理。
恩,好吧。graphql 这条有缺陷。graphql 的 Query
与 Mutation
都是使用 POST
请求。对不一样的执行成功的 Mutation
返回不一样的 200,201,202 仍是比较麻烦。
不过对于错误返回不一样的状态码, 打开 devtool 一眼能够看到红色的 4XX 信息,也对快速定位错误请求有帮助,稍微减小了些烦躁心。
介绍几种常见的4xx状态码
关于400参考 400 BAD request HTTP error code meaning? 这里有一篇文章,关于4xx状态码的选择,取一张图出来
因为 graphql 的强类型 schema,也省了数据输入输出的校验。
对于 Rest API,可使用 JSON Schema 来校验数据格式。node 也可使用 joi 作数据校验。
这里放一份 JSON Schema 的文档:json-schema.org/
得益于 graphql 的 introspection 与强类型的 schema。graphql 能够根据源码以及注释自动生成文档,直接使用 graphiql 或者 graphql playground 上查看。
若是你使用 node.js 来写服务器应用,可使用 apiDoc
另外,注意不要把文档暴露到生产环境,graphql 须要在生产环境中关掉 introspection。