# Web端前后端分离接口设计规范

######版本号：V0.0.1

## 基本规范

参考链接：[RESTful API 最佳实践](http://www.ruanyifeng.com/blog/2018/10/restful-api-best-practices.html)

* 统一使用RESTful风格的接口请求方式，前端需要模拟除`GET`，`POST`以外的请求:
  - `GET`：读取请求，如列表，详情接口
  - `POST`：创建请求，如新增一条数据
  - `PUT`：更新（Update），通常更新整个实体
  - `PATCH`：部分更新
  - `DELETE`：删除
* URI统一使用资源实体的方式定义，资源实体统一定为英文单词的复数形式，筛选参数使用查询字段，以用户(User)实体为例
  - `GET /users`：读取用户列表
  - `GET /users?page=1&size=10`：分页读取用户列表（第1页，每页10条数据）
  - `GET /users/1`：读取id为1的用户详情
  - `GET /users?source=wechat`：读取来自微信的用户
  - `POST /users`: 创建用户
  - `PATCH /users/1`:更新id为1的用户信息
  - `DELETE /users/1`：删除id为1的用户信息
  - `GET /users/1/followers`：读取id为1的用户的粉丝列表
* 统一重写HTTP状态码标识请求状态成功或失败，返回数据里不再有字段表示成功或失败，也不再有字段标识错误代码，前端需要遵循ES6规范，构建Promise对象进行ajax请求，ES6 Promise对象实现示例如下：

```Javascript
var getJSON = function(url) {
  var promise = new Promise(function(resolve, reject){
    var client = new XMLHttpRequest();
    client.open("GET", url);
    client.onreadystatechange = handler;
    client.responseType = "json";
    client.setRequestHeader("Accept", "application/json");
    client.send();

    function handler() {
      if (this.readyState !== 4) {
        return;
      }
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
  });

  return promise;
};

getJSON("http://rap.taobao.org/mockjs/9768/Rap/get").then(function(response) {
  console.log('Contents: ',response);
}, function(error) {
  console.error('出错了', error);
});
```

- 2XX均表示请求成功：

  - `GET`：200，成功
  - `POST`：201，创建成功
  - `PUT`：200，成功
  - `PATCH`：200，成功
  - `DELETE`：200，已删除
  - 异步处理：202，服务器已接收到请求，处于待处理状态（如异步操作）。

- 3XX表示重定向：在前后端分离时由前端控制是否跳转

  - `301`：永久重定向，浏览器直接跳转

  - `302`、`307`：暂时重定向，浏览器直接跳转

  - `303`：暂时重定向，指定跳转URL，前端询问用户是否跳转，如

    ```
      HTTP/1.1 303 See Other
      Location: /users/1
    ```

- 4XX状态码，表示前端错误

  - `400 Bad Request`:无效请求，服务器不理解前端请求
  - `401 Unauthorized`：用户没有提供身份凭证凭据或没有通过身份验证（如未登录，登录信息失效）
  - `403 Forbidden`：用户通过了验证，但是不具有访问资源所需的权限（功能权限或数据权限）
  - `404 Not Found`：请求资源不存在或不可用（如已删除资源）
  - `405 Method Not Allowed`：用户已通过验证，但是所用的HTTP方法不符合要求（如GET方法使用POST请求）
  - `410 Gone`：资源已从该地址转移，不再可用（如文件转移）
  - `415 Unsupported Media Type`：客户端要求的返回格式不支持，如只能返回JSON格式，客户端要求返回XML格式。
  - `422 Unprocessed Entity`：客户端上传的实体无法处理（如数据不完整，数据校验不通过），导致请求失败。
  - `429 Too Many Requests`：客户端请求的次数超过限额。

- 5XX状态码，服务端错误。要求服务端出错时要捕获异常，提供友好的信息给前端，不暴露异常信息到前端。

  - `500 Internal Server Error`：客户端请求有效，服务器处理出现异常（如SQL执行错误，程序执行异常）
  - `503 Service Unavailable`：服务器无法处理请求，通常用于网站维护状态

## 参数约定

* 请求参数和返回参数字段名统一使用首字母小写的驼峰格式
* 返回的字段值数据类型要保持和数据库的数据类型一致，如字符串返回的json格式需要用双引号将内容包含起来，而数值类型的不需要。
* 除对象实体外，其他类型不允许返回`null`。
* 时间类型的数据后端要将时间戳转换为可读格式，后端WEB可用的格式有`Y-M-d H:i:s`，`Y-M-d H:i`，`Y-m-d`，如对时间无特殊要求，默认为`Y-M-d H:i`，即精确到分即可。

### 请求参数约定

__常用的请求参数必须使用下表约定的字段，不允许自定义。__

| 名称      | 参数名       | 数据类型   | 备注                                               |
|:-------:|:---------:|:------:|:------------------------------------------------ |
| 分页页码    | pageNum   | int    | 第一页从1开始                                          |
| 分页大小    | pageSize  | int    | 默认值为20，最大不能超过100                                 |
| 性别      | gender    | string | male=男，female=女                                  |
| 模糊搜索关键字 | keywords  | string | 仅针对同时支持多个字段模糊检索的，如同时从商品名称和商品详情中搜索的字段             |
| 身份证号    | idCard    | string | 特指中国大陆身份证号，前端对输入的身份证号要进行规则校验                     |
| 手机号     | mobile    | string | 特指中国大陆手机号（支持加+86），前端对输入的手机号要进行规则校验               |
| 电话号码    | telephone | string | 包括手机号，400，800，955xx，100xx，固定电话等号码，前端要对表单数据进行规则校验 |
| 姓名      | name      | string | 真实姓名                                             |
| 昵称      | nickname  | string | 网络昵称                                             |
| 邮箱      | email     | string | 前端需要针对邮箱地址进行校验                                   |
| 验证码     | captcha   | string | 包括短信验证码，输入校验验证码                                  |
| 经度      | longitude | float  | 精确到小数点后6位小数                                      |
| 纬度      | latitude  | float  | 精确到小数点后6位小数                                      |
| 唯一编号    | __实体名Id   | int    | 如用户编号，使用userId，分类编号使用categoryId                  |

### 返回格式约定

返回数据遵循ES6的规范，前端能够通过返回数据构建`Promise`对象进行处理，统一采用`JWT`做鉴权，`JWT`的访问令牌`token`通过`HTTP Header`返回。

__常用的返回参数必须使用下表约定的字段，不允许自定义。__

#### 成功返回数据

| 名称   | 参数名  | 数据类型   | 备注                                  |
|:----:|:----:|:------:|:----------------------------------- |
| 数据集合 | list | Object | 返回的数据库实体数据及其业务相关数据，不同的实体分多个json对象返回 |

示例数据如下：

```
{
    data: {
        user: {
            id: 1, 
            realName: "root", 
            genderText: "女士", 
            staffCode: "96582", 
            lastLoginedEndpointText: "网站", 
            lastLoginedAt: {
                date: "2018-12-26 11:21:40.000000", 
                timezoneType: 3, 
                timezone: "Asia/Shanghai"
            }, 
            staffStatusText: "在职", 
            accountStatusText: "正常"
        }
    }
}
```

分页返回示例

```
 {
    "data": {
        "list": [{

            "id": 10,
            "residenceName": "in placeat",
            "residenceLogo": "",
            "buildingsCount": 0,
            "unitsCount": 0,
            "housesCount": 0,
            "householdersCount": 0
        }],
        "pageNum": 1,
        "pageSize": 100,
        "pages": 20,
        "total": 1
    }
}
```

#### 失败返回数据

| 名称       | 参数名          | 数据类型   | 备注                                           |
|:--------:|:------------:|:------:|:-------------------------------------------- |
| 就绪状态     | readyState   | int    | 4=已就绪，服务端已完成响应                               |
| 请求状态码    | status       | int    | 参考http状态码返回                                  |
| 状态码描述    | statusText   | String | http状态码返回对应的英文描述，如Unauthorized, Bad Request等 |
| 响应JSON数据 | responseJSON | Object | 响应JSON数据，其中必须包含message字段，标识错误提示信息            |

示例数据如下：

```
 {
    readyState: 4,
    responseJSON: {
        message: "手机号或密码错误"
    }, 
    status: 401, 
    statusText: "Unauthorized"
}
```
