出处:  某小公司RESTful、共用接口、前后端分离、接口约定的实践

前言

  随着互联网高速发展,公司对项目开发周期不断缩短,我们面对各种需求,使用原有对接方式,各端已经很难快速应对各种需求,更难以提高效率。于是,我们不得不重新制定对接规范、开发逻辑以便快速上线项目。

我们的目标

  1. 尽可能的缩小沟通的成本,开最少的会,确定大部分的事。
  2. 花最少的时间写文档,保证90%的开发人员看懂所有内容。
  3. 哪怕不看文档,也能知道各种接口逻辑。
  4. 不重复写代码
  5. 尽可能的写高可读性的代码

我们做了哪些事

  1. 完成了前后端分离
  2. Android、ios、web共用一套接口
  3. 统一接口规范(post、put、get、patch、delete)
  4. 统一了调试工具
  5. 统一了接口文档

之前的我们

接口是这样子的:

接口地址 含义 请求方式
…/A项目/模块1/getProducts 获得产品 GET
…/A项目/模块1/addProduct 添加产品 POST
…/A项目/模块1/getProductDetail 获得产品详情 GET
…/A项目/模块1/editProduct 修改产品 POST

客户端请求是这样的:

  • …/A项目/模块1/getProducts?id=1&a=2&b=3&c=4&d=5…………
  • A页面=====》B页面(携带n个变量)====》C页面(携带m个变量,包含i个A页面的变量) -------经常n>4
  • 大部分请求是POST,至于put、patch、delete是什么鬼,关我屁事。
  • 关于接口入参使用json,那完全是看开发心情。

出参是这样的:

  {"message":"success","code":0,"data":具体内容}
  其中data里包含数组可能是
  [{"a":"1","b":"1"},{"a":"1","b":"1"},{"a":"1","b":"1"},{"a":"1","b":"1"}]
  即使下一个页面用到也不会使用id,而是把所有字段都传进去。
  A接口中,返回产品用product;B接口中使用good,多个接口很可能不统一。

客户端对接是这样子的:

  • 安卓、ios一套;部分接口各自用一套;html5端一套。
  • 客户端和后台是不停交流的

接口文档是这样的


  1. swagger
  2. 阿里的rap
  3. Word文档
  4. 其它

  当然了,我觉得swagger和rap神器都是非常强大的,能够实现各种功能逻辑,但是考虑到开发人员掌握程度不通,复杂度较高,难以提高效率,我决定初期并不使用这两样神器。

后端是这样的

  …/A项目/模块1/getProducts ----接口
  …/A项目/模块1/Products.html ----页面
  …/A项目/模块1/Products.js ----静态资源

 接口和静态资源缠在一块,毕竟很多页面可能是一位开发人员同时开发前端、后端,这里的弊端是,只需要自己清楚逻辑,很多做法临时应付,方案并不优雅,别人也很难看懂。一旦这位同事离职,很多说不清的逻辑就留给后人采坑了。

等等…………

重构

  下面步入正题,面对以上众多问题聊聊我是如何重新制定流程的

数据库约定

  约定数据库里所有表必须包含名为id主键字段。
  可能有人会说,正常来说不是每张表里都应该有id主键吗?但是,我们项目中由于之前开发不严谨,部分表没有id主键,或者不为id的主键。这里我们采用分布式的全球唯一码来作为id。

api出参约定

  约定所有出参里含list,且其他请求会用到这组list,则list里所有对象必须含id唯一标识。

入参约定

  约定token身份认证统一传入参数模式,后端采用aop切面编程识别用户身份。其他参数一律为json。

resultfull接口约定

  首先我们选择一个名词复数,比如产品

post方法

  新增一条XXX
  比如 ……/products 则代表新增一条产品
入参json如下:

{
"name":"我是一款新产品",
"price":100,
"kind":"我的分类",
"pic":[一组图片],
等等还有很多 }

java 代码control层

    @ResponseBody
