koajs / koa

Expressive middleware for node.js using ES2017 async functions

Home Page:https://koajs.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Context not working in decorator after await action

Nyanng opened this issue · comments

I'm using Typescript, Koa version is 2.13.4, Node js is 16.11.1

First of all, I am using decorator to replace middleware.
So I wrote down below code.

Decorator:

// hasPermission decorator

export function hasPermission(
    type: PermissionType,
    action: PermissionAction,
): MethodDecorator {
    return function (
        target: Object,
        props: string | symbol,
        descriptor: PropertyDescriptor,
    ) {
        let original = descriptor.value;

        descriptor.value = async function (...args: [HttpContext, ...any]) {
            const ctx = args[0];

            const hasPermission = await ctx.state.user?.hasPermission(type, action);

            if (hasPermission) return await original.apply(this, args);
            else ctx.body = ctx.__('error.needPermission');
        };
    };
}

// hasRole decorator

export function hasRole(role: UserRole | UserRole[]) {
    return function (target: any, props: string, descriptor: PropertyDescriptor) {
        let original = descriptor.value;

        descriptor.value = function (...args: [HttpContext, ...any]) {
            const ctx = args[0];

            if (ctx.state.user?.hasRole(role)) return original.apply(this, args);
            else ctx.body = ctx.__('error.needRole');
        };
    };
}

Controller:

@hasRole([UserRole.Administrator, UserRole.Supporter])
@hasPermission(PermissionType.Shop, PermissionAction.Read)
async all(ctx: HttpContext) {
    const shops = await Shop.find({
        select: ['id', 'name', 'domain', 'endedAt'],
    });

    ctx.body = shops;
}

hasRole has no problem, but hasPermission does.

I want to check user has permission. and it is saved on database.
To check it, I have to using async/await function to get data.
But, a matter occured in this part.

in (1), context works perfectly, however (2) doesn't.
in (2), I can't manipulate any response - status code, returning body and so on.
due to this reason, if user wasn't permitted, just returning 404 error.
I don't understand why can't change context after await action.

// hasPermission

descriptor.value = async function (...args: [HttpContext, ...any]) {
    const ctx = args[0];

    // (1) ctx.body = 'in here, ctx works!'

    const hasPermission = await ctx.state.user?.hasPermission(type, action);

    // (2) ctx.body = 'in here, ctx doesn't work!'

    if (hasPermission) return await original.apply(this, args);
    else ctx.body = ctx.__('error.needPermission'); // Thus, This code doesn't work. only return default error (404).
};

How can I resolve this problem?

Please understand that my English is short and Thanks for reading.

I resolved. next() in middleware is not set 'await', so context doesn't work.