typestack/routing-controllers

question: @Param not type casted

NicholasMKim opened this issue · 24 comments

I was trying to...
Context:

  • Migrating from serverless to sst
  • Added @vendia/serverless-express during migration (but not 100% sure if this is necessary but without this sst threw an error of stream.listeners is not a function)

The problem:
After migrating to sst @Param doesn't cast id: number into number.

app.ts

import "reflect-metadata";
import { createExpressServer } from "routing-controllers";
import serverlessExpress from "@vendia/serverless-express";
import { APIGatewayProxyHandlerV2 } from "aws-lambda";


const app = createExpressServer({
  classTransformer: true,
  controllers: [/** controllers */]
});

export const handler: APIGatewayProxyHandlerV2 = (event, context) => {
  const instance = serverlessExpress({ app });
  return instance(event, context, () => {
    console.log("Server started");
  });
};

oneOfTheControllers.ts

@JsonController("/api/v1")
export class ListingController {
  @Get("/listing/agent-team/:agentTeamId")
  @OnUndefined(404)
  @OnNull(404)
  async getListingsByAgentTeamId(
    @CurrentUser() user: any,
    @Param("agentTeamId") agentTeamId: number
  ) {
    // agentTeamId is string
    authValidator(Number(agentTeamId), user, "agentTeamId");
    const listings = await ListingModel.getListingsByAgentTeamId(
      user.agentTeamId
    );
    return listings;
  }
}

Well this indeed seems weird. Could you setup a repro repo so I can debug?

Is there a chance you are missing "emitDecoratorMetadata": true, from your tsconfig.json?

I think that's not the issue. My main project has "emitDecoratorMetadata": true and I just tested the testing repo with that too 🥲. Do you know which function is responsible for class-transformer?

Unfortunately I have no experience with sst. I tried your repo locally, adding emitDecoratorMetadata: true and it worked as intended.
The transformation happens here: https://github.com/typestack/routing-controllers/blob/90ebb6a11e0a1d2f9f9da143c034576cdb564fa6/src/ActionParameterHandler.ts#LL215C21-L215C21

Screenshot 2023-06-13 at 11 33 18 AM

When I log the targetname, it is undefined. Can versions be a problem? Such as ts, node or class-transformer?

Could you try to log the values here? https://github.com/typestack/routing-controllers/blob/90ebb6a11e0a1d2f9f9da143c034576cdb564fa6/src/metadata/ParamMetadata.ts#LL123C1-L123C1

To see of explicitType is set or ParamTypes is resolved correctly.

Screenshot 2023-06-13 at 7 47 27 PM

What have I done wrong 😂. btw, Much appreciated for helping. You are the legend!

Well it seems like emitDecoratorMetadata is not set so you are not getting type information. Are you sure it is set correctly?

Sorry for the very long delay. Did you find a solution to this? The tsconfig.json indeed looks ok to me.

Just ran into this issue as well.
tsconfig.json was:

{
  "extends": "@cappsule/tsconfig/node.json",
  "include": ["src", "./db/**/*", "./scripts/**/*", "./generated/**/*"],

  "exclude": [
    "node_modules",
    "./coverage",
    "./dist",
    "__tests__",
    "jest.config.js"
  ],
  "compilerOptions": {
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true
  }
}

The problem was we were dumping it into prisma which expected a number, a simple Number(param) fixed it but yea not sure what the cause is.

Should note that it worked in dev mode so something happens during compile to not cast it i guess.

What do you use to compile typescript? I know we had issues with esbuild and type casting from decorators.

good question, unless I'm mistaken, we're using swc and this is the .swcrc

{
  "env": {
    "target": {
      "node": 18
    }
  },
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "decorators": true
    }
  },
  "module": {
    "type": "commonjs"
  },
  "sourceMaps": "inline"
}

You have reflect-metadata imported, right?

yea and its in the dist too "reflect-metadata": "^0.1.13",

Could you try to make a simple repro repo for this so I can debug it further?

sure mate, ill ping here when its done

heres the repo

Prod:

yarn && yarn build && yarn start:prod

Dev:

yarn && yarn start:dev

Navigate to: http://localhost:9876/test/1

On prod it should give:

{"type":"string"}

And on dev it'll be:

{"type":"number"}

It seems like you are missing some config in .swcrc. Could you try adding

"transform": {
  "legacyDecorator": true,
  "decoratorMetadata": true
}

into the "jsc" block?

That got it for me. Can't believe I missed that one. Although it might not have been the case for OP

Thanks much

Any updates regarding this? I had the same error where @param arguments are not being type-casted, tried to debug and I'm seeing param.targetName to be empty strings

@engr-mervin could you provide more context or a repro repo?

Hi, after a day of debugging, it turns out that it was not a problem with routing-controllers itself, but it's because I'm using tsx which does not support decorators. I moved to tsc with watch instead, and everything is working. Thanks