@RequestMapping(value = "/A项目/B模块/products", method = {RequestMethod.POST})
public ResultObject getProducts() {
//具体逻辑。
}

put方法

  新增某条XXX记录
  比如 ……/products/1111111111
入参json如下:

{
"name":"我是一款新产品",
"price":100,
"kind":"我的分类",
"pic":[一组图片],
等等还有很多 }

表示增加一条1111111111id的记录
java代码control层

    @ResponseBody
@RequestMapping(value = "/A项目/B模块/products/{id}", method = {RequestMethod.PUT})
public ResultObject putProducts(@PathVariable(value = "id") String id) {
//具体逻辑。
}

get方法

  获得所有XXX
  ……/products 则代表获取所有产品
  因为有分页,所以我们后面加了?page=1&pageSize=50

  我们约定了所有名词复数,都会返回list,且list每个对象都有字段为id的唯一id。
比如

{
"data":{"list":[{"id":"唯一id","其他很多字段":""},{"id":"唯一id","其他很多字段":""}],"page":1,其他字段},
"code":0,
"message":"成功"
}

  ……/products/{id} 获取某个具体产品(一定比列表更详细)

  比如某个具体产品里还包含一个list,如该产品推荐列表,则:
  ……/products/{id}/recommendations

  假设它包含的不是一个list,而是对象,比如产品佣金信息,则:
  ……/products/{id}/Commission

  这里我们以是否名词复数来判断是对象还是list.

java代码control层

    @ResponseBody
@RequestMapping(value = "/A项目/B模块/products/{id}", method = {RequestMethod.GET})
public ResultObject putProducts(@PathVariable(value = "id") String id) {
//具体逻辑。
}

patch 方法

  更新局部XXX产品YYY信息
  入参是post方法时入参的子集,所有支持更新的参数会说明,并不是支持所有变量
  ……/products/{id}

{
"name":"我是一款新产品",
"price":100,
部分变量
}

java代码control层

    @ResponseBody
@RequestMapping(value = "/A项目/B模块/products/{id}", method = {RequestMethod.PATCH})
public ResultObject putProducts(@PathVariable(value = "id") String id) {
//具体逻辑。
}

delete方法

  删除XXX记录
  ……/products/11111

  删除11111产品。
java代码control层

    @ResponseBody
@RequestMapping(value = "/A项目/B模块/products/{id}", method = {RequestMethod.DELETE})
public ResultObject putProducts(@PathVariable(value = "id") String id) {
//具体逻辑。
}

其他说明

  我们尽可能少的使用动词,但有一些行为需要使用动词,比如登录等。
  关于版本号,我们打算在模块后增加/v1/等标识。

权限约定

  服务端要对用户角色进行判断,是否有权限执行某个逻辑。

前后端分离约定

  后端以开发接口为主,不再参与页面开发,或者混合式jsp页面开发,统一以接口形式返回,前端通过js渲染数据以及处理逻辑。

共用接口

  web、Android、ios使用统一接口,不在因为哪方特殊要求额外开放接口。

使用统一dao层生成工具

  基于mybatis-generator改造成适合我们项目的dao层以及部分service层,内部共同维护共同使用。

使用postman最为接口文档、调试工具

  虽然有上文中介绍的rap和swagger都是特别牛的接口神器,但是我们还是选择了postman,开发人员将接口名称、说明、入参、出参,以及各种出参示例都存储,这样开发直接可以看得清接口含义。

  我们建议使用浏览器插件,这里以360极速浏览器为例。
  插件下载地址: download.csdn.net/download/qq…

  打开360浏览器扩展中心,然后勾选开发者模式,再点击加载已解压的扩展程序,选中压缩包解压后的目录,最后点击运行即可。


其中出参注释、及接口说明,写在tests里:

/*
这里是接口说明,和每个出参、入参的意思。
*/复制代码

接口按模块划分为文件夹:

入参:


出参示例:

正常请求:

  开发人员即可直接看到接口示例进行开发,而开发人员开发的时候,自己调用一次即可保存为postman文件,为了加快上线,我们允许将java中实体类变量定义的代码(含注释)直接复制粘贴出来。

