fetcher

Documentation de cbk-toolkit

Fetcher

Client HTTP typé avec gestion d'erreurs unifiée. Wrapper autour de fetch qui parse le JSON automatiquement et lève une ApiErrorstructurée en cas d'échec.

Utilisation de base — GET

Appel GET typé. Le résultat est parsé en JSON automatiquement et retourné avec le type fourni.

import { fetcher } from "@ramses1er/cbk-toolkit/client";

type User = { id: string; name: string; email: string };

function getUsers(): Promise<User[]> {
  return fetcher<User[]>("/api/users", { method: "GET" });
}
Mutations — POST / PATCH / DELETE

Pour les mutations, passer le body sous forme de chaîne JSON. Le Content-Type est déjà défini par défaut.

import { fetcher } from "@ramses1er/cbk-toolkit/client";

type CreateUserPayload = {
  fullname: string;
  email: string;
  roleId: string;
};

function createUser(payload: CreateUserPayload): Promise<{ success: true }> {
  return fetcher<{ success: true }>("/api/users", {
    method: "POST",
    body: JSON.stringify(payload),
  });
}

function updateUser(payload: UpdateUserPayload): Promise<{ success: true }> {
  return fetcher<{ success: true }>("/api/users", {
    method: "PATCH",
    body: JSON.stringify(payload),
  });
}

function deleteUser(id: string): Promise<{ success: true }> {
  return fetcher<{ success: true }>("/api/users", {
    method: "DELETE",
    body: JSON.stringify({ id }),
  });
}
ApiError — gestion d’erreur unifiée

Si la réponse HTTP n’est pas un succès (status ≥ 400), le fetcher lève une ApiError avec les informations structurées du backend.

import { ApiError } from "@ramses1er/cbk-toolkit/client";

try {
  const users = await fetcher<User[]>("/api/users");
} catch (error) {
  if (error instanceof ApiError) {
    console.log(error.message);   // "Email déjà utilisé"
    console.log(error.status);    // 409
    console.log(error.code);      // "EMAIL_DUPLICATE"
    console.log(error.data);      // réponse brute
  }
}
Propriétés d’ApiError :
  • message — message d’erreur (français par défaut)
  • status — code HTTP (400, 404, 409, 500...)
  • code — code métier optionnel (ex: EMAIL_DUPLICATE)
  • data — corps complet de la réponse brute
Pattern recommandé — API + React Query

Le pattern standard : une fonction API qui appelle fetcher, wrappée dans un hook React Query. Le hook expose .data, .error, .isPending directement au composant.

// api/get-users.ts — appelle le fetcher
import { fetcher } from "@ramses1er/cbk-toolkit/client";

export function getUsers(): Promise<User[]> {
  return fetcher<User[]>("/api/users", { method: "GET" });
}
// hooks/use-get-users.ts — React Query
import { useQuery } from "@tanstack/react-query";
import { ApiError } from "@ramses1er/cbk-toolkit/client";
import { getUsers } from "../api/get-users";

export function useGetUsers() {
  return useQuery<User[], ApiError>({
    queryFn: getUsers,
    queryKey: ["users"],
  });
}
// Mutation avec invalidation du cache
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { ApiError } from "@ramses1er/cbk-toolkit/client";
import { createUser } from "../api/create-user";

export function useCreateUser() {
  const queryClient = useQueryClient();

  return useMutation<{ success: true }, ApiError, CreateUserPayload>({
    mutationFn: createUser,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["users"] });
    },
  });
}
Pourquoi ce pattern ?Séparation claire : les fonctions API sont des appels réseau purs et testables, les hooks gèrent le cache et le cycle de vie React.
Options avancées

FetcherOptions étend RequestInit (headers, signal AbortController, etc.) avec une option supplémentaire :

import { fetcher } from "@ramses1er/cbk-toolkit/client";

// Désactiver le parsing JSON automatique
const blob = await fetcher<Blob>("/api/export", {
  method: "GET",
  skipJsonParsing: true,
});

// Passer des headers personnalisés
const data = await fetcher("/api/data", {
  method: "POST",
  body: JSON.stringify(payload),
  headers: {
    "X-Custom": "valeur",
  },
});

// Annuler la requête avec AbortController
const controller = new AbortController();
const data = await fetcher("/api/data", {
  signal: controller.signal,
});
API de référence
PropriétéTypeDéfautDescription
fetcher<T>(url, options?)
urlstringrequisURL de l’API
optionsFetcherOptions{}Options de la requête
FetcherOptions (étend RequestInit)
methodstringGETMéthode HTTP
bodyBodyInitCorps de la requête (passer JSON.stringify)
headersHeadersInit{ "Content-Type": "application/json" }Headers supplémentaires (fusion)
skipJsonParsingbooleanfalseDésactive le parsing JSON automatique
signalAbortSignalSignal AbortController pour annulation
ApiError (étend Error)
messagestringrequisMessage d’erreur
statusnumberrequisCode HTTP (400, 404, 409, etc.)
codestring | undefinedCode erreur métier optionnel
dataunknownCorps brut de la réponse
Comportements par défaut
  • credentials: "include" — envoie les cookies automatiquement (auth)
  • Content-Type: application/json — header par défaut (fusionnable)
  • Parsing JSON automatique si le content-type est application/json
  • ApiError.message par défaut : "Une erreur est survenue"(français)