rest_framework_api規範

目錄

1、什麼是RESTful html

2、什麼是API前端

3、RESTful API規範vue

4、基於Django實現APIgit

5、基於Django Rest Framework框架實現github

 

一. 什麼是RESTful 

  • REST與技術無關,表明的是一種軟件架構風格,REST是Representational State Transfer的簡稱,中文翻譯爲「表徵狀態轉移
  • REST從資源的角度類審視整個網絡,它將分佈在網絡中某個節點的資源經過URL進行標識,客戶端應用經過URL來獲取資源的表徵,得到這些表徵導致這些應用轉變狀態
  • 全部的數據,不論是經過網絡獲取的仍是操做數據庫得到(增刪改查)的數據,都是資源,將一切數據視爲資源是REST區別與其餘架構風格的最本質屬性
  • 對於REST這種面向資源的架構風格,有人提出一種全新的結構理念,即:面向資源架構(ROA:Resource Oriented Architecture)
    • 對互聯網上的任意東西都視爲資源,他認爲一個url就是一個資源 好比:http://www.xxx.com/get_user/

二. 什麼是API

一、什麼是API?ajax

答:API就是接口,提供的url。接口有兩個用途:數據庫

  • - 爲別人提供服務
  • - 先後端分離,一個寫vue,一個寫後端,他們之間都是經過ajax請求

3、RESTful API設計

網絡應用程序,分爲前端和後端兩個部分。當前的發展趨勢,就是前端設備層出不窮(手機、平板、桌面電腦、其餘專用設備......)。django

所以,必須有一種統一的機制,方便不一樣的前端設備與後端進行通訊。這致使API構架的流行,甚至出現"API First"的設計思想。RESTful API是目前比較成熟的一套互聯網應用程序的API設計理論。json

一、協議

API與用戶的通訊協議,老是使用HTTPs協議後端

二、域名(URL)

規範

1.不用大寫;

2.用中槓 - 不用下槓 _ ;

3.參數列表要encode;

4.URI中的名詞表示資源集合,使用複數形式。

5.在RESTful架構中,每一個網址表明一種資源(resource),因此網址中不能有動詞,只能有名詞(特殊狀況可使用動詞),並且所用的名詞每每與數據庫的表格名對應。

域名的兩種方式

# 方式一: 儘可能將API部署在專用域名(會存在跨域問題)
https://api.example.com


# 方式二:若是肯定API很簡單,不會有進一步擴展,能夠考慮放在主域名下。
https://example.org/api/

版本(Versioning)

應該將API的版本號放入URL。

https://api.example.com/v1/
https://api.example.com/v1/zoos
https://api.example.com/v1/zoos/1/animals

另外一種作法是,將版本號放在HTTP頭信息中,但不如放入URL方便和直觀。Github採用這種作法。

詳細域名

URI表示資源的兩種方式:資源集合、單個資源。

資源集合:

       /zoos   # 全部動物園

       /zoos/1/animals  # id爲1的動物園中的全部動物

單個資源:

       /zoos/1  # id爲1的動物園

       /zoos/1;2;3  # id爲1,2,3的動物園


結合版本
       https://api.example.com/v1/zoos
       https://api.example.com/v1/animals
       https://api.example.com/v1/employees

注意事項

在url中表達層級,用於 按實體關聯關係進行對象導航 ,通常根據id導航。

過深的導航容易致使url膨脹,不易維護,如 GET /zoos/1/areas/3/animals/4 ,儘可能使用查詢參數代替路徑中的實體導航,如 GET/animals?zoo=1&area=3 ;

三、HTTP請求(Request)

request方法

方法說明

# 經常使用的HTTP動詞有下面五個(括號裏是對應的SQL命令)

GET(SELECT):從服務器取出資源(一項或多項)。即獲取數據

POST(CREATE):在服務器新建一個資源。 即添加數據

PUT(UPDATE):在服務器更新資源(客戶端提供改變後的完整資源,即完整的數據)。即更新數據。與下面的PATCH相似。

PATCH(UPDATE):在服務器更新資源(客戶端提供改變的屬性,即一部分數據)。即更新數據。

DELETE(DELETE):從服務器刪除資源  。即刪除數據


# 用的很少的 HEAD / OPTION

