Django-Rest-Swagger搭建前后端分离API文档

Django-Rest-Swagger搭建前后端分离API文档

前沿:最近工作需要,做项目需要前后端分离,那么前段与后端的“沟通”就成了项目执行效率的一大障碍。我们尝试过去写API说明文档,但试想一下,作为一个后端工程师,你不光需要修改后端代码,还要去撰写API文档,使得你的工作量剧增,WTF?作为一个能省事儿绝不多敲一行字的鞋狗程序员,希望吧更多的时间投入球鞋“冲冲冲”中,就尝试搭建一个Django-Swagger框架,非常便捷的实现前后端API交互。话不多说,开始正文↓

什么是Django-Swagger

Django大家并不陌生,后端开发的一个框架。而对于Swagger,想必做前端的并不陌生,但对于做后端的我,听到Swagger我的第一反应就是摇起来!Wow Fantastic Baby!我就去百度Swagger,大致了解了Swagger是什么,能做什么。简单的说,Django-Swagger其实就是在Django项目中使用Swagger框架,使得在做后端开发的同时自动生成一个API文档供前端查看。看到“自动”两个字,是不是很有动力?不过搭建DS也有一个弊端,对于已经写好的后端代码,搭建DS需要修改大量的代码,我还是劝你去敲API文档吧lol!但对于全新的一个项目,DS是一个很好的选择。

但是,看了许久貌似对我的项目没有太大的帮助呀,How Should I Do?在查资料的过程中,从某书(JS)网站上看到一位名为“行如风”的大神与2017年写的代码,对我启发很大,那么我也是在他代码的基础上进行的Django-Swagger搭建。

环境配置

Django-Swagger依赖于:

djangorestframework 3.7.1
django-rest-swagger 2.1.2

建议先安装djangorestframework,再安装django-rest-swagger。至于版本问题,不同的版本在代码上有所调整,可能不适用与我的代码,我装载的版本是严格与上述一致的。(不然真的会出很多问题,不信你可以试试~)
Django-Rest-Swagger搭建前后端分离API文档_第1张图片
我默认你会创建一个django项目,并且创建了一个app。在这里我创建了一个名为Swagger的项目,并在项目内部创建了一个名为api的app。接下来我们就开始搭建swagger框架。

搭建DS框架

1-配置settings.py

在INSTALLED_APPS中添加‘api’app、‘rest_framework’、‘rest_frame_work_swagger’。并添加swagger配置项。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'api',
    'rest_framework',
    'rest_framework_swagger'
]

REST_FRAMEWORK = {
    # 下面这一行表示接口文档的访问权限, AllowAny不做权限限制.
    'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.AllowAny',),
    # 'PAGE_SIZE': 10,
    'PAGINATE_BY':10,
}

# swagger 配置项
SWAGGER_SETTINGS = {
    # 基础样式
    'SECURITY_DEFINITIONS': {
        "basic":{
            'type': 'basic'
        }
    },
    # 如果需要登录才能够查看接口文档, 登录的链接使用restframework自带的.
    # 'LOGIN_URL': 'rest_framework:login',
    # 'LOGOUT_URL': 'rest_framework:logout',
    # 'DOC_EXPANSION': None,
    # 'SHOW_REQUEST_HEADERS':True,
    # 'USE_SESSION_AUTH': True,
    # 'DOC_EXPANSION': 'list',
    # 接口文档中方法列表以首字母升序排列
    'APIS_SORTER': 'alpha',
    # 如果支持json提交, 则接口文档中包含json输入框
    'JSON_EDITOR': True,
    # 方法列表字母排序
    'OPERATIONS_SORTER': 'alpha',
    'VALIDATOR_URL': None,
}

2-写入api/views.py

那我们在写views.py之前,就会想一般我们是先有路由,再写views,那在这里为什么需要先写views呢?从我们项目的需求来想,我们需要的功能使然,我们不需要像别的教程那样序列化(Serialize)一个Model,我们只需要对我们的功能函数进行封装,并处理成Swagger能识别的编码格式,因此我们需要对一个类进行重写,同时前后端之间的通信是以JSON格式进行的,我们也需要写一下简单的处理函数(当然不写也可以,全凭自己喜好)。
概括的说,我们先写views不是写功能,是写“配置”。

from django.http import HttpResponse
from rest_framework.views import APIView
from rest_framework.permissions import AllowAny
from rest_framework.schemas import SchemaGenerator
from rest_framework.schemas.generators import LinkNode, insert_into
from rest_framework.renderers import *
from rest_framework_swagger import renderers
from rest_framework.response import Response
import json

def response_as_json(data):
    json_str = json.dumps(data)
    response = HttpResponse(json_str,
                            content_type='application/json')
    response["Access-Control-Allow-Origin"] = '*'
    return response

def json_response(data,code=200,**kwargs):
    data = {
        "code":code,
        "data":data
    }
    return response_as_json(data)

def json_error(error_str,code,**kwargs):
    data = {
        'code':code,
        'error':error_str,
    }
    return response_as_json(data)

JsonResponse = json_response
JsonError = json_error

