routing-controllers icon indicating copy to clipboard operation
routing-controllers copied to clipboard

question: how do I validate that a @HeaderParam() is a base64 encoded object?

Open philly-vanilly opened this issue 3 years ago • 1 comments

I have a Header Param like this:

import { Get, JsonController, QueryParams, HeaderParam } from 'routing-controllers';

@Get()
async someResources(
        @HeaderParam("X-User-Data", {
            validate: {
                // ...
            }
        }) userDataB64: string
): Promise<Response> {
        // ...
}

How do I validate that the HeaderParam is a Base64 of a specific type (and, if possible, parse to that type automatically)? I cannot just replace string with

@IsBase64()
export class UserData {
    @IsString()
    name: string;
}

because @IsBase64() can only be used on properties of objects, e.g not primitives like strings.

philly-vanilly avatar Dec 25 '20 18:12 philly-vanilly

I figured out I can use @HeaderParams() instead, but it is a bit cumbersome as I have to manually decode the header, create an object from the decoded and parsed json, run the validator on that object and parse an error-message with the given validation-error-messages. Is there a way to reduce some of that code?

philly-vanilly avatar Dec 25 '20 21:12 philly-vanilly

Hey @philly-vanilly, I'm not sure if this is still relevant/helpful to you but I recently came across the same scenario you've described. In my case, I have a standard set of headers that must exist on each endpoint. This is the route I took.

@Post()
fnName(@Signal() signalMeta: SignalMetadata){} 

where SignalMetadata is the class that I want to map the header values to and validate on.

I then created a custom @Signal() decorator that will do the mapping and validation:

export function Signal() {
  return createParamDecorator({
    value: (action) => {
      const requestHeaders: IncomingHttpHeaders = action.request.headers;

      // Map headers to expected attributes (obfuscated to protect clients internal structure)
      const signalHeaders = {
        headerOne: requestHeaders["X-Header-One"] as string,
        headerTwo: requestHeaders["X-Header-Two"] as string,
        headerThree: requestHeaders["X-Header-Three"] as string,
        ... rest of attributes
      };
      
      // plainToClass allows transforming the above to the requested class
      const signal = plainToClass(SignalMetadata, signalHeaders);

      // Validate resulting object, returning expected validation errors if any
      const errors = validateSync(signal);
      if (!!errors.length) {
        throw errors;
      }
      return signal;
    },
  });
}

I would imagine you've moved on from this already, but thought I'd drop the not in case it helps anyone. If anyone has any questions, feel free to comment below and I'll try to clarify

tbakerx avatar Oct 18 '22 01:10 tbakerx

Closing this as stale.

If the issue still persists, you may open a new Q&A in the discussions tab and someone from the community may be able to help.

attilaorosz avatar Dec 21 '22 15:12 attilaorosz

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

github-actions[bot] avatar Jan 21 '23 00:01 github-actions[bot]