E-NO
Commandes REST API 7 min de lecture

Commandes de base d'API REST avec exemples pratiques : guide d'implémentation complet

calendar_today Publié : 2026-08-13
update Dernière mise à jour : 2026-08-13
analytics Efficacité SEO : 97%
Illustration du guide technique pour « Commandes de base d'API REST avec exemples pratiques : guide d'implémentation complet ».

Les API REST alimentent la communication entre les applications modernes, mais de nombreux développeurs et opérateurs peinent à aller au-delà des simples requêtes GET lorsqu'ils déboguent, testent ou automatisent des workflows. Ce guide propose des modèles de commandes pratiques, prêts pour la production, pour les opérations REST les plus courantes — authentification, manipulation de ressources, pagination, gestion des erreurs et gestion des limites de taux — en utilisant curl et httpie comme outils principaux. Chaque exemple utilise des placeholders explicites, inclut des étapes de vérification et documente les signaux d'échec avec des chemins de récupération pour opérer en toute sécurité dans les environnements de staging et de production.

Authentification et modèles d'autorisation

Avant d'effectuer toute requête modifiant l'état, vous devez établir des sessions authentifiées. La plupart des API de production utilisent l'un de trois modèles : clés API, jetons Bearer (JWT/OAuth2) ou TLS mutuel. Les exemples ci-dessous supposent que vous avez déjà obtenu les identifiants via le flux documenté de votre fournisseur.

Clé API dans l'en-tête (courant pour AWS, Stripe, SendGrid)

curl -X GET "https://api.example.com/v1/resources" \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Accept: application/json"

Vérification : HTTP 200 avec réponse en tableau JSON. Signal d'échec : HTTP 401 avec {"error": "invalid_api_key"} — faites pivoter la clé dans le tableau de bord du fournisseur et mettez à jour le magasin de secrets.

Jeton Bearer avec actualisation automatique (OAuth2/OIDC)

# Demande initiale de jeton
TOKEN_RESPONSE=$(curl -s -X POST "https://auth.example.com/oauth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}&scope=api.read api.write")

ACCESS_TOKEN=$(echo "${TOKEN_RESPONSE}" | jq -r '.access_token')
EXPIRES_IN=$(echo "${TOKEN_RESPONSE}" | jq -r '.expires_in')

# Utilisation du jeton avec suivi d'expiration
curl -X GET "https://api.example.com/v1/resources" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Accept: application/json"

Vérification : Le jeton se décode via jq -r '.access_token' | cut -d. -f2 | base64 -d | jq . en montrant la revendication exp > heure actuelle. Signal d'échec : HTTP 401 avec WWW-Authenticate: Bearer error="invalid_token" — relancez la demande de jeton, vérifiez le décalage d'horloge, confirmez que le secret client n'a pas été renouvelé.

TLS mutuel (mTLS) pour environnements Zero-Trust

curl -X GET "https://api.internal.example.com/v1/sensitive-data" \
  --cert /etc/certs/client.pem \
  --key /etc/certs/client-key.pem \
  --cacert /etc/certs/ca-chain.pem \
  -H "Accept: application/json"

Vérification : HTTP 200. Signal d'échec : Échec de la négociation SSL (code de sortie curl 35/58) — vérifiez l'expiration du certificat avec openssl x509 -in /etc/certs/client.pem -text -noout | grep "Not After", confirmez que la chaîne CA correspond au magasin de confiance du serveur.

Opérations CRUD sur les ressources avec idempotence

Les API REST associent les méthodes HTTP à la sémantique CRUD, mais la sécurité en production exige de comprendre les garanties d'idempotence et les requêtes conditionnelles.

Créer une ressource (POST) — Non idempotent, utiliser des clés d'idempotence

IDEMPOTENCY_KEY=$(uuidgen)
curl -X POST "https://api.example.com/v1/orders" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: ${IDEMPOTENCY_KEY}" \
  -d '{
    "customer_id": "cust_abc123",
    "items": [{"sku": "SKU-001", "quantity": 2}],
    "shipping_address": {"line1": "123 Main St", "city": "Boston", "state": "MA", "postal_code": "02101", "country": "US"}
  }'

