lumnik. / scénarios Tous les scénarios · English

Une appli Spring derrière un proxy garde chaque produit sous son SKU

Objectif Lire tout le stock d'une application Spring Data REST maison, page par page, et garder chaque produit sous son SKU, quel que soit l'hôte par lequel on l'atteint.

Un ancien prestataire a laissé une application de stock en Spring Data REST, derrière nginx. lumnik la lit avec le preset spring-hateoas:

manifests/lab-docker-compose.yml
# The stock application of an earlier provider: Spring Data REST behind nginx.name: lumnik-spring-inventoryservices:  inventory:    build: ../run/inventory-app    environment:      # none: Spring builds its links from the host nginx called, inventory:8080.      # framework: it reads X-Forwarded-Host, the host the caller used — the one-line fix.      SERVER_FORWARD_HEADERS_STRATEGY: ${FORWARD_HEADERS:-none}  proxy:    image: nginx:1.27-alpine    ports: ["127.0.0.1:${INVENTORY_PORT:-9230}:80"]   # this machine only    volumes: ["./lab-nginx.conf:/etc/nginx/conf.d/default.conf:ro"]    depends_on: [inventory]
manifests/lab-nginx.conf
# The in-house reverse proxy: it forwards the caller's host, as most do.server {  listen 80;  location / {    proxy_pass http://inventory:8080;    proxy_set_header X-Forwarded-Host $http_host;    proxy_set_header X-Forwarded-Proto $scheme;  }}
manifests/10-inventory.yaml
apiVersion: connectors.lumnik.io/v1kind: Connectormetadata:  name: scenario-inventory-a  connector_type: rest-generic  scopes: [inventory]spec:  base_url: http://host.docker.internal:9230  endpoints:    - id: products      path: /products      method: GET      pagination: { kind: spring-hateoas, items: products, total_path: $.page.totalElements }      target:        kind: hybrid        table: ext.scenario_inventory_a        unique_key: { path: $._links.self.href, transform: last_path_segment }        promote:          - { name: sku, path: $._links.self.href, transform: last_path_segment, type: text }          - { name: name, path: $.name, type: text }          - { name: warehouse, path: $.warehouse, type: text }          - { name: stock, path: $.stock, type: integer }
$ lm connector run scenario-inventory-a
run scheduled: f309dd90-1100-48b5-80ba-8fd11a8d9c33

$ lm run get f309dd90-1100-48b5-80ba-8fd11a8d9c33
ID        CONNECTOR             ENDPOINT  STATUS  IN  OUT  SKIPPED  DEAD-LETTERS  STARTED           ENDED             EVALUATED
f309dd90  scenario-inventory-a  products  Failed  0   0    0        0             2026-10-30 13:51  2026-10-30 13:51  yes
✖ run failed: Refusing to follow pagination URL 'http://inventory:8080/products': host 'inventory' differs from the connector's host 'host.docker.internal'
$ lm connector run scenario-inventory-a
run scheduled: 2506d359-e048-4183-9d39-baa67e3f95bb

$ lm run get 2506d359-e048-4183-9d39-baa67e3f95bb
ID        CONNECTOR             ENDPOINT  STATUS     IN    OUT   SKIPPED  DEAD-LETTERS  STARTED           ENDED             EVALUATED
2506d359  scenario-inventory-a  products  Completed  1250  1250  0        0             2026-10-30 13:51  2026-10-30 13:51  yes
$ lm connector run scenario-inventory-a
run scheduled: 5b925538-5a8c-4f67-9478-0bed9ecae001

$ lm run get 5b925538-5a8c-4f67-9478-0bed9ecae001
ID        CONNECTOR             ENDPOINT  STATUS     IN    OUT   SKIPPED  DEAD-LETTERS  STARTED           ENDED             EVALUATED
5b925538  scenario-inventory-a  products  Completed  1250  1250  0        0             2026-10-30 13:51  2026-10-30 13:51  yes

Limites

  • La clé est le dernier segment du lien: le lien doit finir par l'identifiant, comme Spring Data REST le fait par défaut.
  • Un produit dont le lien n'a pas de segment fait échouer le run, en nommant la clé.
  • Le refus de l'hôte interne demande une correction côté application ou proxy: lumnik ne réécrit pas les liens.
  • Application Spring de démonstration, données synthétiques.

Intégration · application maison

Une appli de stock en Spring, laissée par un ancien prestataire.

Il faut lire tout le stock, chaque nuit.

Application et données de démonstration

Le problème

L'API ne donne pas l'identifiant.

  • Le SKU n'est que dans le lien de chaque produit.
  • Les liens pointent vers le nom interne du serveur.

Ce qui n'est pas modifié

Le code de l'application reste tel quel.

  • Une propriété de déploiement: faire confiance au proxy.
  • Aucun champ ajouté à l'API.

Ce qu'il a fallu écrire

pagination: { kind: spring-hateoas, items: products }
unique_key: { path: $._links.self.href,
              transform: last_path_segment }

On nomme le framework, on dit où est la clé.

Un connecteur de 24 lignes.

Le rouge

Page 2 vers inventory:8080: le run refuse.

  • Il nomme l'hôte interne.
  • Aucune liste partielle annoncée verte.

Le vert

1250 produits, 63 pages, rangés sous leur SKU.

  • La nuit suivante: 1250 lignes, 1250 clés.
  • Un passage en https ne changerait aucune clé.

La limite

Le lien doit finir par l'identifiant.

  • C'est le cas par défaut avec Spring Data REST.
  • Un lien sans segment fait échouer le run, en nommant la clé.

Essayer

Le scénario se rejoue en local.

Une vraie application Spring Boot, un vrai nginx, chaque étape publiée avec sa sortie.

Ce scénario tourne sur lumnik Open, gratuit et open source.

Essayer lumnik Open →