js等静态资源缓存问题

  从短期角度上讲,我的要求是减少js文件的变更,如果有变更,务必更改版本号。那么如何减少修改,我们的做法是将一部分js写在html内,反正前后端分离,大不了刷新一下cdn的节点缓存,毕竟大部分浏览器也不会主动缓存html文件(大部分浏览器会缓存js等文件)。

统一js请求框架

  这里我们使用angular js的请求框架,因为我们内部对angularjs使用较多,比较熟悉,封装后的请求,可以自动弹窗错误请求,可复写错误回调。

目前效果

  目前,我们客户端看到接口,大概能说出其意思,也能猜出一连串接口的含义,比如
    ……/classes
  可以看出它是获取班级列表接口,猜到

    ……/classes/id get获取id为id的班级详情
    ……/classes/id patch 修改班级信息
    ……/classes/id delete 删除班级信息

  至于入参,patch是post的子集、put=patch、delete无入参。

  而入参含义,直接打开postman可以直接查看每个字段的含义,并且,可以实时调取开发环境数据(非开发人员电脑),这里我们使用了多环境,详情可了解我之前写的一篇我是如何重构整个研发项目,促进自动化运维DevOps的落地?

  前端使用统一封装后的js请求框架也加快了开发进度,不用造轮子。

  开发人员,一般代码开发写好,使用postman自我测试,测试完成后,接口文档也就写好了。

  测试人员想了解接口文档的也可以直接使用postman进行导入查看。

  至此,我们交流成本下降了一大半,剩下开会的内容就是按ui分解需求或者按ui施工了。

总结

  经过一番的折腾,开发进度总算快了点,也一定程度上达到了快速上线项目的效果。关于restful风格api,每个人都有自己的见解,只要内部约定清楚,能尽可能少的减少沟通,我觉得就是好的理解。至于接口工具,可能很多人会说为什么不用之前的,我觉得以后还是会用的,最好能做到插件自动化生成api,但是对java开发注释要求比较严格,随意慢慢来吧,毕竟后面我们还有很多路要走。

RESTful、共用接口、前后端分离、接口约定的实践 (转)的更多相关文章

  1. [转] 基于NodeJS的前后端分离的思考与实践(五)多终端适配

    前言 近年来各站点基于 Web 的多终端适配进行得如火如荼,行业间也发展出依赖各种技术的解决方案.有如基于浏览器原生 CSS3 Media Query 的响应式设计.基于云端智能重排的「云适配」方案等 ...

  2. Java Web前后端分离的思考与实践

    第一节 Java Web开发方式的变化 Web开发虽然是我们常说的B/S模式,其实本质上也是一种特殊的C/S模式,只不过C和S的选择余地相对要窄了不少,而且更标准化.不论是采用什么浏览器和后端框架,W ...

  3. 前后端分离&接口API设计学习报告

    接口API设计学习报告 15331023 陈康怡 什么是API? API即Application Programming Interface.API是一种通道,负责一个程序与另一个程序的沟通.而对于w ...

  4. FastAPI + Vue 前后端分离 接口自动化测试工具 apiAutoTestWeb

    apiAutoTestWeb使用说明 apiAutoTestWeb是为apiAutoTest的可视化版本,其采用前后端分离(FastAPI + Vue2)方式实现 具体使用: Python3 + Fa ...

  5. Restful风格的前后端分离

    1.概述 ResultFul推荐每个URL能操作具体的资源,而且能准确描述服务器对资源的处理动作,通常服务器对资源支持get/post/put/delete/等,用来实现资源的增删改查.前后端分离的话 ...

  6. 《论vue在前后端分离项目中的实践之年终总结》

    我是2014年的时候开始了解知道的vue,当时vue还不太成熟,想用但是又怕自己hold不住,况且那时候vue还没有成熟的(路由.验证.ui组件)插件,社区也是不温不火的,再说也没有合适的机遇让我去项 ...

  7. Spring-Gateway与Spring-Security在前后端分离项目中的实践

    前言 网上貌似webflux这一套的SpringSecurity操作资料貌似很少. 自己研究了一波,记录下来做一点备忘,如果能帮到也在迷惑的人一点点,就更好了. 新项目是前后端分离的项目,前台vue, ...

  8. 前后端分离项目 nginx配置实践

    新项目采用前后端分离的方式开发,前后端代码打算分开部署(同机器且同域名),但打算支持后端依然可访问静态资源. 搜索nginx配置大部分都通过url前缀进行转发来做前后端分离,不适用目前项目. 说明 前 ...

  9. vue 前后端分离 接口及result规范 及drf安装使用方法

    接口 # 接口:url链接,通过向链接发送不同的类型请求与参数得到相应的响应数据​# 1.在视图层书写处理请求的 视图函数# 2.在路由层为视图函数配置 url链接 => 产生接口# 3.前台通 ...

  10. 前后端分离 接口管理神器——Rap本地搭建

    我这里要用做mockserver的就是rap了,rap结合了团队管理,项目管理,文档编写.Mock.js.可视化.接口过渡.文档历史版本(赞).mock插件(线上线下切换就只需要注释一句代码就OK), ...