Vérification : HTTP 201 avec en-tête Location: /v1/orders/ord_xyz789 et corps de réponse contenant {"id": "ord_xyz789", "status": "pending"}. Signal d'échec : HTTP 409 avec {"error": "idempotency_key_conflict"} — même clé utilisée avec une charge utile différente ; générez une nouvelle clé. HTTP 422 — validez les champs requis selon la spécification de l'API.

Lire une ressource (GET) — Sûre, mise en cache, utiliser les ETags

# Première requête capture l'ETag
RESPONSE=$(curl -s -D - -X GET "https://api.example.com/v1/orders/ord_xyz789" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Accept: application/json")
ETAG=$(echo "${RESPONSE}" | grep -i "^etag:" | cut -d' ' -f2 | tr -d '\r')

# Requête subséquente avec en-tête conditionnel
curl -X GET "https://api.example.com/v1/orders/ord_xyz789" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Accept: application/json" \
  -H "If-None-Match: ${ETAG}"

Vérification : HTTP 200 sur la première requête, HTTP 304 (Not Modified) sur la requête conditionnelle avec corps vide. Signal d'échec : HTTP 412 Precondition Failed — ressource modifiée, récupérez une copie fraîche sans If-None-Match.

Mettre à jour une ressource (PATCH) — Préférer à PUT pour les mises à jour partielles

curl -X PATCH "https://api.example.com/v1/orders/ord_xyz789" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -H "If-Match: ${ETAG}" \
  -d '{"status": "confirmed", "metadata": {"confirmed_by": "ops_user", "confirmed_at": "2024-01-15T10:30:00Z"}}'

Vérification : HTTP 200 avec représentation de la ressource mise à jour. Signal d'échec : HTTP 412 — incompatibilité d'ETag, ressource modifiée depuis la lecture ; relisez et réessayez. HTTP 409 — conflit de logique métier (ex. : impossible de confirmer une commande annulée).

Supprimer une ressource (DELETE) — Idempotent après le premier succès

curl -X DELETE "https://api.example.com/v1/orders/ord_xyz789" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "If-Match: ${ETAG}"

Vérification : HTTP 204 No Content. Signal d'échec : HTTP 404 — déjà supprimé (succès idempotent). HTTP 409 — suppression bloquée par des ressources dépendantes ; consultez la documentation de l'API pour les paramètres cascade/force.

Pagination, filtrage et gestion des gros volumes de données

Les API de production paginent les résultats. Récupérer aveuglément la page 1 manque des données ; les boucles naïves heurtent les limites de taux. Utilisez la pagination basée sur curseur quand disponible (plus stable que l'offset), et respectez les en-têtes Retry-After.

Pagination basée sur curseur (recommandée pour gros jeux de données/changeants)

NEXT_CURSOR=""
while true; do
  URL="https://api.example.com/v1/events?limit=100"
  [ -n "${NEXT_CURSOR}" ] && URL="${URL}&cursor=${NEXT_CURSOR}"

  RESPONSE=$(curl -s -X GET "${URL}" \
    -H "Authorization: Bearer ${ACCESS_TOKEN}" \
    -H "Accept: application/json")

  # Extraire et traiter les éléments
  echo "${RESPONSE}" | jq -c '.data[]' | while read -r item; do
    echo "${item}" | jq -r '.id'  # Remplacer par le traitement réel
  done

  # Vérifier la page suivante
  NEXT_CURSOR=$(echo "${RESPONSE}" | jq -r '.pagination.next_cursor // empty')
  [ -z "${NEXT_CURSOR}" ] && break

  # Respecter la limite de taux — délai minimal
  sleep 0.2
done

Vérification : La boucle se termine quand next_cursor est null/vide. Signal d'échec : HTTP 429 avec Retry-After: 45 — analysez l'en-tête, sleep $(echo "${RETRY_AFTER}" | tr -d '\r'), puis réessayez le même curseur.

Pagination offset/limite avec compte total (pour rapports statiques)

TOTAL=$(curl -s -X GET "https://api.example.com/v1/reports?limit=1" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" | jq -r '.pagination.total')
PAGES=$(( (TOTAL + 99) / 100 ))

for ((page=1; page<=PAGES; page++)); do
  curl -s -X GET "https://api.example.com/v1/reports?limit=100&offset=$(( (page-1)*100 ))" \
    -H "Authorization: Bearer ${ACCESS_TOKEN}" \
    -H "Accept: application/json" | jq -c '.data[]'
  sleep 0.1
done

Vérification : Le nombre d'éléments agrégés correspond au total de la première requête. Signal d'échec : HTTP 5xx en milieu de boucle — journalisez l'offset échoué, reprenez depuis cette page après un délai d'attente.

Filtrage et recherche (côté serveur, pas côté client)

# Plage de dates + filtre de statut + projection de champs
curl -X GET "https://api.example.com/v1/orders?created_after=2024-01-01T00:00:00Z&created_before=2024-01-31T23:59:59Z&status=confirmed,shipped&fields=id,customer_id,total,status,created_at" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Accept: application/json"

Vérification : La réponse ne contient que les champs demandés, tous les éléments dans la plage de dates et l'ensemble de statuts. Signal d'échec : HTTP 400 avec {"error": "invalid_filter", "field": "created_after", "reason": "must_be_iso8601"} — corrigez le format.

Gestion des erreurs, limites de taux et observabilité

Les clients API robustes classifient les erreurs, implémentent un recul exponentiel avec gigue et émettent des journaux structurés pour le débogage.

Gestion structurée des réponses d'erreur

RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "https://api.example.com/v1/webhooks" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://myapp.example.com/webhook", "events": ["order.created", "order.shipped"]}')

HTTP_CODE=$(echo "${RESPONSE}" | tail -n1)
BODY=$(echo "${RESPONSE}" | head -n -1)

case ${HTTP_CODE} in
  201) echo "Webhook créé : $(echo "${BODY}" | jq -r '.id')" ;;
  400) echo "Erreur de validation : $(echo "${BODY}" | jq -r '.errors | map(.field + ": " + .message) | join(", ")')" ;;
  409) echo "Conflit : $(echo "${BODY}" | jq -r '.error.message')" ;;
  422) echo "Non traitable : $(echo "${BODY}" | jq -r '.error.details')" ;;
  429) RETRY_AFTER=$(curl -s -I "https://api.example.com/v1/webhooks" -H "Authorization: Bearer ${ACCESS_TOKEN}" | grep -i "^retry-after:" | cut -d' ' -f2 | tr -d '\r')
       echo "Limite de taux atteinte. Réessayer après ${RETRY_AFTER:-60}s" ;;
  5*) echo "Erreur serveur ${HTTP_CODE}. Corps : ${BODY}" ;;
  *) echo "HTTP ${HTTP_CODE} inattendu : ${BODY}" ;;
