前后端完全分离之API设计

标签: Java Javascript Rest 架构 | 发表时间:2015-04-18 09:46 | 作者:
出处:http://arccode.net/

背景

API就是开发者使用的界面。我的目标不仅是能用,而且好用, 跨平台(PC, Android, IOS, etc…)使用; 本文将详细介绍API的设计及异常处理, 并将异常信息进行封装友好地反馈给前端.

上篇文章 前后端完全分离初探只是讲了些宽泛的概念, 接下来的文章将直接上干货, 干货的源码会挂在 github上.

前后端完全分离后, 前端和后端如何交互?

答: 通过双方协商好的API.

接下来我分享我自己设计的API接口, 欢迎各位朋友指教.

API设计理念

  1. 将涉及的实体抽象成资源, 即按 id访问资源, 在 url上做文章, 以后再也不用为 url起名字而苦恼了.
  2. 使用 HTTP动词对资源进行 CRUD(增删改查); get->查, post->增, put->改, delete->删.
  3. URL命名规则, 对于资源无法使用一个单数名词表示的情况, 我使用中横线( -)连接.
    • 资源采用名词命名, e.g: 产品 -> product
    • 新增资源, e.g: 新增产品, url -> /product , verb -> POST
    • 修改资源, e.g: 修改产品, url -> /products/{id} , verb -> PUT
    • 资源详情, e.g: 指定产品详情, url -> /products/{id} , verb -> GET
    • 删除资源, e.g: 删除产品, url -> /products/{id} , verb -> DELETE
    • 资源列表, e.g: 产品列表, url -> /products , verb -> GET
    • 资源关联关系, e.g: 收藏产品, url -> /products/{id}/star , verb -> PUT
    • 资源关联关系, e.g: 删除收藏产品, url -> /products/{id}/star , verb -> DELETE

目前我API的设计只涉及这两点, 至于第三点 HATEOAS(Hypermedia As The Engine Of Application State)那就由读者自己去选择了.

项目地址

本文中只涉及了设计的理念, 具体的实现请下载源码 https://github.com/arccode/rest-api, 项目内写了比较详细的注释.

项目实战

实战将从业务场景出发, 详细介绍如何使用HTTP verb对资源进行操作( 状态转移), 使用JSON返回结果( 资源表述), 并定义JSON的基础结构.

JSON结构

requestParams:

1     
2
{     
}

responseBody:

1     
2
3
4
5
6
{     
"meta": {
},
"data": {
}
}

meta中封装操作成功或失败的消息, data中封装返回的具体数据.

当新建商品或更新产品时, 相关属性封装在JSON中, 通过POST或PUT发送,

1     
2
3
4
{     
"name": "Apple Watch SPORT",
"description": "Sport 系列的表壳材料为轻巧的银色及深空灰色阳极氧化铝金属,强化 Ion-X 玻璃材质为显示屏提供保护。搭配高性能 Fluoroelastomer 表带,共有 5 款缤纷色彩。"
}

当用户对商品进行操作后, 将得到响应结果,

GET, POST, PUT操作成功, 返回如下结果

1     
2
3
4
5
6
7
8
9
10
11
{     
"meta": {
"code": 201,
"message": "创建成功"
},
"data": {
"id": "5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9",
"name": "Apple Watch SPORT",
"description": "Sport 系列的表壳材料为轻巧的银色及深空灰色阳极氧化铝金属,强化 Ion-X 玻璃材质为显示屏提供保护。搭配高性能 Fluoroelastomer 表带,共有 5 款缤纷色彩。"
}
}

DELETE操作成功, 返回如下结果

1     
2
3
4
5
6
{     
"meta": {
"code": 204,
"message": "删除成功"
}
}

业务场景一

电商网站的管理员对商品进行新增,编辑,删除,浏览的操作; 暂时不考虑认证授权, 只关注对商品的操作.

为了以后便于做分布式, 所有资源id(表主键)均采用uuid.

新增商品

1, url: /api/product

2, method: POST

3, requestParams:

1     
2
3
4
{     
"name": "Apple Watch SPORT",
"description": "Sport 系列的表壳材料为轻巧的银色及深空灰色阳极氧化铝金属,强化 Ion-X 玻璃材质为显示屏提供保护。搭配高性能 Fluoroelastomer 表带,共有 5 款缤纷色彩。"
}

4, responseBody

1     
2
3
4
5
6
7
8
9
10
11
{     
"meta": {
"code": 201,
"message": "创建成功"
},
"data": {
"id": "5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9",
"name": "Apple Watch SPORT",
"description": "Sport 系列的表壳材料为轻巧的银色及深空灰色阳极氧化铝金属,强化 Ion-X 玻璃材质为显示屏提供保护。搭配高性能 Fluoroelastomer 表带,共有 5 款缤纷色彩。"
}
}

编辑商品

1, url: /api/products/{id}

2, method: PUT

3, requestParams:

