如果一个前后端分离项目需要对用户表进行增删改查的需求
普通的后端代码需要这样写:
http://www.baidu.com/add_user/
一个接口需要有一个返回值。因此后端接口还需要提供接口文档,说明这个接口的相关信息。
http://www.baidu.com/update_user/
http://www.baidu.com/get_user/
http://www.baidu.com/delete_user/
前端代码需要发送ajax请求,去请求上述的url,也就是接口。
$.ajax({})
1.接口(api)开发:注意这里将的接口开发并不涉及到restful,就是单纯的接口开发。
第一种普通的思路:
urlpatterns = [
url(r’^get_order/’, views.get_order),
url(r’^add_order/’, views.add_order),
url(r’^del_order/’, views.del_order),
url(r’^update_order/’, views.update_order),
]
def get_order(request):
return HttpResponse(’’)
def add_order(request):
return HttpResponse(’’)
def del_order(request):
return HttpResponse(’’)
def update_order(request):
return HttpResponse(’’)
上面这种也是接口开发,但是不建议这样写,因为一个order数据的操作就要设置四个url。如果数据多的话,前后端的url的数量也会成倍的增加。
渐渐的出来一种规范,如果大家都安装这种规范来做的话,会大大的减少url的数量,url更加简洁,此时就出现了restful规范。
2.restful api规范
a. 同一种数据的操作,只设置一个url路由。也就是根据请求方法来区分具体的处理逻辑。而不再设置多个增删改查的路由。
(1)可以基于FBV来通过请求方法的不同,处理不同的逻辑。
url(r’^order/’, views.order),
def order(request):
if request.method == ‘GET’:
return HttpResponse(‘获取订单’)
elif request.method == ‘POST’:
return HttpResponse(‘创建订单’)
elif request.method == ‘PUT’:
return HttpResponse(‘更新订单’)
elif request.method == ‘DELETE’:
return HttpResponse(‘删除订单’)
(2)可以基于CBV来实现处理不同的逻辑
url(r’^order/’, views.OrderView.as_view()),
class OrderView(View):
def get(self,request,*args,**kwargs):
return HttpResponse(json.dumps(ret),status=201)
def post(self,request,*args,**kwargs):
return HttpResponse(‘创建订单’)
def put(self,request,*args,**kwargs):
return HttpResponse(‘更新订单’)
def delete(self,request,*args,**kwargs):
return HttpResponse(‘删除订单’)
而两种方式中,最建议使用CBV的方式去写接口,更加简洁,不用判断了。
b. 域名建议
为了对用户使用的url和网页中使用的接口api进行区别,设置如下规则
(1)子域名的方式区分(需要解决跨域的问题):
www.baidu.com (用户在浏览器中输入的地址,可以访问网站页面)
但是网页需要到后台请求接口,获取数据,那么接口的api应该如何命名呢?
api.baidu.com/v1/login.json
用户一看到域名是以api开头的,就知道是接口,返回的是json数据。
(2)URL的方式进行区分(不需要解决跨域问题):
www.baidu.com (用户使用的URL)
www.baidu.com/api/v1/login.json
不管使用哪种方式,就是为了能够一眼区分出来这是一个api接口。
两种方式哪一种更好呢?
答案是第二种,因为第一种可能会出现跨域请求,也就是当域名不同或者端口不同的时候,都会出现跨域请求,而第二种保证了域名和端口的一致性,只是url不一样而已。
跨域:因为浏览器的同源策略,当你通过浏览器向www.baidu.com前端页面发送请求的时候,网页需要向后台请求接口,但是如果接口的域名和当前的域名不一致,就会出现跨域请求的错误,无法访问到页面。而跨源是网页向api发送请求之后,服务器响应了这个请求,但是是浏览器端把这一次请求的响应给阻止了,并不是在请求不同域名的接口时,服务端不会响应这个请求。跨源是浏览器端的阻止行为,而不是服务器端的。
c. 版本规则
两个版本共存的时候,应该将API的版本号放入URL。
api.example.com/api/v1/
另一种做法是,将版本号放在HTTP头信息中,但不如放入URL方便和直观。Github采用这种做法。
d. 面向资源编程
将网络中的任何东西都看作是资源,对资源可以进行增删改查的操作,但是资源表示的是一个名称,如果一个url后面跟的是一个名词(单复数都可以),所用的名词往往与数据库的表格名对应,就表示要对这个资源进行增删改查的操作了。而get/post/delete/put是动词,所以url中不建议出现动词。
www.baidu.com/api/v1/order/ (遵循规范)
www.baidu.com/api/v1/orders/ (遵循规范)
www.baidu.com/api/v1/get_order/ (没有遵循规范)
e. HTTP方法规范
GET:从服务器上获取一个或者多个资源
POST:在服务器上新建一个资源
PUT:在服务器跟新全部资源
PATCH:在服务器更新部分资源
比如用户表就有用户名,密码,性别,如果是PUT就全部更新。如果是PATHCH就只更新密码。
f. 过滤规范
www.baidu.com/api/v1/orders/?status=1&page=2&offset
g. 状态码规范(状态码+code码)
后台提供的状态码,供前端使用。
200系列,300系列表示重定向,400系列表示客户端错误,500系列表示服务端错误(后台代码错误)。
但是只有状态码还是不够的,请求的状态太多,所以除了使用状态码表示状态以外,还应该有code码来表示更加详细的请求情况。
比如:支付宝的code码,20000,20001等
def get(self,request,*args,**kwargs):
ret = {
'code':1000,
'msg':'没有携带cookie'
}
return HttpResponse(json.dumps(ret),status=201)
h. 请求的返回值规范
GET /order/:返回资源对象的列表(数组)
GET /order/1/:返回单个资源对象
POST /order/:返回新生成的资源对象
PUT /order/1/:返回完整的资源对象
PATCH /order/1/:返回完整的资源对象
DELETE /order/1/:返回一个空文档
i. Hypermedia API超链接规范
希望在请求结果中包含这一个资源的详细信息的api。
比如,我们请求商品列表信息得到如下的结果:
[
{
"id": 1,
"name": "袜子"
},
{
"id": 2,
"name": "裤子"
},
{
"id": 3,
"name": "鞋子"
}
]
如果你想查看id=1的商品的详细信息,你需要使用这个id拼接详情页的url地址,并发出请求,但是restful中希望这个详情页的url直接包含在json数据中,不用再单独进行拼接了。
[
{
"id": 1,
"name": "袜子",
"url": "http://www.baidu.com/api/v1/1/"
},
{
"id": 2,
"name": "裤子"
"url": "http://www.baidu.com/api/v1/2/"
},
{
"id": 3,
"name": "鞋子"
"url": "http://www.baidu.com/api/v1/2/"
}
]