返回文章列表文章索引阅读全文
STARBLOG / 阅读手记
Django

Wrapping Django API Responses in a Unified Format

Introduction I've been really busy lately. I started a new project, and to get a product out quickly I chose Django for the backend, then picked up the project scaffolding I had packaged before, DjangoStarter. Because I wrote quite a bit of .NetCore backend code recently and gained some new insights into CRUD API development, I definitely have to revamp DjangoStarter as well, to make it more convenient to use~ Side note: I finally actually started using react on the frontend. I have to say ts + react is really nice to use,

曦远 (DealiAxy)约 11 分钟
目录5 个章节

Introduction

I've been really busy lately. I started a new project, and to get a product out quickly I chose Django for the backend, then picked up the project scaffolding I had packaged before, DjangoStarter.

Because I wrote quite a bit of .NetCore backend code recently and gained some new insights into CRUD API development, I definitely have to revamp DjangoStarter as well, to make it more convenient to use~

Side note: I finally actually started using react on the frontend. I have to say ts + react is really nice to use. The recommendation from "Frontend Guru" was really solid (nice

The Main Topic

To be precise, this is implemented together with DjangoRestFramework. The core code consists of two parts: one is the error-handling wrapper, and the other is the response wrapper renderer.

Whether the request errors or not, it will be wrapped by our custom renderer.

Code

Let's get to the code~

First, add a new Python package to the project. Place it wherever makes sense for you; in the DjangoStarter template, I put it at utils/response. The next two files will both go in this directory.

The first is the error-handling exception.py file:

from typing import Dict

from rest_framework.exceptions import ValidationError
from rest_framework.views import exception_handler
from rest_framework.views import Response
from rest_framework.utils.serializer_helpers import ReturnDict
from rest_framework import status


def custom_handler(err: ValidationError, context: dict):
    # 先调用REST framework默认的异常处理方法获得标准错误响应对象
    response: Response = exception_handler(err, context)

    if response is None:
        return Response({
            'message': f'服务器错误:{err}'
        }, status=status.HTTP_500_INTERNAL_SERVER_ERROR, exception=True)

    else:
        # 因为RestFramework默认的报错信息是 detail 字段,这里取出系统的报错信息
        msg = response.data.pop('detail', response.reason_phrase)
        res = {'message': msg}
        res.update(response.data)
        return Response(res, status=response.status_code, exception=True)

Then the custom renderer.py code:

from rest_framework.renderers import JSONRenderer


class CustomRenderer(JSONRenderer):
    # 重构render方法
    def render(self, data, accepted_media_type=None, renderer_context=None):
        if renderer_context:
            # 响应的信息,成功和错误的都是这个
            # 成功和异常响应的信息,异常信息在前面自定义异常处理中已经处理为{'message': 'error'}这种格式

            # 如果返回的data为字典
            if isinstance(data, dict):
                # 响应信息中有message和code这两个key,则获取响应信息中的message和code,并且将原本data中的这两个key删除,放在自定义响应信息里
                # 响应信息中没有则将msg内容改为请求成功 code改为请求的状态码
                msg = data.pop('message', '请求成功')
                code = data.pop('code', renderer_context["response"].status_code)
            # 如果不是字典则将msg内容改为请求成功 code改为响应的状态码
            else:
                msg = '请求成功'
                code = renderer_context["response"].status_code

            # 自定义返回的格式
            ret = {
                'message': msg,
                'code': code,
                'data': data,
            }
            # 返回JSON数据
            return super().render(ret, accepted_media_type, renderer_context)
        else:
            return super().render(data, accepted_media_type, renderer_context)

The key parts are commented, so it should be easy to follow.

After wrapping, every API's return value looks like this:

{
    "message": "msg",
    "code": 200,
    "data": {
        "data1": "123"
    }
}

Configuration

For the code above to take effect, you still need to configure RestFramework.

Edit the settings.py file and add these two settings under the REST_FRAMEWORK node. Make sure the paths match the two files above. Here I'm using the DjangoStarter project as an example.

REST_FRAMEWORK = {
    # 全局配置异常模块
    'EXCEPTION_HANDLER': 'utils.response.exception.custom_handler',
    # 修改默认返回JSON的renderer的类
    'DEFAULT_RENDERER_CLASSES': ('utils.response.renderer.CustomRenderer',),
}

That's it~ It's that simple.

(Simpler than wrapping return values in AspNetCore……)

The full code is available on GitHub: https://github.com/Deali-Axy/DjangoStarter

References

_EOF_

Wrapping Django API Responses in a Unified Format

本文作者:
程序设计实验室
版权声明:
本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

相关文章

Django中「强行」使用MVVM设计模式

扫盲 首先带大家了解一下什么是MVVM模式: 什么是MVVM?MVVM是Model-View-ViewModel的缩写。 MVVM是MVC的增强版,实质上和MVC没有本质区别,只是代码的位置变动而已 从名字上看,MVVM比MVC架构中多了一个ViewModel,没错,就是这个ViewModel,他是MVVM相对于MVC改进的核心思想。在开发过程中,由于需求的变更或添加,项目的复杂度越来越高,代码量

2021-12-18 · Django · 约 1 分钟

讨论

共 0 条

良言一句三冬暖,恶语伤人六月寒。

加载评论中…