Retour • 08/09/2024
Le meilleur moyen de créer des API Routes en NextJS App Directory
Écris par Melvyn Malherbe le 08/09/2024
En NextJS
il est possible d'utiliser le fichier route.ts
pour créer des routes... le problème c'est qu'on se retrouve très souvent à faire le même code :
const Schema = z.object({
title: z.string;
})
export const POST = async (req: NextRequest) => {
const json = await req.json();
const body = Schema.parse(json);
// ...
}
On va aussi souvent :
- Authentifier l'utilisateur
- Vérifier le type de search params ou de params
- ...
Maintenant imagine une librairie qui te permet :
- De TypeSafe toutes les entrées automatiquement avec
Zod
- De faire des
middleware
- De simplifier considérablement le routing
C'est ce que j'ai créé en contribuant au projet next-safe-route
et en créant un fork next-zod-route
!
Pourquoi j'ai créé un fork ? Le mainteneur de next-safe-route
prenait beaucoup de temps à me répondre et j'ai envie de créer une documentation clean etc...
Installation et setup
Tu peux installer la librairie avec npm :
npm install next-zod-route
Une fois fait, on va créer des routes en fonction de nos besoins dans un fichier src/lib/safe-route.ts
(j'explique comment j'organise mes fichiers dans cet article)
Voici un exemple :
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 });
},
});
On vient créer une route
avec createZodRoute
qui vient gérer ce qui se produit en cas d'erreur.
Ici tu peux rajouter des conditions pour par exemple une erreur Prisma
ou autre.
Une fois fait, on va pouvoir utiliser voire réutiliser route
dans un fichier /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,
},
})
});
Tu peux voir que le handler
a req
(la request NextJS) et body
. Tu ne peux pas le voir ici mais tout ceci est 100% TypeSafe :
middleware
Ce qui est intéressant c'est d'utiliser les middleware pour réutiliser de la logique et de venir gérer des cas d'erreur pour nos routes.
Imagine que tu veux 2 middleware
:
- Le premier qui vérifie si l'utilisateur est connecté
- Le deuxième qui vérifie si l'utilisateur est admin
Pour ça, on va pouvoir utiliser route.use
:
export const route = createZodRoute({
// Code précédent
})
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!");
}
});
Ici on va pouvoir utiliser deux nouvelles méthodes route
! Avec ce système qui permet de composer et de dupliquer les routes, on peut créer des routes pour tous nos besoins.
Elle s'utilise ensuite exactement de la même manière que route
:
export const GET = authRoute.handler(async (req, params) => {
// On a accès au context !
return NextResponse.json(params.context.user);
});
Comme d'habitude, tout est 100% TypeSafe ce qui permet d'être confiant dans le fonctionnement de notre application.
S'il y a une erreur dans le middleware
, celle-ci sera traitée par handleServerError
et l'exécution de handler
ne sera jamais effectuée.
Pourquoi utiliser des API Routes ?
Tu pourrais vouloir utiliser next-safe-action qui permet de faire des server-actions sans prise de tête.
Mais attention !
Les Server Actions ne sont pas conçues pour récupérer des données.
Tu peux voir dans ce Tweet que les server-actions ont un problème, il n'est pas facile de cache
la valeur de retour.
Si tu souhaites vraiment avoir des éléments client-side, utiliser des API Route avec TanStack Query c'est le meilleur choix !
Conclusion
N'hésite pas à me dire ce que tu as pensé de cette librairie et si tu comptes l'utiliser. En attendant, tu peux t'inscrire à mon cours sur NextJS dans lequel on comprend tout sur 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 :