HEAD:獲取資源的元數據

OPTIONS:獲取信息,關於資源的哪些屬性是客戶端能夠改變的

reques方法的一些使用例子

GET /zoos  # 列出全部動物園
GET /zoos/ID  # 獲取某個指定動物園的信息
GET /zoos/ID/animals  # 列出某個指定動物園的全部animals

POST /zoos  # 新建一個動物園
POST /zoos/1/employees  # 爲id爲1的動物園僱傭員工

PUT /zoos/ID  # 更新某個指定動物園的信息(提供該動物園的所有信息)

PATCH /zoos/ID  # 更新某個指定動物園的信息(提供該動物園的部分信息)

DELETE /zoos/ID  # 刪除某個動物園
DELETE /zoos/ID/animals/ID  # 刪除某個指定動物園的指定動物
DELETE /zoos/ID/animals/2;5;6;8  # 刪除某個指定動物園的指定動物,使用";"表示多個

過濾信息(Filtering)

若是記錄數量不少,服務器不可能都將它們返回給用戶。API應該提供參數,過濾返回結果。

下面是一些常見的參數。

# 分頁相關
?limit=10  # 指定返回記錄的數量
?offset=10  # 指定返回記錄的開始位置。
?page=2&per_page=100  # 指定第幾頁,以及每頁的記錄數。

# 排序相關
?sortby=name&order=asc  # 指定返回結果按照哪一個屬性排序,以及排序順序。

# 過濾條件
?type=1&age=16  # 容許必定的uri冗餘,如 /zoos/1 與 /zoos?id=1
?animal_type_id=1  # 指定篩選條件

# 投影
?whitelist=id,name,email

參數的設計容許存在冗餘,即容許API路徑和URL參數偶爾有重複。好比,GET /zoo/ID/animals 與 GET /animals?zoo_id=ID 的含義是相同的。

四、返回結果(Response)

各HTTP方法成功處理後的數據格式

·

response 格式

GET

單個對象、集合

POST

新增成功的對象

PUT/PATCH

更新成功的對象

DELETE

狀態碼(status codes)

# 服務器向用戶返回的狀態碼和提示信息,常見的有如下一些(方括號中是該狀態碼對應的HTTP動詞)。

200 OK - [GET]:服務器成功返回用戶請求的數據,該操做是冪等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:用戶新建或修改數據成功。
202 Accepted - [*]:表示一個請求已經進入後臺排隊(異步任務)
204 NO CONTENT - [DELETE]:用戶刪除數據成功。
400 INVALID REQUEST - [POST/PUT/PATCH]:用戶發出的請求有錯誤,服務器沒有進行新建或修改數據的操做,該操做是冪等的。
401 Unauthorized - [*]:表示用戶沒有權限(令牌、用戶名、密碼錯誤)。
403 Forbidden - [*] 表示用戶獲得受權(與401錯誤相對),可是訪問是被禁止的。
404 NOT FOUND - [*]:用戶發出的請求針對的是不存在的記錄,服務器沒有進行操做,該操做是冪等的。
406 Not Acceptable - [GET]:用戶請求的格式不可得(好比用戶請求JSON格式,可是隻有XML格式)。
410 Gone -[GET]:用戶請求的資源被永久刪除,且不會再獲得的。
422 Unprocesable entity - [POST/PUT/PATCH] 當建立一個對象時,發生一個驗證錯誤。
500 INTERNAL SERVER ERROR - [*]:服務器發生錯誤,用戶將沒法判斷髮出的請求是否成功。


# URI失效
隨着系統發展,總有一些API失效或者遷移,對失效的API,返回404 not found 或 410 gone;對遷移的API,返回 301重定向。

狀態碼的徹底列表參見這裏

Bookmarker

常用的、複雜的查詢標籤化,下降維護成本。

如:GET /trades?status=closed&sort=created,desc

快捷方式:GET /trades#recently-closed或者GET /trades/recently-closed

五、錯誤處理(Error handling)

1.     不要發生了錯誤卻給2xx響應,客戶端可能會緩存成功的http請求;

2.     正確設置http狀態碼,不要自定義;

3.     Response body提供

即:返回的信息中將error做爲鍵名,出錯信息做爲鍵值便可

