打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
WebAPI接口开发实践

背景

在团队两年多陆续负责了几个项目的开发上线已经代码的review,特别是对老项目的重构过程中,发现之前的API设计是没有任何规范和约定的,不同的开发同学有不同的习惯,因此需要一套规范去约定,现在分享一下我们目前试运行的一套规范,一起交流完善下。

WebAPI开发流程

  • 第一步首先设计接口文档,公司内部有一套自研的多人协作文档系统,可以很好的做到这一步,并能很好的做好版本控制。如果公司内部没有可以基于showdoc搭建一套

  • 第二步有技术负责人确认接口以及字段的命名规范

  • 第三步找对应API对接人,确认接口是否符合要求

    这三步其实是个闭环,只有等到全部通过后才会正式开始开发API

命名规范

  • 所有接口中不能出现拼音,统一用英语

  • 不能有特殊字符,例如/

  • 接口命名遵循像个原则: 简单 易懂

    出入参规范

  • 命名规范参考之前的一篇文章

  • 若需要使用分割符,只可以使用中划线 -

  • 禁止把所有数据库字段全部返回,统一使用Dto,只返回调用方需要的字段

    HTTP 请求方法使用规范

根据 HTTP 标准,HTTP 请求可以使用多种请求方法。
HTTP1.0 定义了三种请求方法: GET, POST 和 HEAD方法。
HTTP1.1 新增了六种请求方法:OPTIONS、PUT、PATCH、DELETE、TRACE 和 CONNECT 方法。
这里统一只是用 GET, POST,PUT,DELETE,PATCH

GET(SELECT): 从服务器获取单个资源或者资源列表
POST(CREATE):发送请求创建一个新的资源
PUT(UPDATE):通过接口更新服务器上的资源信息,资源内容全量更新,提供资源全部字段信息
DELETE(DELETE):通过删除服务器上的资源
PATCH(UPDATE) :通过接口更新服务器上的资源信息,资源内容增量更新,仅提供更新的属性信息
具体使用规范,使用GET查询获取信息,POST创建新的资源,PUT修改已存在资源信息,DELETE删除服务器资源信息,不强制要求使用Patch。

HTTP码状态使用规范

  • 200 OK :成功

  • 201 CREATED:成功创建数据 不强制使用,可以使用200

  • 400 Bad Request:提交的参数错误。错误信息中要能体现哪个parameter没有通过validation,为什么

  • 401 Unauthorized:客户端传入了一个无效的auth token。客户端需要更新token进行重试,包括让用户重新登陆

  • 403 Forbidden:访问被拒绝。最常见的case为水平越权。和401的区别是:如果改接口需要用户登陆,无有效的登陆token,则返回401,表示登陆验证未通过。登陆验证通过后,但是因为要操作的资源没有权限,则返回403.比如用户更新或者删除不属于自己的resource

  • 404 Not Found: 资源为找到

  • 429 Too Many Requests:对于限频接口请求次数超频

  • 500 Internal Server Error:应用服务器内部错误

  • 502 Bad Gateway:网关或者代理处理请求错误

  • 503 Service Unavailable:应用服务器暂时不可用

  • 504 Gateway Timeout: 网关超时。网关从上游服务没有在设定的时长内获取到数据。

自定义Header规范,

x-[应用英文缩写]-[语义化英文单词说明用途]

示例:
X-Test-Authorization: qwaszxerdfcvtyghbn

返回规范

全部统一使用 Content-Type = application/json 格式返回

请求失败的Response

  • Http码的状态为200或者201

  • code统一为 200,message 为success

  • isSuccess为true

  • 有返回值时,统一通过data返回,无返回值时为{},禁止使用null返回

  • 返回的header中追加标记本次请求的唯一值的 X-[项目英文缩写]-ResponseId

  1. {
  2. 'isSuccess': true,
  3. 'code': 200,
  4. 'message': 'success',
  5. 'data': {
  6. 'id': 0,
  7. 'value': 'Default'
  8. },
  9. 'timestamp': '02/02/2020 13:19:22'
  10. }

请求异常的Response

  • Http码的状态根据上一小节介绍的按需使用

  • code和http码对应,message 为对应异常说明

  • isSuccess为false

  • data统一返回为{}

  • 返回的header中追加标记本次请求的唯一值的 X-[项目英文缩写]-ResponseId

  1. {
  2. 'isSuccess': false,
  3. 'code': 400,
  4. 'message': 'Bad Request',
  5. 'value': {},
  6. 'timestamp': '02/02/2020 13:35:33'
  7. }

接口注释说明

约定

  • 项目统一使用swagger

  • 接口相关的文档地址

  • 相关jira.$ 分割 XXX-XXX $ XXX-XXX

  • 可能的返回的状态码

  • 对应参数说明

