#Composing decorators with the new decorator factory

7 messages · Page 1 of 1 (latest)

earnest horizon
#

The new strongly typed decorator factory is great. I'm attempting to replace all instances where we were setting the metadata in our codebase, however I've run across an example that breaks the mold a bit.

import { SetMetadata, applyDecorators } from "@nestjs/common";
import { DECORATORS } from "@nestjs/swagger/dist/constants";

export const IS_PUBLIC_METADATA_KEY = "isPublic";

/**
 * Public decorator to explicitly set public routes
 * Inspired by: https://docs.nestjs.com/security/authorization#basic-rbac-implementation
 */
export const Public = () =>
  applyDecorators(
    SetMetadata(IS_PUBLIC_METADATA_KEY, true),
    SetMetadata(DECORATORS.API_SECURITY, [IS_PUBLIC_METADATA_KEY]),
  );

In this case I'm using the single decorator to set multiple pieces of metadata under the hood (the second one is a workaround to override the default security setting). I haven't been able to find a clean pattern to replicate this behavior with Reflector.createDecorator. Looking for any suggestions for how to address this.

hollow sable
#

Make two decorators using the factory, then reference both those decorators in the composition method

earnest horizon
#

Do the types on applyDecorators need to be updated? ReflectableDecorator isn't a valid parameter

hollow sable
#

Probably, but you can probably use as any to get around it for now

earnest horizon
#

Ah I'd be happy to open a PR, the reflector stuff is in core though and applyDecorators is in common, what's the best way to handle that? I could move/copy the type to common, but then to test it properly I'd still need the ability to create one

earnest horizon
#

Oh wait, the types are fine, the reflectable decorator just needs to be called before passing to applyDecorators

#

So it looks like

import { SetMetadata, applyDecorators } from "@nestjs/common";
import { Reflector } from "@nestjs/core";
import { DECORATORS } from "@nestjs/swagger/dist/constants";

export const IS_PUBLIC_METADATA_KEY = "isPublic";

/**
 * Public decorator to explicitly set public routes
 * Inspired by: https://docs.nestjs.com/security/authorization#basic-rbac-implementation
 */
export const Public = () =>
  applyDecorators(
    PublicDecorator(),
    SetMetadata(DECORATORS.API_SECURITY, [IS_PUBLIC_METADATA_KEY]),
  );

export const PublicDecorator = Reflector.createDecorator<boolean | undefined>({
  transform: () => true,
});

And then @Public is used as the decorator, and PublicDecorator is used to retrieve the status