1)錯誤的代碼(日誌/問題追查);

2)錯誤的描述文本(展現給用戶)。

 

若是狀態碼是4xx,就應該向用戶返回出錯信息。通常來講,返回的信息中將error做爲鍵名,出錯信息做爲鍵值便可。

{
    code: 10086,
    error: "Invalid API key"
}

六、Hypermedia API  超媒體API

RESTful API最好作到Hypermedia,即返回結果中提供連接,連向其餘API方法,使得用戶不查文檔,也知道下一步應該作什麼。

好比,當用戶向api.example.com的根目錄發出請求,會獲得這樣一個文檔。

{"link": {
  "rel":   "collection https://www.example.com/zoos",  #表示這個API與當前網址的關係(collection關係,並給出該collection的網址)
  "href":  "https://api.example.com/zoos",  #API路徑
  "title": "List of zoos",  #API的標題
  "type":  "application/vnd.yourformat+json"  #返回類型
}}

Hypermedia API的設計被稱爲HATEOAS。Github的API就是這種設計,訪問api.github.com會獲得一個全部可用API的網址列表。

{
  "current_user_url": "https://api.github.com/user",
  "authorizations_url": "https://api.github.com/authorizations",
  // ...
}

從上面能夠看到,若是想獲取當前用戶的信息,應該去訪問api.github.com/user,而後就獲得了下面結果。

{
  "message": "Requires authentication",
  "documentation_url": "https://developer.github.com/v3"
}

4、基於Django實現API

方式一:FBV模式

from django.contrib import admin

from django.conf.urls import url, include
from app01 import views
from app02 import views

urlpatterns = [
    url('admin/', admin.site.urls),
    # path('hosts/',views.HostView.as_view()),
    url('app02/', include('app02.urls'))
]
全局url.py
from app02 import views
from django.conf.urls import url
urlpatterns = [
    url('^users/', views.users),
    url('^user/(\d+)', views.user),

    url('^users/', views.UsersView.as_view()),
    url('^user/', views.UserView.as_view()),
]
app02/url.py
from django.shortcuts import render,HttpResponse

# Create your views here.
import json

def users(request):
    response = {'code':1000,'data':None}  #code用來表示狀態,好比1000表明成功,1001表明
    response['data'] = [
        {'name':'haiyan','age':22},
        {'name':'haidong','age':10},
        {'name':'haixiyu','age':11},
    ]
    return HttpResponse(json.dumps(response))  #返回多條數據

def user(request,pk):
    if request.method =='GET':
        return HttpResponse(json.dumps({'name':'haiyan','age':11}))  #返回一條數據
    elif request.method =='POST':
        return HttpResponse(json.dumps({'code':1111}))  #返回一條數據
    elif request.method =='PUT':
        pass
    elif request.method =='DELETE':
        pass
views.py

方式二:CBV模式

from app02 import views
from django.conf.urls import url
urlpatterns = [
    url('^users/', views.UsersView.as_view()),
    url('^user/', views.UserView.as_view()),
]
app02/url.py
from django.views import View
class UsersView(View):
    def get(self,request):
        response = {'code':1000,'data':None}
        response['data'] = [
            {'name': 'haiyan', 'age': 22},
            {'name': 'haidong', 'age': 10},
            {'name': 'haixiyu', 'age': 11},
        ]
        return HttpResponse(json.dumps(response),stutas=200)

class UserView(View):
    def get(self,request,pk):
        return HttpResponse(json.dumps({'name':'haiyan','age':11}))  #返回一條數據
    def post(self,request,pk):
        return HttpResponse(json.dumps({'code':1111}))  #返回一條數據
    def put(self,request,pk):
        pass
    def delete(self,request,pk):
        pass
views.py

基於django實現的API許多功能都須要咱們本身開發,這時候djangorestframework就給咱們提供了方便,直接基於它來返回數據,總之原理都是同樣的,就是給一個接口也就是url,讓前端的人去請求這個url去獲取數據,在頁面上顯示出來。這樣也就達到了先後端分離的效果。下面咱們來看看基於Django Rest Framework框架實現

5、基於Django Rest Framework框架實現

一、自定義認證規則

詳見連接

