> ## Documentation Index
> Fetch the complete documentation index at: https://docs-kit.lucdidion.lu/llms.txt
> Use this file to discover all available pages before exploring further.

# API Layer

> Abstraction centralisée pour toutes les interactions GraphQL via Nhost

## Principe fondamental

**Règle d'or :** Aucun composant ne doit appeler `nhost.graphql` directement. Toutes les interactions passent par le dossier `src/api/` via les wrappers `apiCall()` et `apiCallVoid()`.

### ❌ Ne jamais faire

```typescript theme={null}
// Dans un composant React
import { nhost } from '@/api/client';

function ToolsList() {
  useEffect(() => {
    // ❌ Appel GraphQL direct dans le composant
    nhost.graphql.request({ query: '{ tools { id name } }' })
      .then(r => setTools(r.body.data.tools));
  }, []);
}
```

### ✅ Toujours faire

```typescript theme={null}
// Via l'API layer
import { toolsApi } from '@/api';

function ToolsList() {
  useEffect(() => {
    toolsApi.list().then(setTools);
  }, []);
}
```

***

## Structure de l'API layer

```
src/api/
├── base.ts                 # apiCall, apiCallVoid, ApiError
├── client.ts               # Client Nhost singleton
├── types.ts                # Types partagés
├── index.ts                # Barrel exports
│
├── auth.ts                 # Authentification (Nhost Auth)
├── tools.ts                # CRUD Tools (GraphQL)
├── categories.ts           # CRUD Categories
├── filters.ts              # CRUD Filters/Features
├── workflows.ts            # CRUD Workflows
├── packs.ts                # CRUD Tool Packs
├── quiz/                   # CRUD Quiz (multi-fichiers)
│
└── __tests__/              # Tests API
    ├── tools.spec.ts
    └── ...
```

***

## Fichiers de base

### `client.ts` - Client Nhost singleton

```typescript theme={null}
import { createClient } from '@nhost/nhost-js';

const nhostSubdomain = import.meta.env.VITE_NHOST_SUBDOMAIN || 'gqvlmqwbsmkhlllmgbyw';
const nhostRegion = import.meta.env.VITE_NHOST_REGION || 'eu-central-1';

export const nhost = createClient({
  subdomain: nhostSubdomain,
  region: nhostRegion,
});
```

**Pourquoi un singleton ?**

* Une seule instance partagée
* Gestion de session centralisée par Nhost
* Token JWT automatiquement injecté dans les requêtes

***

### `base.ts` - Wrappers et gestion d'erreurs

```typescript theme={null}
export class ApiError extends Error {
  constructor(message: string, public code?: string, public details?: unknown) {
    super(message);
    this.name = 'ApiError';
  }
}

// Pour les opérations qui retournent des données
export async function apiCall<T>(
  operation: () => Promise<{ data: T; error: unknown }>,
  operationName: string
): Promise<T> { /* ... */ }

// Pour les mutations sans retour
export async function apiCallVoid(
  operation: () => Promise<{ error: unknown }>,
  operationName: string
): Promise<void> { /* ... */ }
```

**Bénéfices :**

* Erreurs typées (ApiError) et prévisibles
* Logging centralisé via `logger` (pas de console.log)
* Détection automatique des erreurs réseau
* Nom d'opération pour le debugging

***

## Patterns d'utilisation

### Pattern 1 : Query simple

```typescript theme={null}
import { apiCall } from './base';
import { nhost } from './client';

async function listTools() {
  const query = `
    query GetTools {
      tools(order_by: { name: asc }) {
        id name description pricing_tier
      }
    }
  `;

  return apiCall(
    () => nhost.graphql.request({ query }).then(r => ({
      data: r.body?.data?.tools || [],
      error: r.error
    })),
    'tools.list'
  );
}
```

### Pattern 2 : Mutation avec variables

```typescript theme={null}
async function createTool(tool: ToolInsert) {
  const mutation = `
    mutation InsertTool($object: tools_insert_input!) {
      insert_tools_one(object: $object) {
        id name
      }
    }
  `;

  return apiCall(
    () => nhost.graphql.request({
      query: mutation,
      variables: { object: tool }
    }).then(r => ({
      data: r.body?.data?.insert_tools_one,
      error: r.error
    })),
    'tools.create'
  );
}
```

### Pattern 3 : Update avec `_set` (convention Hasura)

```typescript theme={null}
async function updateTool(id: string, updates: Partial<ToolInsert>) {
  const mutation = `
    mutation UpdateTool($id: uuid!, $set: tools_set_input!) {
      update_tools_by_pk(pk_columns: { id: $id }, _set: $set) {
        id name
      }
    }
  `;

  return apiCall(
    () => nhost.graphql.request({
      query: mutation,
      variables: { id, set: updates }
    }).then(r => ({
      data: r.body?.data?.update_tools_by_pk,
      error: r.error
    })),
    'tools.update'
  );
}
```

<Warning>
  **Convention Hasura** : Utilisez `_set` (avec underscore) pour les champs à mettre à jour dans les mutations. C'est le format attendu par Hasura.
</Warning>

### Pattern 4 : Delete (void)

```typescript theme={null}
async function deleteTool(id: string) {
  const mutation = `
    mutation DeleteTool($id: uuid!) {
      delete_tools_by_pk(id: $id) { id }
    }
  `;

  await apiCallVoid(
    () => nhost.graphql.request({
      query: mutation,
      variables: { id }
    }).then(r => ({ error: r.error })),
    'tools.delete'
  );
}
```

***

## Authentification

### `auth.ts`

```typescript theme={null}
import { nhost } from './client';

export const authApi = {
  async signIn(email: string, password: string) {
    const result = await nhost.auth.signIn({ email, password });
    if (result.error) throw new ApiError(result.error.message);
    return result.session;
  },

  async signOut() {
    const result = await nhost.auth.signOut();
    if (result.error) throw new ApiError(result.error.message);
  },

  getSession() {
    return nhost.auth.getSession();
  },

  isAuthenticated() {
    return !!nhost.auth.getSession();
  }
};
```

***

## Bonnes pratiques

### ✅ À faire

1. **Toujours utiliser apiCall/apiCallVoid**
2. **Toujours typer les retours** : `Promise<EnhancedTool[]>`
3. **Utiliser logger** au lieu de console.log
4. **Nommer les opérations** : `'tools.list'`, `'workflows.create'`
5. **Valider les entrées** côté client avant d'envoyer

### ❌ À éviter

1. **Appels `nhost.graphql` directs dans les composants**
2. **Ignorer les erreurs** silencieusement
3. **Types `any`** — utiliser `src/api/types.ts`
4. **console.log** en production — utiliser `logger`

***

## Ressources

<CardGroup cols={2}>
  <Card title="Nhost & GraphQL" icon="plug" href="/architecture/nhost-graphql">
    Architecture backend complète
  </Card>

  <Card title="Database Schema" icon="database" href="/database/schema">
    Structure des 13 tables
  </Card>

  <Card title="Hooks" icon="hook" href="/development/hooks">
    Utiliser l'API dans des hooks
  </Card>

  <Card title="Testing" icon="flask" href="/development/testing">
    Tester l'API layer
  </Card>
</CardGroup>