class MySchemaGenerator(SchemaGenerator):
    def get_links(self, request=None):
        links = LinkNode()
        paths = []
        view_endpoints = []
        for path, method, callback in self.endpoints:
            view = self.create_view(callback, method, request)
            path = self.coerce_path(path, method, view)
            paths.append(path)
            view_endpoints.append((path, method, view))
        if not paths:
            return None
        prefix = self.determine_path_prefix(paths)
        for path, method, view in view_endpoints:
            if not self.has_view_permissions(path, method, view):
                continue
            link = view.schema.get_link(path, method, base_url=self.url)
            # 添加下面这一行方便在views编写过程中自定义参数.
            link._fields += self.get_core_fields(view)
            subpath = path[len(prefix):]
            keys = self.get_keys(subpath, method, view)
            insert_into(links, keys, link)
        return links
    # 从类中取出我们自定义的参数, 交给swagger 以生成接口文档.
    def get_core_fields(self, view):
        return getattr(view, 'coreapi_fields', ())

class SwaggerSchemaView(APIView):
    _ignore_model_permissions = True
    exclude_from_schema = True
    permission_classes = [AllowAny]
    renderer_classes = [
        CoreJSONRenderer,
        renderers.OpenAPIRenderer,
        renderers.SwaggerUIRenderer
    ]

    def get(self, request):
        generator = MySchemaGenerator(title='接口', description='前后端分离接口API查询')
        schema = generator.get_schema(request=request)
        return Response(schema)
详细介绍一下上述代码实现的功能,从参考的网页中看到他们调入的序列化库不外乎是将代码转为json格式,但是我们的json库完全够用,因此就写了三个函数作为转json使用,相比大家也能够看明白;其次,MySchemaGenerator继承自SchemaGenerator并重写了部分代码,以实现自定义参数。

再往views中添加一个功能用于测试

class ReturnJson(APIView):
    def get(self,request,*args,**kwargs):
        return JsonResponse('测试用例')

3-配置url.py

    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    url(r'^docs/', views.SwaggerSchemaView.as_view(), name='apiDocs'),

4-测试

python manage.py runserver 8000

输入127.0.0.1:8000/docs查看结果如下图
Django-Rest-Swagger搭建前后端分离API文档_第2张图片
到这里,我们的框架已经成功搭建了。Mission Success近在眼前。从页面里看到,我们无法进行传参,无法告知前端我们需要什么样的参数,是字符串?还是文件?有木有详细说明?或者举个例子?

这就需要我们在views.py文件中继续定义一个传递参数的函数,如下:

# 定义参数传递
import coreapi
from django.http import QueryDict
from rest_framework.request import Request

def DocParam(name= 'default',location='',
             required = False,description =None,type = 'string',
             *args,**kwargs):
    return coreapi.Field(name=name,location=location,required=required,description=description,type=type)

# 编写参数统一处理的方法
def get_parameter_dic(request,*args,**kwargs):
    if isinstance(request,Request) == False:
        return {}
    query_params = request.query_params
    if isinstance(query_params,QueryDict):
        query_params = query_params.dict()
    result_data = request.data
    if isinstance(result_data,QueryDict):
        result_data = result_data.dict()
    if query_params != {}:
        return query_params
    else:
        return result_data

为什么要编写参数统一处理的方法?简单地说你去试一下便知,如果不编写,出的错误你也会看的很明白。若想深入理解编写参数同意的方法,可以参考文章开头博主提到那位大神,他在文章中说的很明确。

我们为项目的ReturnJson添加一个传参,再为项目添加一个POST功能函数,实现文件上传,并返回具体的Error信息来测试上文的所有功能。别忘了在url中添加post的url

class ReturnJson(APIView):
    coreapi_fields = (
        DocParam("token"),
        DocParam("contract_type")
    )
    def get(self,request,*args,**kwargs):
        params = get_parameter_dic(request)
        return JsonResponse(data=params,code=102)

class Approval(APIView):
    coreapi_fields = (
        DocParam('contract_file',location='formData',type='file',description='上传文件'),
        DocParam('contract_type',location ='query',description='合同工类型')
    )
    def post(self,request,*args,**kwargs):
        if request.method == 'POST':
            file = request.FILES.get('contract_file')
            params = get_parameter_dic(request)
            if not file and 'contract_type' not in params:
                error = 'Please Select a File and Select contract_type'
                return JsonError(error, 101)
            elif not file:
                error = 'Please Select a File'
                return JsonError(error, 102)
            elif 'contract_type' not in params:
                error = 'Please Select Contract Type'
                return JsonError(error, 103)
            else:
                contract_type = params['contract_type']
                return JsonResponse("success")

访问docs返回结果如下图:
Django-Rest-Swagger搭建前后端分离API文档_第3张图片

前段就可以在Swagger页面中测试参数,填写参数并调试后端返回的信息了。

Django-Rest-Swagger搭建前后端分离API文档_第4张图片
Django-Rest-Swagger搭建前后端分离API文档_第5张图片
这样,我们就可以在我们的项目中使用Django-Swagger这个前后端分离API文档自动生成的框架了,这能给后端开发者省去很多的时间。当然还是那句话,对于已经搭建好的项目,改代码太麻烦啦,写API文档吧,对于不喜欢DS的大神,写API文档吧!

你可能感兴趣的:(Django-Rest-Swagger搭建前后端分离API文档)