class MyAuthtication(BasicAuthentication):
    def authenticate(self, request):
        token = request.query_params.get('token')  #注意是沒有GET的,用query_params表示
        if token == 'zxxzzxzc':
            return ('uuuuuu','afsdsgdf') #返回user,auth
        raise APIException('認證錯誤')

class UserView(APIView):
    authentication_classes = [MyAuthtication,]
    def get(self,request,*args,**kwargs):
        print(request.user)
        print(request.auth)
        return Response('用戶列表')

二、應用

主要是作Token驗證  url中as_view裏面調用了dispatch方法。

能夠有兩種方式

局部使用

from app01 import views
from django.conf.urls import url
urlpatterns = [
    # django rest framework
    url('^hosts/', views.HostView.as_view()),
    url(r'^auth/', views.AuthView.as_view()),
]
urls.py
from django.shortcuts import render,HttpResponse
# Create your views here.
from rest_framework.views import  APIView
from rest_framework.views import Request
from rest_framework.authentication import SessionAuthentication
from rest_framework.authentication import BaseAuthentication, BasicAuthentication
from rest_framework.parsers import JSONParser
from rest_framework.negotiation import  DefaultContentNegotiation
from rest_framework.exceptions import APIException
from app01 import models
from rest_framework.response import Response  #友好的顯示返回結果



class AuthView(APIView):
    #auth登陸頁面不須要驗證,可設置
    authentication_classes = []  #登陸頁面不須要認證
    def get(self,request):
        '''
        接收用戶名和密碼
        :param request:
        :return:
        '''
        ret = {'code':1000,'msg':None}
        user = request.query_params.get('username')

        pwd = request.query_params.get('password')
        print(user,pwd)
        obj = models.UserInfo.objects.filter(username=user,password=pwd).first()
        print(obj)
        if not obj :
            ret['code'] = 1001
            ret['msg'] = '用戶名或者密碼錯誤'
            return Response(ret)
        #建立隨機字符串
        import time
        import hashlib
        ctime = time.time()
        key = '%s|%s'%(user,ctime)
        m = hashlib.md5()
        m.update(key.encode('utf-8'))
        token = m.hexdigest()

        #保存數據
        obj.token = token
        obj.save()

        ret['token'] = token
        return Response(ret)

class HostView(APIView):
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)

    # authentication_classes = [MyAuthtication]

    def get(self,request,*args,**kwargs):
        print(request.user,'dddddddddddffffff')
        print(request.auth,'dddddddddd')
        #原來的request,django.core.handlers.wsgi.WSGIRequest
        #如今的request ,rest_framework.request.Request
        # print(request)
        authentication_classes = [SessionAuthentication,BaseAuthentication]
        # print(self.authentication_classes)  # [<class 'rest_framework.authentication.SessionAuthentication'>,
                                            #  <class 'rest_framework.authentication.BasicAuthentication'>]
        return HttpResponse('GET請求的響應內容')

    def post(self,request,*args,**kwargs):
        pass
        # try:
        #     try :
        #         current_page = request.POST.get("page")
        #
        #         current_page = int(current_page)
        #         int("asd")
        #     except ValueError as e:
        #         print(e)
        #         raise #若是有raise說明本身處理不了了,就交給下面的一個去捕捉了
        # except Exception as e:
        #     print("OK")


        return  HttpResponse('post請求的響應內容')

    def put(self, request, *args, **kwargs):
        return HttpResponse('put請求的響應內容')
Views.py

全局使用

#註冊認證類
REST_FRAMEWORK = {
    'UNAUTHENTICATED_USER': None,
    'UNAUTHENTICATED_TOKEN': None,  #將匿名用戶設置爲None
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "app01.utils.MyAuthentication",
    ],
}
settings.py
from  rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import APIException
from app02 import models


class MyAuthentication(BaseAuthentication):
    def authenticate(self, request):
        token=request.query_params.get('token')
        print(token)
        obj=models.UserInfo.objects.filter(token=token).first()
        print(obj)
        if obj:
            return (obj.username,obj)
        raise  APIException('沒有經過驗證')
全局驗證

注:rest_framewor是一個app須要settings裏面設置。

 

參考or轉發

http://www.cnblogs.com/haiyan123/p/8419972.html

相關文章
相關標籤/搜索