Skip to content

Handling @fastify/type-provider-typebox schema validation errors on the frontend #1026

Open
@satnamDev-Ops

Description

@satnamDev-Ops

Description:

I am currently using @fastify/type-provider-typebox for schema validation in a Fastify application, and I'm interested in understanding how to handle the validation errors more effectively.

Below is a simplified version of my setup:

app.ts:

export async function build(opts: FastifyOptions): Promise<FastifyInstance> {
  const app = fastify(opts)
    .setValidatorCompiler(TypeBoxValidatorCompiler)
    .withTypeProvider<TypeBoxTypeProvider>();

  // Registering routes
  app.register(user, { prefix: '/user' });
  return app;
}

user.schema.ts:

import { Type, Static } from '@fastify/type-provider-typebox';

export const UserSchema = Type.Object({
  firstName: Type.String(),
  lastName: Type.String(),
  DoB: Type.String(),
});
export type User = Static<typeof UserSchema>;

userRoute.ts:

app.post('/user', { schema: { body: UserSchema } }, 
  async (req: FastifyRequest<{Body: User}>, reply: FastifyReply) => {
    return { ...req.body };
  }
);

When there's a validation error, the error message I receive is in string format:

{
  "statusCode": 400,
  "code": "FST_ERR_VALIDATION",
  "error": "Bad Request",
  "message": "body/lastName Required property, body/DoB Required property, body/lastName Expected string, body/DoB Expected string"
}

I'm concerned about handling these error messages on the frontend as the message is in string format.

To improve this, I tried customizing the error format using the setErrorHandler method:

app.ts (with custom error format):

export async function build(opts: FastifyOptions): Promise<FastifyInstance> {
  const customErrorFormat = (
    error: FastifyError,
    request: FastifyRequest,
    reply: FastifyReply
  ) => {
   if(error.validation){
      const structuredErrors: {
        keyword: string;
        schemaErrors: FastifySchemaValidationError[];
        message: string;
      }[] = [
            {
              keyword: 'validation',
              schemaErrors: error.validation,
              message: error.message,
            },
          ];
        return structuredErrors;
    }

    return error
  }

  const app = fastify(opts)
    .setValidatorCompiler(TypeBoxValidatorCompiler)
    .setErrorHandler(customErrorFormat)
    .withTypeProvider<TypeBoxTypeProvider>();

  // Registering routes
  app.register(user, { prefix: '/user' });
  return app;
}

With this setup, I get the errors in the following format:

[
  {
    "keyword": "validation",
    "schemaErrors": [
      {
        "message": "Required property",
        "instancePath": "/lastName"
      },
      {
        "message": "Required property",
        "instancePath": "/DoB"
      },
      {
        "message": "Expected string",
        "instancePath": "/lastName"
      },
      {
        "message": "Expected string",
        "instancePath": "/DoB"
      }
    ],
    "message": "body/lastName Required property, body/DoB Required property, body/lastName Expected string, body/DoB Expected string"
  }
]

While this format is more structured, I'm still unsure if it's the right approach, and I have a few questions:

Questions:

  1. Is structuring the error message (using setErrorHandler(customErrorFormat)) in the provided format the recommended approach for handling schema validation errors?
  2. Can I customize the error messages for each instance path in the schema validation error?
  3. How do developers typically handle these issues in real-life scenarios when using schema validation?

I would appreciate any insights or advice.


Metadata

Metadata

Assignees

No one assigned

    Labels

    help wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions