Back • 08/09/2024
The best way to create API Routes in NextJS App Directory
Written by Melvyn Malherbe on 08/09/2024
In NextJS
it is possible to use the route.ts
file to create routes... the problem is that we often end up writing the same code:
const Schema = z.object({
title: z.string();
})
export const POST = async (req: NextRequest) => {
const json = await req.json();
const body = Schema.parse(json);
// ...
}
We also often:
- Authenticate the user
- Check the type of search params or params
- ...
Now imagine a library that allows you to:
- TypeSafe all inputs automatically with
Zod
- Use
middleware
- Simplify routing considerably
That's what I created by contributing to the next-safe-route
project and creating a fork next-zod-route
!
Why did I create a fork? The maintainer of next-safe-route
took a long time to respond to me and I wanted to create clean documentation, etc...
Installation and setup
You can install the library with npm:
npm install next-zod-route
Once done, we will create routes according to our needs in a file src/lib/safe-route.ts
(I explain how I organize my files in this article)
Here is an example:
export class RouteError extends Error {
status?: number;
constructor(message: string, status?: number) {
super(message);
this.status = status;
}
}
export const route = createZodRoute({
handleServerError: (e: Error) => {
if (e instanceof RouteError) {
return NextResponse.json(
{ message: e.message, status: e.status },
{
status: e.status,
},
);
}
return NextResponse.json({ message: "Internal server error" }, { status: 500 });
},
});
We create a route
with createZodRoute
that handles what happens in case of an error.
Here you can add conditions for example for a Prisma
error or others.
Once done, we will be able to use or even reuse route
in a file /api/users/route.ts
:
import { route } from "~/lib/safe-route";
const BodySchema = z.object({
name: z.string(),
email: z.string().email(),
});
export const POST = route
.body(BodySchema)
.handler(async (req, { body }) => {
await prisma.user.create({
data: {
name: body.name,
email: body.email,
},
})
});
You can see that the handler
has req
(the NextJS request) and body
. You can't see it here but all this is 100% TypeSafe:
middleware
What is interesting is to use middleware to reuse logic and handle error cases for our routes.
Imagine you want 2 middleware
:
- The first one checks if the user is logged in
- The second one checks if the user is an admin
For that, we will be able to use route.use
:
export const route = createZodRoute({
// Previous code
})
export const authRoute = route.use(async () => {
const user = await auth();
if (!user) {
throw new RouteError("Session not found!");
}
return {
user,
};
});
export const adminRoute = authRoute.use(async (params) => {
if (!params.context.user.isAdmin) {
throw new RouteError("You are not admin!");
}
});
Here we will be able to use two new route
methods! With this system that allows composing and duplicating routes, we can create routes for all our needs.
It is then used exactly the same way as route
:
export const GET = authRoute.handler(async (req, params) => {
// We have access to the context!
return NextResponse.json(params.context.user);
});
As usual, everything is 100% TypeSafe which allows us to be confident in the functioning of our application.
If there is an error in the middleware
, it will be handled by handleServerError
and the execution of handler
will never be performed.
Why use API Routes?
You might want to use next-safe-action which allows you to do server-actions without hassle.
But be careful!
Server Actions are not designed to fetch data.
You can see in this Tweet that server-actions have a problem, it is not easy to cache
the return value.
If you really want to have client-side elements, using API Routes with TanStack Query is the best choice!
Conclusion
Feel free to tell me what you think of this library and if you plan to use it. In the meantime, you can sign up for my NextJS course where we understand everything about NextJS:
Le meilleur moyen d'apprendre NextJS !
Rejoins par développeurs, cette formation reçoit une note de 4.7 / 5 🚀
Reçois la formation gratuitement dans ta boîte mail :