À côté du client, la requête que le lecteur a construite — écrite dans le langage
dans lequel il travaille, et réécrite à chaque frappe.

## Ce qui est livré

| Groupe       | Clients                                  |
| :----------- | :--------------------------------------- |
| `curl`       | curl                                     |
| TypeScript   | `fetch`, `$fetch`, `useFetch`, axios     |
| Python       | requests, httpx, urllib                  |
| Go           | `net/http`                               |
| PHP          | Guzzle, Laravel `Http`, extension curl   |

**Sept sont actifs par défaut :** curl, `fetch`, `$fetch`, Python requests, Go,
Guzzle et Laravel `Http`. Les cinq autres sont le second client d’un langage qui
en a déjà un à l’écran, et un sélecteur sert à choisir, pas à lister tout ce qui
existe.

## Deux niveaux

Le langage est l’onglet et le client un sélecteur dedans : PHP avec trois clients
coûte donc un onglet. Un site qui en ajoute trois à lui pour un langage en coûte
toujours un. Le choix du lecteur est retenu d’une page à l’autre : qui travaille en
curl travaille en curl sur l’endpoint suivant aussi.

## Configurer la liste

```ts
export default defineAppConfig({
  duxt: {
    requestSamples: ['curl', 'php-guzzle', 'php-laravel']
  }
})
```

Une chaîne choisit l’un des livrés ; les ids sont `curl`, `fetch`, `ofetch`,
`use-fetch`, `axios`, `python-requests`, `python-httpx`, `python-urllib`, `go`,
`php-guzzle`, `php-laravel`, `php-curl`.

La liste **remplace** au lieu d’étendre, comme toute autre liste de la
configuration : sinon un site documentant une API en PHP pourrait ajouter ses
clients mais jamais retirer ceux dont il ne veut pas. L’ordre est l’ordre dans
lequel ils apparaissent.

## Votre propre générateur

Un objet en ajoute un à vous — ou remplace un livré, en réutilisant son id.

```ts
requestSamples: [
  'curl',
  {
    id: 'ruby',
    group: 'Ruby',
    label: 'Net::HTTP',
    language: 'ruby',
    generate: (request) => `
uri = URI('${request.url}')
Net::HTTP.get(uri)
`.trim()
  }
]
```

| Champ      | Type                  | Remarques                                     |
| :--------- | :-------------------- | :-------------------------------------------- |
| `id`       | `string`              | Stable : c’est aussi la valeur retenue        |
| `group`    | `DuxtText`            | L’onglet                                      |
| `label`    | `DuxtText`            | L’entrée dans l’onglet                        |
| `language` | `string`              | Un id Shiki — il décide de la grammaire       |
| `generate` | `(request) => string` | Synchrone, pur, sans réseau, sans DOM         |

`generate` tourne dans le **navigateur**, à chaque frappe, parce que
l’échantillon doit suivre la requête en cours d’édition. `request` vaut
`{ method, url, headers, body?, responseType? }`, où `body` est le texte de l’éditeur et n’est pas
parsé — un générateur qui le veut en données le parse lui-même, et décide quoi
faire quand ce n’est pas du JSON.


### Pourquoi TypeScript et pas JavaScript

`$fetch`, `useFetch` et axios prennent la forme de la réponse en paramètre de
type, et `responseType` est ce qui le remplit : `$fetch<Widget>(…)` est la ligne
que quelqu’un écrit vraiment. `fetch` n’en a aucun — il renvoie un `Response`
quel que soit le corps — son échantillon est donc le même dans les deux langages.

C’est aussi pourquoi il y a un groupe et non deux. Un groupe JavaScript à côté
porterait un `fetch` qui ne diffère jamais et trois clients qui ne diffèrent que
là où le document a nommé son schéma de réponse, pour deux fois les onglets.

`responseType` est le nom du composant que renvoie une réponse réussie —
`Widget`, ou `Widget[]` pour une liste. Il est absent là où le schéma de réponse
est en ligne plutôt que derrière un `$ref`, et l’échantillon n’a alors tout
simplement pas de paramètre de type : rien ici n’invente un nom que le document
n’a pas donné.

## Ce que montre un échantillon

**La requête, et rien après.** La réponse est déjà à l’écran, dans le panneau sous
l’éditeur ; un échantillon qui irait la chercher une seconde fois montrerait au
lecteur quelque chose qu’il voit — au prix d’une branche d’erreur dans chaque
langage qui en a une.

Go est l’exception et garde ses vérifications de `err` : sans elles ce n’est pas du
Go, et un extrait qui ne compile pas est pire qu’un long.

## Les grammaires se paient, elles ne se supposent pas

Ces échantillons sont colorés dans le navigateur : chaque langage est donc des
octets qu’un lecteur télécharge — contrairement à un bloc Markdown, dont la
grammaire est un coût de build et n’atteint jamais un navigateur.

Le jeu de grammaires est donc **généré depuis la liste ci-dessus** : un site livre
exactement les langages que ses échantillons nomment. Les sept par défaut en
demandent six. Charger la table paresseuse de Shiki coûterait 3 Ko et ferait
émettre 242 fragments de grammaire à chaque build.

## Échantillons venus du document

`x-codeSamples` — dans l’une ou l’autre orthographe, l’ancienne `x-code-samples`
comprise — est lu sur une opération et **remplace les échantillons générés pour
son langage**. Celui qui possède l’API connaît ses idiomes mieux qu’un générateur.

```yaml
paths:
  /pets:
    get:
      x-codeSamples:
        - lang: ruby
          label: Net::HTTP
          source: |
            Net::HTTP.get(URI('https://api.example.com/pets'))
```

Un tel échantillon est **statique** — il ne peut pas suivre les modifications du
lecteur — c’est pourquoi le panneau dit qui l’a écrit et qu’il ne suit pas les
modifications ci-dessus. Un lecteur qui a changé le corps puis y est passé
conclurait sinon que l’éditeur est cassé plutôt que que cet échantillon est fixe.

Son langage n’est pas visible là où le jeu de grammaires est écrit : une source
distante n’est pas encore clonée. Nommez-le donc :

```ts
duxt: {
  sampleLanguages: ['ruby']
}
```

Sans cela l’échantillon est rendu en texte brut.