1     
2
3
4
{     
"name": "iPhone 6",
"description": "此次苹果发布会发布了iPhone 6与iPhone 6 Plus,搭载iOS 8,尺寸分别是4.7和5.5英寸。外观设计不再棱角分明,表层玻璃边有一个弧度向下延伸,与阳极氧化铝金属机身边框衔接。机身背部采用三段式设计。机身更薄,续航能力更强。"
}

4, responseBody

1     
2
3
4
5
6
7
8
9
10
11
{     
"meta": {
"code": 200,
"message": "修改成功"
},
"data": {
"id": "5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9",
"name": "iPhone 6",
"description": "此次苹果发布会发布了iPhone 6与iPhone 6 Plus,搭载iOS 8,尺寸分别是4.7和5.5英寸。外观设计不再棱角分明,表层玻璃边有一个弧度向下延伸,与阳极氧化铝金属机身边框衔接。机身背部采用三段式设计。机身更薄,续航能力更强。"
}
}

删除商品

1, url: /api/products/{id}

2, method: DELETE

3, responseBody

1     
2
3
4
5
6
7
{     
"meta": {
"code": 204,
"message": "删除成功"
},
"data": {}
}

获取商品详情

1, url: /api/products/{id}

2, method: GET

3, responseBody

删除前

1     
2
3
4
5
6
7
8
9
10
11
{     
"meta": {
"code": 200,
"message": "查询成功"
},
"data": {
"id": "5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9",
"name": "Apple Watch SPORT",
"description": "Sport 系列的表壳材料为轻巧的银色及深空灰色阳极氧化铝金属,强化 Ion-X 玻璃材质为显示屏提供保护。搭配高性能 Fluoroelastomer 表带,共有 5 款缤纷色彩。"
}
}

删除后

1     
2
3
4
5
6
{     
"meta": {
"code": 404,
"message": "指定产品不存在"
}
}

获取商品列表(未分页)

1, url: /api/products

2, method: GET

3, responseBody

1     
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{     
"meta": {
"code": 200,
"message": "获取全部商品成功"
},
"data": [
{
"id": "5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9",
"name": "Apple Watch SPORT",
"description": "Sport 系列的表壳材料为轻巧的银色及深空灰色阳极氧化铝金属,强化 Ion-X 玻璃材质为显示屏提供保护。搭配高性能 Fluoroelastomer 表带,共有 5 款缤纷色彩。"
},
{
"id": "9db1992a-c342-4ff0-a2a4-aeb3dbfd93f6",
"name": "Apple Watch SPORT",
"description": "Sport 系列的表壳材料为轻巧的银色及深空灰色阳极氧化铝金属,强化 Ion-X 玻璃材质为显示屏提供保护。搭配高性能 Fluoroelastomer 表带,共有 5 款缤纷色彩。"
},
{
"id": "4481619b-45c5-4729-9539-f93bb01f10d8",
"name": "Apple Watch SPORT",
"description": "Sport 系列的表壳材料为轻巧的银色及深空灰色阳极氧化铝金属,强化 Ion-X 玻璃材质为显示屏提供保护。搭配高性能 Fluoroelastomer 表带,共有 5 款缤纷色彩。"
}
]
}

业务场景二

业务场景一中只涉及了单个资源的操作, 但实际场景中还有些关联操作; 如用户去电商网站浏览商品, 并收藏了一些商品, 之后又取消收藏了部分商品.

暂时不考虑用户认证授权, 以后加了 token后, 用户信息可以从中获取.

收藏商品

1, url: /api/products/{id}/star

2, method: PUT

3, responseBody

1     
2
3
4
5
6
7
8
9
10
11
12
13
{     
"meta": {
"code": 200,
"message": "收藏商品[5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9]成功"
},
"data": [
{
"id": "5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9",
"name": "iPhone 6",
"description": "此次苹果发布会发布了iPhone 6与iPhone 6 Plus,搭载iOS 8,尺寸分别是4.7和5.5英寸。外观设计不再棱角分明,表层玻璃边有一个弧度向下延伸,与阳极氧化铝金属机身边框衔接。机身背部采用三段式设计。机身更薄,续航能力更强。"
}
]
}

取消收藏商品

1, url: /api/products/{id}/star

2, method: DELETE

3, responseBody

1     
2
3
4
5
6
7
{     
"meta": {
"code": 200,
"message": "删除收藏商品[5308e9c2-a4ce-4dca-9373-cc1ffe63d5f9]成功"
},
"data": []
}

自定义异常和异常处理

所有自定义异常继承RuntimeException, 在业务层抛出, 统一在Controller层进行处理.

异常分为全局异常和局部异常, 例如http method unsupported(405), unauthorized(401), accessDenied(403), not found(404)等属于全局异常; 针对对独立业务的一些异常属于局部异常, 例如产品编辑出错;

异常在Controller中进行处理, 并封装成json返回给前端, 封装后的数据如下, 相关实现见 源码;

