codelynx.dev
🇫🇷🇬🇧

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 :

TS
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 :

  1. De TypeSafe toutes les entrées automatiquement avec Zod
  2. De faire des middleware
  3. 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 :

BASH
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 :

TS
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 :

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 :

Tout 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 :

  1. Le premier qui vérifie si l'utilisateur est connecté
  2. Le deuxième qui vérifie si l'utilisateur est admin

Pour ça, on va pouvoir utiliser route.use :

TS
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 :

TS
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 :

NextReact

Cours NextJS gratuit

Accède à des exercices, des vidéos et bien plus sur NextJS dans la formation "NextReact" 👇