Untitled

mail@pastecode.io avatar
unknown
plain_text
a year ago
2.5 kB
2
Indexable
Never
import BadRequestException from "@/exceptions/BadRequestException";
import HttpException from "@/exceptions/HttpException";
import InternalServerException from "@/exceptions/InternelServerException";
import UnauthorizedException from "@/exceptions/UnauthorizedException";
import authOptions from "@/lib/auth";
import { NextApiHandler, NextApiRequest, NextApiResponse } from "next";
import { getServerSession } from "next-auth";
import { ZodSchema, z } from "zod";
import { TUser } from "../interfaces/user";
import ForbiddenException from "@/exceptions/ForbiddenException";

const handlerHelper = (handler: NextApiHandler): NextApiHandler => {
  return async (req, res) => {
    try {
      return await handler(req, res);
    } catch (err) {
      if (err instanceof HttpException) {
        return res.status(err.statusCode).json(err.getResponse());
      }

      console.log(err);
      const internalServerError = new InternalServerException();
      return res
        .status(internalServerError.statusCode)
        .json(internalServerError.getResponse());
    }
  };
};

interface EndpointHelperOptions {
  schema?: ZodSchema;
  auth?: boolean;
  // eslint-disable-next-line no-unused-vars
  middleware: (user?: TUser) => boolean | Promise<boolean>;
}

interface CustomApiRequest<TBody> extends NextApiRequest {
  body: TBody;
  user: TUser;
}

type CustomNextApiHandler<TSchema extends ZodSchema> = (
  // eslint-disable-next-line no-unused-vars
  req: CustomApiRequest<z.infer<TSchema>>,
  // eslint-disable-next-line no-unused-vars
  res: NextApiResponse
) => unknown;

export const endpointHelper = <TSchema extends ZodSchema>(
  handler: CustomNextApiHandler<TSchema>,
  options?: EndpointHelperOptions
): CustomNextApiHandler<any> => {
  return async (req, res) => {
    if (options?.auth) {
      const session = await getServerSession(req, res, authOptions);

      if (!session) {
        throw new UnauthorizedException();
      }

      req.user = session.user;
    }

    if (options?.middleware) {
      const validation = await options.middleware(req.user);

      if (!validation) {
        throw new ForbiddenException();
      }
    }

    if (options?.schema) {
      const validation = await options.schema.safeParseAsync(req.body);

      if (!validation.success) {
        throw new BadRequestException(validation.error.issues);
      }

      req.body = validation.data;
    }

    return await handler(req, res);
  };
};

export default handlerHelper;