1     
2
3
4
5
6
{     
"meta": {
"code": 404,
"message": "指定产品不存在"
}
}
1     
2
3
4
5
6
{     
"meta": {
"code": 405,
"message": "Request method 'POST' not supported"
}
}

项目运行截图部分

本系列文章

  • 前后端完全分离初探
  • 前后端完全分离之API设计
  • 前后端完全分离之安全认证与授权-上
  • 前后端完全分离之安全认证与授权-下
  • 前后端完全分离之前端模块化开发
  • 前后端完全分离之前端路由系统
  • 前后端完全分离之后端面向服务的模块化开发

相关 [后端 完全 分离] 推荐:

前后端完全分离之API设计

- - ITeye资讯频道
API就是开发者使用的界面. 我的目标不仅是能用,而且好用, 跨平台(PC, Android, IOS, etc…)使用:本文将详细介绍API的设计及异常处理,并将异常信息进行封装友好地反馈给前端. 上篇文章前后端完全分离初探只是讲了些宽泛的概念,接下来的文章将直接上干货,干货的源码会挂在github上.

前后端分离了,然后呢?

- - ITeye资讯频道
前后端分离已经是业界所共识的一种开发/部署模式了. 关于前后端开发的另一个讨论可以参考这里. 即使通过API来解耦前端和后端开发过程,前后端通过RESTFul的接口来通信,前端的静态内容和后端的动态计算分别开发,分别部署,集成仍然是一个绕不开的问题 — 前端/后端的应用都可以独立的运行,但是集成起来却不工作.

前后端分离的优缺点

- - Web前端 - ITeye博客
WEB 前后端分离三个最大的优点在于:1:最大的好处就是前端JS可以做很大部分的数据处理工作,对服务器的压力减小到最小2:后台错误不会直接反映到前台,错误接秒较为友好3:由于后台是很难去探知前台页面的分布情况,而这又是JS的强项,而JS又是无法独立和服务器进行通讯的. 所以单单用后台去控制整体页面,又或者只靠JS完成效果,都会难度加大,前后台各尽其职可以最大程度的减少开发难度.

实现前后端分离的心得

- - 文章 – 伯乐在线
对目前的web来说,前后端分离已经变得越来越流行了,越来越多的企业/网站都开始往这个方向靠拢. 那么,为什么要选择前后端分离呢. 前后端分离对实际开发有什么好处呢?. 在以前传统的网站开发中,前端一般扮演的只是切图的工作,只是简单地将UI设计师提供的原型图实现成静态的HTML页面,而具体的页面交互逻辑,比如与后台的数据交互工作等,可能都是由后台的开发人员来实现的,或者是前端是紧紧的耦合后台.

前后端分离的思考与实践(四)

- - TaoBaoUED
前后端分离模式下的安全解决方案. 在前后端分离的开发模式中,从开发的角色和职能上来讲,一个最明显的变化就是:以往传统中,只负责浏览器环境中开发的前端同学,需要涉猎到服务端层面,编写服务端代码. 而摆在面前的一个基础性问题就是. 本文就在前后端分离模式的架构下,针对前端在Web开发中,所遇到的安全问题以及应对措施和注意事项,并提出解决方案.

前后端分离的思考与实践(五)

- - TaoBaoUED
近年来各站点基于 Web 的多终端适配进行得如火如荼,行业间也发展出依赖各种技术的解决方案. 有如基于浏览器原生 CSS3 Media Query 的响应式设计、基于云端智能重排的「云适配」方案等. 本文则主要探讨在前后端分离基础下的多终端适配方案. 关于前后端分离的方案,在 《前后端分离的思考与实践(一)》中有非常清晰的解释.

前后端分离的思考与实践(六)

- - TaoBaoUED
Nginx + Node.js + Java 的软件栈部署实践. 关于前后端分享的思考,我们已经有五篇文章阐述思路与设计. 收藏夹将 Node.js 引入传统技术栈的具体实践. 淘宝网线上应用的传统软件栈结构为 Nginx + Velocity + Java,即:. 在这个体系中,Nginx 将请求转发给 Java 应用,后者处理完事务,再将数据用 Velocity 模板渲染成最终的页面.

也谈基于NodeJS的全栈式开发(基于NodeJS的前端后端分离)

- - TaoBaoUED
随着不同终端(pad/mobile/pc)的兴起,对开发人员的要求越来越高,纯浏览器端的响应式已经不能满足用户体验的高要求,我们往往需要针对不同的终端开发定制的版本. 为了提升开发效率,前后端分离的需求越来越被重视,后端负责业务/数据接口,前端负责展现/交互逻辑,同一份数据接口,我们可以定制开发多个版本.

mysql 数据分离

- - 数据库 - ITeye博客
网上看到一个读写分离的帖子,感觉不错. 构建高性能web之路------mysql读写分离实战(转). 一个完整的mysql读写分离环境包括以下几个部分:. 在本次实战中,应用程序client基于c3p0连接后端的database proxy. database proxy负责管理client实际访问database的路由策略,采用开源框架amoeba.