elysiajs / elysia

Ergonomic Framework for Humans
https://elysiajs.com
MIT License
9.23k stars 198 forks source link

Custom body object validation not working as intended when `NODE_ENV=production` #585

Open RappyTV opened 3 months ago

RappyTV commented 3 months ago

What version of Elysia.JS is running?

^1.0.10

What platform is your computer?

Linux 5.4.0-174-generic x86_64 x86_64

What steps can reproduce the bug?

I'm using this code to validate the body of a specific route:

{
    params: t.Object({ uuid: t.String() }),
    body: t.Object({ tag: t.String({ error: `Missing field "tag".` }) }, { error: `Missing field "tag".` }),
    headers: t.Object({ authorization: t.String({ error: `You're not authorized!` }) }, { error: `You're not authorized!` })
}

and this is my Elysia#onError:

.onError(({ code, set, error }) => {
    if(code == 'VALIDATION') {
        set.status = 422;
        return { error: error.message };
    } else if(code == 'NOT_FOUND') {
        set.status = 404;
        return { error: `Not Found` };
    } else {
        set.status = 500;
        Logger.error(error.message);
        return { error: `An unknown error ocurred! Please try again later` };
    }
})

What is the expected behavior?

I expect this response:

{
    "error": "Missing field \"tag\"."
}

What do you see instead?

I get this response:

{
    "error": "{\"type\":\"validation\",\"on\":\"body\"}"
}

Additional information

I get the wrong validation error response only when using bun start (NODE_ENV=production bun src/index.ts). When I start the server with bun dev or bun --watch src/index.ts/bun src/index.ts (the --watch option does not change anything) I get the expected results.

chriskalmar commented 3 months ago

I'm seeing similar behavior with 0.8.17. But in my case, it responds with {"type": "body"}

After a bit of digging, I found the place where it happens. https://github.com/elysiajs/elysia/blob/0.8/src/error.ts#L114-L118

Basically, in production any standard schema validation errors are being swallowed. I'm not sure if this is on purpose, but it makes it difficult to have a good API response in case of an incorrect input shape. I prefer my APIs to tell the consumer exactly where they failed in their payload.

I do understand there might be use cases where this detailed validation response might open your API up to attackers, but this should be something that could be decided on a by-project basis. Running the server in development mode is not ideal.

chriskalmar commented 3 months ago

Sorry, my bad. Typical RTFM problem 😅

All I needed was this:

new Elysia()
  .onError(({ code, error }) => {
    if (code === 'VALIDATION') {
      return error.all.map((prop) => ({
        message: prop.message,
        path: prop.path,
        type: prop.schema?.type,
        found: prop.value,
      }));
    }
  })

and now I get for example that in production mode:

[
  { message: "Required property", path: "/config", type: "object" },
  {
    message: "Expected string",
    path: "/uploadToken",
    type: "string",
    found: 12312,
  },
  { message: "Expected object", path: "/config", type: "object" },
  { message: "Required property", path: "/log/0/timestamp", type: "string" },
  { message: "Required property", path: "/log/0/level" },
  { message: "Required property", path: "/log/0/context", type: "string" },
];

🎉