tintin
tintin

Reputation: 11

Typescript error handling with custom defined errors

So, I just would like to know your opinions on how I'm currently handling errors on my application. First, here's my src/errors/index.ts:

interface BaseErrorProperties {
  name?: string;
  message: string;
  statusCode: number;
  action?: string;
  stack: string;
  key?: string;
}

class BaseError extends Error {
  public statusCode: number;
  public action?: string;
  public key?: string;

  constructor({ name, message, action, statusCode, stack, key }) {
    super();

    this.message = message;
    this.name = name;
    this.action = action;
    this.statusCode = statusCode;
    this.stack = stack;
    this.key = key;
  }
}

class ServiceError extends BaseError {
  constructor({
    message,
    action,
    statusCode,
    stack,
    key,
  }: BaseErrorProperties) {
    super({
      name: "ServiceError",
      message: message || "A service error happened.",
      statusCode: statusCode || 503,
      action:
        action ||
        "Please try again. If the error persists, contact the administrator.",
      stack: stack,
      key: null,
    });
  }
}

class ValidationError extends BaseError {
  constructor({
    message,
    action,
    statusCode,
    stack,
    key,
  }: BaseErrorProperties) {
    super({
      name: "ValidationError",
      message: message || "A validation error happened",
      statusCode: statusCode || 400,
      action:
        action ||
        "Please try again. If the error persists, contact the administrator.",
      stack: stack,
      key: key,
    });
  }
}

export { ServiceError, ValidationError };

And here's my e-mail sending controller:

import { ValidationError } from "@/errors";
import email from "models/email";
import { z, ZodError } from "zod";

const emailRequestBodySchema = z.object({
  from: z.string().email(),
  to: z.string().email(),
  subject: z.string(),
  text: z.string(),
  html: z.string(),
});

export async function POST(request: Request) {
  try {
    const requestBody = await request.json();

    // check for possible mistakes
    emailRequestBodySchema.parse(requestBody);

    email.sendMail(requestBody);

    return Response.json({
      ok: true,
    });
  } catch (error) {
    if (error instanceof ZodError) {
      const validationError = new ValidationError({
        key: String(error.issues[0].path[0]),
        message: "Invalid data",
        stack: new Error().stack,
        statusCode: 400,
        action: "Check your data",
      });

      return new Response(
        JSON.stringify({
          error: validationError,
        }),
        {
          status: validationError.statusCode,
        },
      );
    }
  }
}

Of course I could check for more errors on the controller, that I know. I would just like to know if this way to handle errors on a web app is actually sustainable or am I doing something bad?

Just to explain: when the error response gets to the client, I will probably render an error toast, not just console.log the error or something like that.

Upvotes: 1

Views: 30

Answers (0)

Related Questions