Servir sa première API
TutorielExploitationDepuis la version 0.1.0
Guide d'exploitation : configurer, déployer et observer la passerelle. Ce que fait la capacité côté produit : guide produit ; l'appeler : guide développeur.
Objectif : router une opération déclarée, sans identité ni quota, pour vérifier la chaîne.
Commande
cat > flexway.yaml <<'EOF'
version: 1
contracts:
openapi: ./openapi.yaml
upstreams:
default:
url: http://host.docker.internal:8081 # votre API ; dans un conteneur, localhost est la passerelle elle-même
protocol: http
timeout: 3s
EOF
flexway validate # hors ligne, sans cluster
docker run --rm --name flexway -p 8080:8080 -p 9090:9090 \
--add-host=host.docker.internal:host-gateway \
-v "$PWD:/etc/flexway:ro" \
ghcr.io/flexwiz/flexway:<version>Un tag d'image porte le v de la release (ghcr.io/flexwiz/flexway:v1.0.0). La passerelle sert
le trafic sur 8080 et son administration sur 9090 ; l'openapi.yaml est à
côté de flexway.yaml, et chacune de ses opérations porte un operationId - une opération sans
lui est refusée au chargement, car quotas, clés et audit nomment les opérations par lui.
Vérif : une opération déclarée dans l'OpenAPI répond. Une route non déclarée répond 404
en application/problem+json - pas parce qu'elle est interdite, parce qu'elle n'existe pas.
Toute opération sans
x-flexway-upstreamutilise l'amontdefault. C'est ce qui permet de démarrer avec quatre lignes.
Gabarits de chemin. Un segment peut mêler paramètres et texte, comme OpenAPI le permet :
/reports/{year}.pdf, /api/v{n}/status, /tiles/{z}-{x}-{y}.png, /tasks/{id}:cancel. Chaque
paramètre prend au moins un caractère et s'arrête au premier texte qui le suit (/files/{name}.{ext}
sur archive.tar.gz : name = archive, ext = tar.gz). Précédence : un segment littéral
(/reports/latest.pdf), puis le segment mixte qui a le plus de texte, puis le paramètre seul
(/reports/{id}). Sont refusés au chargement, opération nommée : deux paramètres collés
({x}{y}), une accolade isolée, et deux segments mixtes de même rang qui peuvent lire le même texte
(a{x} et {x}a).
Avant de démarrer, la même vérification se joue hors ligne, sans grappe ni réseau :
flexway validate
# ou, sans dépôt cloné - le validateur est dans chaque image publiée (signée, même digest) :
docker run --rm -v "$PWD:/etc/flexway:ro" ghcr.io/flexwiz/flexway:<version> validate -v
docker run --rm -v "$PWD:/w:ro" ghcr.io/flexwiz/flexway:<version> validate --config /w/flexway.yaml --contract /w/next.yamlCode de sortie 0 quand le profil est accepté, 1 avec le champ fautif quand il est refusé, 2
sur une ligne de commande mal formée. --contract valide un autre document OpenAPI contre la même
configuration, à la place de contracts.openapi.
Elle rejoue exactement ce que fait le service au démarrage - même chargeur, mêmes
refus. Un validateur qui réimplémenterait les contrôles finirait par diverger de ce
qu'il valide. Une exception, voulue : une référence de secret ("${VAR}", file:/...) est
vérifiée dans sa forme, pas résolue - une chaîne d'intégration ne détient pas les secrets de
production. Une variable absente se découvre au démarrage, qui refuse de servir et la nomme.
Régler les délais. Trois budgets, avec des défauts qui conviennent à une API ordinaire - ne les écrire que pour s'en écarter :
server:
timeouts:
connect: 5s # établir la connexion amont
read: 60s # silence toléré entre deux octets - c'est lui, et lui seul, qui borne un flux
total: 30s # l'échange entier, reprises comprises
shutdown:
drain: 20s # au SIGTERM, temps laissé à ce qui est en coursLe plus précis gagne : server.timeouts.total, puis timeout sur l'amont, puis
x-flexway-timeout sur l'opération dans le contrat. Une recherche à 2s et un export à 120s
cohabitent ainsi sans relever le budget de tout le monde.
Vérif : une opération qui dépasse son budget répond 504 upstream_timeout à l'échéance,
pas à celle du client. Un flux SSE qui émet au moins une fois par read n'est jamais coupé,
quelle que soit sa durée.
Dire qui répond d'une opération, et quand elle sera retirée. Deux extensions du contrat, lues pour le catalogue de la console - jamais sur le chemin de la requête :
info:
title: Orders
version: "1.0.0"
x-flexway-owner: { team: orders-team, contact: "#orders" } # chaque opération en hérite
paths:
/v1/orders/{id}:
get:
operationId: getOrderV1
deprecated: true
x-flexway-sunset: "2027-06-30" # date de retrait : exige deprecated: true
x-flexway-owner: { team: legacy-team } # celle de l'opération gagneteam est obligatoire, contact facultatif ; 128 caractères chacun. Le contact est un canal
d'équipe (une liste, un salon, une page), jamais une personne : tout lecteur de la console le voit.
La date s'écrit AAAA-MM-JJ. En gRPC, dans l'option de la méthode :
rpc ListPayouts(Req) returns (Resp) {
option deprecated = true; // l'option native de Protobuf, lue comme deprecated
option (flexway.v1.operation) = { owner: { team: "payments-team" } sunset: "2027-03-01" };
}Vérif : flexway validate refuse une date sans dépréciation (is set on an operation that is not deprecated),
une date mal écrite, un owner sans team ou avec une clé inconnue ; le /config
d'administration publie owner et sunset dans catalog. Une opération sans propriétaire se charge :
c'est la conformité du catalogue qui la signale. Les en-têtes Sunset et Deprecation vers les
appelants viendront avec un change suivant.
Disponible depuis 1.2.0.