esac

Vérification : L'instruction case couvre tous les codes d'erreur documentés pour l'endpoint. Signal d'échec : Code HTTP non géré — ajoutez-le à l'instruction case, alertez l'équipe d'astreinte.

Recul exponentiel avec gigue (logique de réessai pour 429/5xx)

retry_with_backoff() {
  local max_attempts=5
  local base_delay=2
  local attempt=1

  while [ ${attempt} -le ${max_attempts} ]; do
    RESPONSE=$(curl -s -w "\n%{http_code}" "$@")
    HTTP_CODE=$(echo "${RESPONSE}" | tail -n1)
    BODY=$(echo "${RESPONSE}" | head -n -1)

    if [ ${HTTP_CODE} -eq 200 ] || [ ${HTTP_CODE} -eq 201 ] || [ ${HTTP_CODE} -eq 204 ]; then
      echo "${BODY}"
      return 0
    elif [ ${HTTP_CODE} -eq 429 ] || [ ${HTTP_CODE} -ge 500 ]; then
      # Extraire Retry-After ou calculer le recul
      RETRY_AFTER=$(echo "${RESPONSE}" | grep -i "^retry-after:" | cut -d' ' -f2 | tr -d '\r')
      if [ -n "${RETRY_AFTER}" ] && [ "${RETRY_AFTER}" -gt 0 ]; then
        DELAY=${RETRY_AFTER}
      else
        DELAY=$(( base_delay * (2 ** (attempt - 1)) + RANDOM % 5 ))
      fi
      echo "Tentative ${attempt}/${max_attempts} échouée (HTTP ${HTTP_CODE}). Nouvel essai dans ${DELAY}s..." >&2
      sleep ${DELAY}
      ((attempt++))
    else
      echo "${BODY}" >&2
      return 1
    fi
  done

  echo "Nombre maximal de tentatives dépassé" >&2
  return 1
}

