Skip to content

Koa2+Ts扩展Content

https://koajs.com/

问题

在 koa2 中,我们通常会使用 context.body 来返回数据

ts
route.post('/login', async (context: Context) => {
    const res = {
        data: {},
        code: 200,
        msg: 'success'
    }
    context.response.type = 'application/json'
    context.body = res
})

但是这样很显然是不合理的,因为每次的返回数据结构都是不可控的,所以需要统一返回数据的方法和数据结构

目标

  • 1、扩展 Content
  • 2、统一接口数据结构
  • 3、类型定义文件扩展

解决

定义数据结构

ts
/**
 * 接口响应体
 */
export interface IResponse {
    code?: number
    message?: string
    success?: boolean
    serverTime?: number
    data?: any
}

扩展Content

同样的,我们在 content 中定义新的方法,然后统一返回数据结构

为了区分,成功使用 success,失败使用 fail

我们将这个操作放在中间件中去维护,其实就是一个 function

ts
/**
 * @author: forguo
 * @description: rest
 */
import { Context, Next } from 'koa'
import { IResponse } from '@/types/response'

// 处理请求成功方法
const render = (context: Context) => {
    // 返回一个 function
    return ({ code = 200, message = 'success', data }: IResponse) => {
        context.response.type = 'application/json'
        const response: IResponse = {
            code,
            message,
            success: code.toString().startsWith('2'),
            serverTime: Date.now()
        }
        if (data) {
            response.data = data
        }
        context.body = response
    }
}

// 处理请求失败方法
const renderFail = (ctx: Context) => {
    // 返回一个 function
    return ({ code = -1, message = 'error', data }: IResponse) => {
        ctx.success({
            code,
            message,
            data
        })
    }
}

export default () => {
    return async (context: Context, next: Next) => {
        // 返回一个 function,在 controller 中执行
        context.success = render(context)
        context.fail = renderFail(context)
        await next()
    }
}

中间件集成

ts
import { Context, Next } from 'koa'
import compose from 'koa-compose'
import koaBody from 'koa-body'
import json from 'koa-json'
import rest from './rest'

const app = new Koa()

/**
 * 使用koa-compose 集成中间件
 */
const middleware = compose([
    // ...其他中间件
    json(),
    koaBody(),
    rest(),
    // ...其他中间件
])

app.use(middleware)

中间件集成完成,也就完成了 context.successcontext.fail 的扩展

这里也可以在错误处理中去集成 context.fail

使用

ts
route.post('/login', async (context: Context) => {
    const res = {
        data: {},
        code: 200,
        msg: 'success'
    }
    context.success(res)
})

类型定义文件扩展

由于我们是扩展 npm 包,所以需要使用 declare module 'koa'

ts
/**
 * 扩展 koa Context,ts 会自动融合类型
 */
import { IResponse } from '@/types/response'

export * from 'koa'
declare module 'koa' {
    /**
     * 添加 success 和 fail 方法
     */
    interface Context {
        /**
         * 响应成功
         * @param data 响应数据
         */
        success: (data: IResponse) => void
        /**
         * 响应失败
         * @param data
         */
        fail: (data: IResponse) => void
    }
}

这样就可以愉快的使用 context.successcontext.fail 了,并且是有类型提示和 ts 错误提示的