[c#] view plaincopyprint?
  1. <code class='hljs cs'><span class='hljs-comment'><span class='hljs-doctag'>///</span> <span class='hljs-doctag'><summary></span></span>  

  2. <span class='hljs-comment'><span class='hljs-doctag'>///</span> PUT api/values/5</span>  

  3. <span class='hljs-comment'><span class='hljs-doctag'>///</span> <span class='hljs-doctag'></summary></span></span>  

  4. <span class='hljs-comment'><span class='hljs-doctag'>///</span> <span class='hljs-doctag'><param name='id'></span>id<span class='hljs-doctag'></param></span></span>  

  5. <span class='hljs-comment'><span class='hljs-doctag'>///</span> <span class='hljs-doctag'><param name='dto'></span>dto<span class='hljs-doctag'></param></span></span>  

  6. <span class='hljs-comment'><span class='hljs-doctag'>///</span> <span class='hljs-doctag'><remarks></span></span>  

  7. <span class='hljs-comment'><span class='hljs-doctag'>///</span> <span class='hljs-doctag'><url></span>doc: https://www.cnblogs.com/sagecheng/<span class='hljs-doctag'></url></span> <span class='hljs-doctag'><br/></span></span>  

  8. <span class='hljs-comment'><span class='hljs-doctag'>///</span> <span class='hljs-doctag'><br/></span></span>  

  9. <span class='hljs-comment'><span class='hljs-doctag'>///</span> <span class='hljs-doctag'><br/></span></span>  

  10. <span class='hljs-comment'><span class='hljs-doctag'>///</span> <span class='hljs-doctag'><jira></span>jira: XXX-XXX<span class='hljs-doctag'></jira></span></span>  

  11. <span class='hljs-comment'><span class='hljs-doctag'>///</span> <span class='hljs-doctag'></remarks></span></span>  

  12. <span class='hljs-comment'><span class='hljs-doctag'>///</span> <span class='hljs-doctag'><returns></span><span class='hljs-doctag'></returns></span></span>  

  13. <span class='hljs-comment'><span class='hljs-doctag'>///</span> <span class='hljs-doctag'><response code='200'></span> success <span class='hljs-doctag'></response></span></span>  

  14. <span class='hljs-comment'><span class='hljs-doctag'>///</span> <span class='hljs-doctag'><response code='400'></span>If the id is null<span class='hljs-doctag'></response></span></span>  

  15. <span class='hljs-comment'><span class='hljs-doctag'>///</span> <span class='hljs-doctag'><response code='404'></span>If the id is not found<span class='hljs-doctag'></response></span></span>  

  16. [<span class='hljs-meta'>HttpPut(<span class='hljs-meta-string'>'{id}'</span>)</span>]  

  17. [<span class='hljs-meta'>ProducesResponseType(StatusCodes.Status200OK)</span>]  

  18. [<span class='hljs-meta'>ProducesResponseType(StatusCodes.Status400BadRequest)</span>]  

  19. [<span class='hljs-meta'>ProducesResponseType(StatusCodes.Status404NotFound)</span>]  

  20. <span class='hljs-function'><span class='hljs-keyword'>public</span> ApiResult <span class='hljs-title'>Put</span>(<span class='hljs-params'><span class='hljs-keyword'>int</span> id, [FromBody] ValueDto dto</span>)  

  21. </span>{  

  22.     <span class='hljs-keyword'>var</span> info = values.FirstOrDefault(o => o.Id == id);  

  23.     <span class='hljs-keyword'>if</span> (info == <span class='hljs-literal'>null</span>)  

  24.     {  

  25.         <span class='hljs-keyword'>throw</span> <span class='hljs-keyword'>new</span> ApiException(StatusCodes.Status404NotFound, <span class='hljs-string'>'Not Found'</span>);  

  26.     }  

  27.     info.Value = dto.Value;  

  28.     <span class='hljs-keyword'>return</span> ApiResult.GetSuccessResult();  

  29. }</code>  

  1. /// <summary>
  2. /// PUT api/values/5
  3. /// </summary>
  4. /// <param name='id'>id</param>
  5. /// <param name='dto'>dto</param>
  6. /// <remarks>
  7. /// <url>doc: https://www.cnblogs.com/sagecheng/</url> <br/>
  8. /// <br/>
  9. /// <br/>
  10. /// <jira>jira: XXX-XXX</jira>
  11. /// </remarks>
  12. /// <returns></returns>
  13. /// <response code='200'> success </response>
  14. /// <response code='400'>If the id is null</response>
  15. /// <response code='404'>If the id is not found</response>
  16. [HttpPut('{id}')]
  17. [ProducesResponseType(StatusCodes.Status200OK)]
  18. [ProducesResponseType(StatusCodes.Status400BadRequest)]
  19. [ProducesResponseType(StatusCodes.Status404NotFound)]
  20. public ApiResult Put(int id, [FromBody] ValueDto dto)
  21. {
  22. var info = values.FirstOrDefault(o => o.Id == id);
  23. if (info == null)
  24. {
  25. throw new ApiException(StatusCodes.Status404NotFound, 'Not Found');
  26. }
  27. info.Value = dto.Value;
  28. return ApiResult.GetSuccessResult();
  29. }

Swagger相关效果

整体效果

注释效果

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Exchange2010/2013/2016删除指定主题邮件
在Ubuntu下搭建Qt开发环境和Qt creator
几种常见的激活函数
Android屏幕适配方案
面试题
你不知道的Linux下的常用查找命令
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服