# RESTful API

## 参考

[服务端指南 | 良好的 API 设计指南 - 掘金](https://juejin.im/post/59826a4e518825359c5e72d1) [RESTful 架构详解 | 菜鸟教程](https://www.runoob.com/w3cnote/restful-architecture.html) [RESTful API 最佳实践 - 阮一峰的网络日志](http://www.ruanyifeng.com/blog/2018/10/restful-api-best-practices.html) [RESTful API浅谈 - 老\_张 - 博客园](https://www.cnblogs.com/imyalost/p/7923230.html)

## 概述

### 资源与URI

动词 http method+ 名词uri

```
【GET】          /users                # 查询用户信息列表
【GET】          /users/1001           # 查看某个用户信息
【POST】         /users                # 新建用户信息
【PUT】          /users/1001           # 更新用户信息(全部字段)
【PATCH】        /users/1001           # 更新用户信息(部分字段)
【DELETE】       /users/1001           # 删除用户信息
```

避免多级url，而是采用过滤条件

```
GET /authors/12/categories/2
应该换成
GET /authors/12?categories=2
```

> 使用\_或-来让URI可读性更好 使用/来表示资源的层级关系 使用?用来过滤资源 ,或;可以用来表示同级资源的关系

**动词的覆盖** 有些客户端无法支持PUT、DELETE等方法，这种情况必须使用POT来模拟， 客户端可以在发出的HTTP请求中，加上`X-HTTP-Method-Override`属性，告诉服务器使用哪一个动词

```http
POST /api/Person/4 HTTP/1.1  
X-HTTP-Method-Override: PUT
```

#### 版本

api接口升级时，为了去兼容一些暂时无法升级的客户端（比如移动端的app是运行在客户设备上，不像服务器上的客户端可以直接升级），需要保留旧版本接口。 为了解决版本兼容问题，在RESTful API中使用了版本号，常见的情况下在url使用版本号，也可以在header中使用版本号，不过一般都在url中，这样更直观。

```http
【GET】  /v1/users/{user_id}  // 版本 v1 的查询用户列表的 API 接口
【GET】  /v2/users/{user_id}  // 版本 v2 的查询用户列表的 API 接口
```

#### 提供链接

为了方便api使用者，让资源之间具有连通性（超媒体），在响应体中，返回其他资源的url

例如，GitHub 的 API 都在 <https://api.github.com/> 这个域名。访问它，就可以得到其他 URL。

```javascript
{
  ...
  "feeds_url": "https://api.github.com/feeds",
  "followers_url": "https://api.github.com/user/followers",
  "following_url": "https://api.github.com/user/following{/target}",
  "gists_url": "https://api.github.com/gists{/gist_id}",
  "hub_url": "https://api.github.com/hub",
  ...
}
```

在返回头中返回link

```bash
url -I https://api.github.com/orgs/github/repos
HTTP/1.1 200 OK

ETag: "c4f394acb6f2603b159ee8d694d308cb"
X-GitHub-Media-Type: github.v3; format=json
Link: <https://api.github.com/organizations/9919/repos?page=2>; rel="next", <https://api.github.com/organizations/9919/repos?page=10>; rel="last"
```

### 状态码

应该尽量在http状态码中表述错误状态，而不是统一使用200，统一200的方式实际上几近取消了状态码

```http
HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "error": "Invalid payoad.",
  "detail": {
     "surname": "This field is required."
  }
}
```

## 附加

### 常用状态码

**GET** 安全且幂等 获取表示 变更时获取表示（缓存） 200（OK） - 表示已在响应中发出 204（无内容） - 资源有空表示 301（Moved Permanently） - 资源的URI已被更新 303（See Other） - 其他（如，负载均衡） 304（not modified）- 资源未更改（缓存） 400 （bad request）- 指代坏请求（如，参数错误） 404 （not found）- 资源不存在 406 （not acceptable）- 服务端不支持所需表示 500 （internal server error）- 通用错误响应 503 （Service Unavailable）- 服务端当前无法处理请求

**POST** 不安全且不幂等 使用服务端管理的（自动产生）的实例号创建资源 创建子资源 部分更新资源 如果没有被修改，则不过更新资源（乐观锁） 200（OK）- 如果现有资源已被更改 201（created）- 如果新资源被创建 202（accepted）- 已接受处理请求但尚未完成（异步处理） 301（Moved Permanently）- 资源的URI被更新 303（See Other）- 其他（如，负载均衡） 400（bad request）- 指代坏请求 404 （not found）- 资源不存在 406 （not acceptable）- 服务端不支持所需表示 409 （conflict）- 通用冲突 412 （Precondition Failed）- 前置条件失败（如执行条件更新时的冲突） 415 （unsupported media type）- 接受到的表示不受支持 500 （internal server error）- 通用错误响应 503 （Service Unavailable）- 服务当前无法处理请求

**PUT** 不安全但幂等 用客户端管理的实例号创建一个资源 通过替换的方式更新资源 如果未被修改，则更新资源（乐观锁） 200 （OK）- 如果已存在资源被更改 201 （created）- 如果新资源被创建 301（Moved Permanently）- 资源的URI已更改 303 （See Other）- 其他（如，负载均衡） 400 （bad request）- 指代坏请求 404 （not found）- 资源不存在 406 （not acceptable）- 服务端不支持所需表示 409 （conflict）- 通用冲突 412 （Precondition Failed）- 前置条件失败（如执行条件更新时的冲突） 415 （unsupported media type）- 接受到的表示不受支持 500 （internal server error）- 通用错误响应 503 （Service Unavailable）- 服务当前无法处理请求

**DELETE** 不安全但幂等 删除资源 200 （OK）- 资源已被删除 301 （Moved Permanently）- 资源的URI已更改 303 （See Other）- 其他，如负载均衡 400 （bad request）- 指代坏请求 404 （not found）- 资源不存在 409 （conflict）- 通用冲突 500 （internal server error）- 通用错误响应 503 （Service Unavailable）- 服务端当前无法处理请求


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://book.rizon.top/zhuan-ti/restfulapi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