# Utilisation
retry_with_backoff -X GET "https://api.example.com/v1/reports/large" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Accept: application/json"

Vérification : La fonction retourne 0 en cas de succès, non-zéro après le nombre maximal de tentatives. Signal d'échec : Nombre maximal de tentatives dépassé — alertez avec le dernier code HTTP et le corps pour investigation manuelle.

Journalisation des requêtes/réponses pour pistes d'audit

LOG_DIR="/var/log/api-client"
mkdir -p "${LOG_DIR}"
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
REQUEST_ID=$(uuidgen)

# Journaliser la requête (nettoyer les secrets)
curl -X POST "https://api.example.com/v1/payments" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -H "X-Request-ID: ${REQUEST_ID}" \
  -d '{"amount": 9999, "currency": "USD", "payment_method_id": "pm_abc"}' \
  -w "\nHTTP %{http_code} %{time_total}s" \
  -o "${LOG_DIR}/${REQUEST_ID}.response.json" \
  -D "${LOG_DIR}/${REQUEST_ID}.response.headers" \
  2>"${LOG_DIR}/${REQUEST_ID}.curl.stderr" | tee "${LOG_DIR}/${REQUEST_ID}.request.log"

# Nettoyer les journaux avant rétention
sed -i 's/"authorization": "Bearer [^"]*"/"authorization": "Bearer ***REDACTED***"/g' "${LOG_DIR}/${REQUEST_ID}.request.log"

Vérification : Fichiers journaux créés avec corrélation par ID de requête. Signal d'échec : Fichiers journaux manquants — vérifiez l'espace disque, les permissions, le code de sortie de curl.

Conclusion

Opérer des API REST en toute sécurité en production exige plus que la connaissance des verbes HTTP — cela demande une gestion disciplinée de l'authentification, une conscience de l'idempotence, des stratégies de pagination qui survivent aux changements de jeux de données, et une gestion des erreurs qui distingue les conditions réessayables des conditions fatales. Les modèles de ce guide — pagination basée sur curseur avec respect des limites de taux, mutations protégées par ETag, recul exponentiel avec gigue, et journalisation structurée des requêtes — forment une base que vous pouvez adapter à toute API REST. Avant d'automatiser contre un nouvel endpoint, consacrez quinze minutes à la spécification OpenAPI du fournisseur : notez la méthode d'authentification, le style de pagination, les en-têtes de limite de taux, le support des clés d'idempotence et la taxonomie des codes d'erreur. Implémentez ensuite une vérification en lecture seule, confirmez que la forme de la réponse correspond aux attentes, et seulement alors ajoutez les opérations d'écriture avec observabilité complète. Une intégration fiable rend l'échec visible, protège les identifiants à chaque couche, limite chaque changement à sa ressource visée, et définit la vérification de récupération avant qu'un incident ne force la décision.

Recherches connexes

Score de qualité de l’article

Utilité pour le lecteur 97%
  • check_circle Guide prêt à lire
  • check_circle Exemples pratiques inclus
  • check_circle URL d’article optimisée pour le SEO