mirror of
https://github.com/Sonny93/my-links.git
synced 2025-12-08 22:53:25 +00:00
feat: api handler
This commit is contained in:
@@ -1,29 +0,0 @@
|
||||
import PATHS from "constants/paths";
|
||||
|
||||
export { default } from "next-auth/middleware";
|
||||
|
||||
// WAIT: for fix - Next.js@13.4.4 seems to be broken
|
||||
// cf: https://github.com/nextauthjs/next-auth/issues/7650
|
||||
// (this file must renamed "middleware.ts")
|
||||
|
||||
export const config = {
|
||||
matcher: [
|
||||
PATHS.HOME,
|
||||
|
||||
PATHS.LINK.CREATE,
|
||||
PATHS.LINK.EDIT,
|
||||
PATHS.LINK.REMOVE,
|
||||
|
||||
PATHS.CATEGORY.CREATE,
|
||||
PATHS.CATEGORY.EDIT,
|
||||
PATHS.CATEGORY.REMOVE,
|
||||
|
||||
PATHS.API.CATEGORY.CREATE,
|
||||
PATHS.API.CATEGORY.EDIT,
|
||||
PATHS.API.CATEGORY.REMOVE,
|
||||
|
||||
PATHS.API.LINK.CREATE,
|
||||
PATHS.API.LINK.EDIT,
|
||||
PATHS.API.LINK.REMOVE,
|
||||
],
|
||||
};
|
||||
93
src/lib/api/handler.ts
Normal file
93
src/lib/api/handler.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import { User } from "@prisma/client";
|
||||
import { PrismaClientKnownRequestError } from "@prisma/client/runtime";
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
import { Session } from "next-auth";
|
||||
|
||||
import getUserOrThrow from "lib/user/getUserOrThrow";
|
||||
import { getSessionOrThrow } from "utils/session";
|
||||
|
||||
type ApiHandlerMethod = ({
|
||||
req,
|
||||
res,
|
||||
session,
|
||||
user,
|
||||
}: {
|
||||
req: NextApiRequest;
|
||||
res: NextApiResponse;
|
||||
session: Session;
|
||||
user: User;
|
||||
}) => Promise<void>;
|
||||
|
||||
// This API Handler strongly inspired by
|
||||
// Source: https://jasonwatmore.com/next-js-13-middleware-for-authentication-and-error-handling-on-api-routes
|
||||
|
||||
export function apiHandler(handler: {
|
||||
get?: ApiHandlerMethod;
|
||||
post?: ApiHandlerMethod;
|
||||
put?: ApiHandlerMethod;
|
||||
patch?: ApiHandlerMethod;
|
||||
delete?: ApiHandlerMethod;
|
||||
}) {
|
||||
return async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const method = req.method.toLowerCase();
|
||||
if (!handler[method])
|
||||
return res
|
||||
.status(405)
|
||||
.json({ error: `Method ${req.method} Not Allowed` });
|
||||
|
||||
try {
|
||||
const session = await getSessionOrThrow(req, res);
|
||||
const user = await getUserOrThrow(session);
|
||||
|
||||
await handler[method]({ req, res, session, user });
|
||||
} catch (err) {
|
||||
errorHandler(err, res);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function errorHandler(error: any, response: NextApiResponse) {
|
||||
if (typeof error === "string") {
|
||||
const is404 = error.toLowerCase().endsWith("not found");
|
||||
const statusCode = is404 ? 404 : 400;
|
||||
|
||||
return response.status(statusCode).json({ message: error });
|
||||
}
|
||||
|
||||
// does not fit with current error throwed
|
||||
// TODO: fix errors returned
|
||||
// by getSessionOrThrow or getUserOrThrow
|
||||
if (error.name === "UnauthorizedError") {
|
||||
// authentication error
|
||||
return response.status(401).json({ message: "You must be connected" });
|
||||
}
|
||||
|
||||
const errorMessage =
|
||||
error.constructor.name === "PrismaClientKnownRequestError"
|
||||
? handlePrismaError(error) // Handle Prisma specific errors
|
||||
: error.message;
|
||||
|
||||
console.error(error);
|
||||
return response.status(500).json({ message: errorMessage });
|
||||
}
|
||||
|
||||
function handlePrismaError({
|
||||
meta,
|
||||
code,
|
||||
message,
|
||||
}: PrismaClientKnownRequestError) {
|
||||
switch (code) {
|
||||
case "P2002":
|
||||
return `Duplicate field value: ${meta.target}`;
|
||||
case "P2003":
|
||||
return `Foreign key constraint failed on the field: ${meta.field_name}`;
|
||||
case "P2014":
|
||||
return `Invalid ID: ${meta.target}`;
|
||||
case "P2003":
|
||||
return `Invalid input data: ${meta.target}`;
|
||||
|
||||
// Details should not leak to client, be carreful with this
|
||||
default:
|
||||
return `Something went wrong: ${message}`;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,9 @@ import { Session } from "next-auth";
|
||||
import prisma from "utils/prisma";
|
||||
|
||||
export default async function getUserOrThrow(session: Session) {
|
||||
if (!session || session === null) {
|
||||
throw new Error("You must be connected");
|
||||
}
|
||||
return await prisma.user.findFirstOrThrow({
|
||||
where: {
|
||||
email: session?.user?.email,
|
||||
|
||||
@@ -3,11 +3,15 @@ import { getServerSession } from "next-auth/next";
|
||||
|
||||
import { authOptions } from "pages/api/auth/[...nextauth]";
|
||||
|
||||
export async function getSession(req: NextApiRequest, res: NextApiResponse) {
|
||||
return await getServerSession(req, res, authOptions);
|
||||
}
|
||||
|
||||
export async function getSessionOrThrow(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
const session = await getServerSession(req, res, authOptions);
|
||||
const session = await getSession(req, res);
|
||||
|
||||
if (!session) {
|
||||
throw new Error("You must be connected");
|
||||
|
||||
Reference in New Issue
Block a user