随机推荐

  1. 图论——Floyd算法拓展及其动规本质

    一.Floyd算法本质 首先,关于Floyd算法: Floyd-Warshall算法是一种在具有正或负边缘权重(但没有负周期)的加权图中找到最短路径的算法.算法的单个执行将找到所有顶点对之间的最短路径 ...

  2. [CSP-S模拟测试]:A(单调栈维护凸包+二分答案)

    题目传送门(内部题150) 输入格式 第一行两个整数$N,Q$. 接下来的$N$行,每行两个整数$a_i,b_i$. 接下来的$Q$行,每行一个整数$x$. 输出格式 对于每个询问,输出一行一个整数表 ...

  3. 【redis 学习系列08】Redis小功能大用处02 Pipeline、事务与Lua

    3.Pipeline 3.1 Pipeline概念 Redis客户端执行一条命令分为如下四个过程: (1)发送命令 (2)命令排队 (3)命令执行 (4)返回结果 其中(1)和(4)称为Round T ...

  4. Dubbo系列(一)dubbo的产生背景与原理概述

    一.Dubbo框架的产生背景        大规模服务化之前,应用只是通过RMI或Hessian等工具,简单的暴露和引用远程服务,通过配置服务的URL地址进行调用,通过F5等硬件进行负载均衡. (1) ...

  5. leetcode题目142.环形链表Ⅱ(中等)

    题目描述: 给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 如果 p ...

  6. win10系统配置FTP

    FTP是一种远程传输协议,支持这种协议的就是FTP服务器.我们可以在自己的PC机上创建一个.然后通过网页就可以访问FTP服务器下的文件夹. 搭建过程 1.首先需要开启FTP服务.在菜单中打开控制面板. ...

  7. Netfilter 之 五个钩子点

    概述 在协议栈的三层IPv4(IPv6还没看,不清楚)数据包的处理过程中,可能经过Netfilter的五个钩子点,分别为NF_INET_PRE_ROUTING.NF_INET_LOCAL_IN.NF_ ...

  8. DS-博客作业07

    1.本周学习总结(0--2分) 1.1思维导图 1.2 谈谈你对查找运算的认识及学习体会. 在查找这一章,我学习的比较认真,但是还是有部分没太清楚.这章没有前一章树那么多的代码要记,但是还是要用心. ...

  9. Nginx之搭建反向代理实现tomcat分布式集群

    参考博文: Nginx反向代理实现Tomcat分布式集群 1. jdk 安装 jdk 下载网址: http://www.oracle.com/technetwork/java/javase/downl ...

  10. 封装带SSH跳板机的MYSQL

    一.封装带SSH跳板机的MYSQL 二.配置settting import pymysql from sshtunnel import SSHTunnelForwarder class MyDb(ob ...