ApiBorne
Sommaire du guide

vendorData

Chaque réponse peut inclure des objets vendorData (au niveau réponse, patient ou appointment). La borne ne les lit jamais : elle mémorise chacun sous l'id de l'entité qui le porte, et le renvoie inchangé sur les appels suivants visant cette entité.

Principe du round-trip

Vous posez un objet opaque sur une entité de votre réponse — ici un sur le patient, un sur le RDV :

votre réponse à identify
{
  "patients": [
    {
      "patient": {
        "id": "pat-77",
        "firstName": "Marie", "lastName": "Durand",
        "vendorData": { "patientKey": 77, "shard": "eu-1" }
      },
      "appointments": [
        {
          "id": "apt-1001", "examLabel": "IRM lombaire",
          "vendorData": { "appointmentKey": 1001 }
        }
      ]
    }
  ]
}

La borne le restitue tel quel dans context.vendorData des appels suivants qui visent la même entité :

appel suivant de la borne
PATCH /patients/pat-77
{
  "context": {
    "locationId": "loc-42",
    "vendorData": { "patientKey": 77, "shard": "eu-1" }   // ← celui de pat-77, tel quel
  },
  "patient": { "mobilePhone": "+33612345678" }
}

La clé : vos propres ids

Il n'y a pas de « clé de session » à définir : la clé de mémorisation est l'id contrat de l'entité, c'est-à-dire le patient.id ou l'appointment.id que vous avez renvoyé. La borne tient une table id d'entité → vendorData : quand une réponse porte un vendorData sur pat-77, elle enregistre (ou remplace) l'entrée pat-77 ; quand elle appelle une route qui concerne pat-77, elle joint cette entrée — et uniquement celle-là.

Le contenu de l'objet est entièrement libre et défini par vous (ids de base internes, clé de partition, jeton…) : la borne ne l'interprète jamais, elle ne fait que le ranger sous votre id et le ressortir.

Quel vendorData sur quel appel

  • POST /patients/identify — jamais de vendorData : c'est le premier appel, la borne n'a encore rien à restituer ;
  • PATCH /patients/{patientId} — le vendorData du patient visé ;
  • toutes les routes /appointments/{appointmentId}/… (documents, upload, prescripteur, readiness, check-in) — le vendorData du RDV visé ;
  • un vendorData au niveau réponse (ex. réponse de check-in) est mémorisé sous l'id de l'entité que l'appel concernait — même logique.

Pourquoi deux accueils ne se mélangent pas

Un nouvel accueil recommence toujours par une identification : les réponses portent les entités du nouveau patient, avec leurs propres ids — donc leurs propres entrées dans la table. Les appels du parcours ne visent que ces ids-là : le vendorData d'un autre patient ne peut structurellement pas être joint, puisque la clé est l'id de l'entité visée, pas une session.

Et si le même patient repasse ? Même id → même entrée, et chaque réponse qui porte un vendorData remplace la valeur mémorisée (dernier écrit gagne) : la valeur jointe est donc toujours la plus récente que vous ayez servie pour cette entité.

Séquence sur deux accueils : la borne mémorise chaque vendorData sous l'id de l'entité qui le porte (pat-77, apt-1001, puis pat-88) et ne renvoie jamais que celui de l'entité visée par l'appel.Borne ApiBornemémoire par id d'entitéVotre serveurAccueil n°1POST /patients/identifypremier appel : pas encore de vendorDatapatient pat-77 + RDV apt-1001, chacun avec son vendorDatamémorise vendorData[pat-77] et vendorData[apt-1001]PATCH /patients/pat-77context.vendorData = celui de pat-77POST /appointments/apt-1001/check-incontext.vendorData = celui d'apt-1001Accueil n°2 — un autre patientPOST /patients/identifypatient pat-88 avec son vendorDataPATCH /patients/pat-88context.vendorData = celui de pat-88 — jamais celui de pat-77la clé, c'est l'id — pas la session
La clé de mémorisation est VOTRE id (patient.id / appointment.id). Un autre patient = d'autres ids = d'autres entrées : aucun croisement possible entre accueils.

Règles et limites

  • Opaque : la borne ne lit ni ne modifie jamais le contenu ;
  • Taille : moins de 4 Ko sérialisé par objet ;
  • Pas de secret : l'objet transite par le navigateur de la borne — n'y mettez rien de sensible (pas de mot de passe, pas de clé d'API) ;
  • Optimisation, pas un canal d'état : la mémoire vit avec la session de l'application borne (elle est vide après un redémarrage). Vos routes DOIVENT fonctionner sans context.vendorData — servez-vous-en pour éviter une résolution d'identifiants, jamais comme unique porteur d'un état indispensable ;
  • Mécanisme d'extension officiel : tout besoin propriétaire passe par vendorData, jamais par une modification de la spec.

Dans l'implémentation de référence, le pattern est visible dans src/server/contract/mappers.ts (les ids SQLite internes voyagent en vendorData).