06 — Response di fallimento T4MED (OperationOutcome)¶
Flussi coperti: A, B, C, D, E, F, G, H
| Flusso | Operazione |
|---|---|
| A | Inserimento nuova prenotazione — POST {base-url} (Bundle transaction) |
| B | Aggiornamento prenotazione — PUT /Appointment/{id} |
| C | Cancellazione prenotazione — DELETE /Appointment/{id} |
| D | Download PDF dati monitoraggio — POST /Patient/{cfisc}/$generate-pdf |
| E | Upload nuovo referto firmato (v1) — POST {base-url} (Bundle transaction) |
| F | Upload referto sostitutivo (v>1) — POST {base-url} (Bundle transaction) |
| G | Annullamento referto — PUT /DocumentReference/{id} |
| H | Aggiornamento dei soli metadati — PUT /DocumentReference/{id} |
Per ognuno dei flussi sopra, le specifiche T4MED indicano solo la response "corretta" (200 OK/201 Created con il body di successo). Questo documento definisce il formato della response di FALLIMENTO, valido per tutti e 8 i flussi. Il Flusso D prevede inoltre un caso speciale non di errore (204 No Content — nessun dato clinico disponibile), descritto nella sezione 2.4.
1 — Formato unico di risposta di fallimento: OperationOutcome (FHIR R4)¶
Lo standard FHIR R4 prevede un solo formato per le risposte di errore, indipendentemente dal tipo di operazione (CRUD su singola risorsa, Bundle transaction, o $operation custom): la risorsa OperationOutcome.
- Restituita come body JSON con
Content-Type: application/fhir+json - Accompagnata da uno status HTTP nel range 4xx (errore client) o 5xx (errore server)
- Struttura sempre identica, qualunque sia il flusso (A–H)
Questo significa che gt4medServices può implementare un solo parser per le risposte di errore di T4MED, da riusare su tutte le chiamate (Appointment, $generate-pdf, Bundle transaction).
1.1 — Struttura generale¶
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "fatal | error | warning | information",
"code": "<IssueType FHIR R4>",
"details": {
"coding": [
{
"system": "<eventuale codice errore proprietario T4MED>",
"code": "<codice-errore>",
"display": "<descrizione breve>"
}
],
"text": "<messaggio leggibile per log/diagnostica>"
},
"diagnostics": "<dettaglio tecnico, es. id transazione>",
"expression": [ "<path FHIRPath dell'elemento che ha causato l'errore>" ]
}
]
}
Campi:
| Campo | Significato |
|---|---|
severity |
gravità (error/fatal bloccano l'operazione; warning/information possono accompagnare anche risposte 200 OK, ma per i flussi A-H si considerano solo errori bloccanti) |
code |
valore dal valueset FHIR R4 IssueType (vedi tabella 1.2) |
details |
codice/testo descrittivo — eventuale codice errore specifico T4MED da mappare |
diagnostics |
testo libero, utile per il logging interno di gt4medServices |
expression |
path dell'elemento del payload che ha causato l'errore (utile per Flussi A/E con Bundle multi-risorsa) |
Nota: l'array
issuepuò contenere più elementi (es. più errori di validazione contemporanei su un Bundle). gt4medServices deve iterare su tutti gli elementi, non solo sul primo.
1.2 — Codici HTTP e IssueType più rilevanti per gt4medServices¶
| HTTP Status | IssueType code | Significato tipico |
|---|---|---|
| 400 Bad Request | invalid, structure |
Bundle/risorsa non valida, JSON malformato / schema errato |
| 400 Bad Request | required |
campo obbligatorio mancante |
| 400 Bad Request | value |
valore di un campo non valido |
| 400 Bad Request | code-invalid |
codice da terminologia non valido (es. ASL/STS11/prestazione) |
| 401 Unauthorized | login |
header X-API-Key mancante o non valido |
| 403 Forbidden | forbidden |
X-API-Key valida ma IP non autorizzato, o scope insufficiente |
| 404 Not Found | not-found |
Appointment/Patient/DocumentReference/{id} inesistente |
| 405 Method Not Allowed | not-supported |
Operazione/verbo HTTP non supportato su questo endpoint |
| 409 Conflict | conflict |
Conflitto di stato (es. doppia prenotazione, Appointment già cancellato/concluso) |
| 409 Conflict | duplicate |
Risorsa duplicata (es. identifier già esistente) |
| 422 Unprocessable Entity | business-rule |
Regola di business violata (es. data fine < data inizio, paziente non trovato per CF) |
| 429 Too Many Requests | throttled |
Rate limit superato |
| 500/502/503/504 | exception, timeout, transient |
Errore interno T4MED / timeout / servizio non disponibile / errore transitorio (riprovabile) |
Nota: l'elenco esatto dei codici HTTP/IssueType effettivamente restituiti da T4MED non è stato dettagliato in fase di specifica. La tabella sopra rappresenta il mapping standard FHIR R4 e copre gli scenari più probabili per ciascun flusso.
1.3 — Bundle transaction (Flussi A, E ed F): tutto-o-niente¶
Per i Flussi A, E ed F (POST {base-url} con Bundle transaction), lo standard FHIR R4 prevede che, in caso di fallimento di una qualsiasi entry del Bundle, il server:
- annulli l'intera transazione (atomicità — nessuna risorsa viene creata, incluso un eventuale
Patientcensito nella stessa transazione) - non restituisca un Bundle
transaction-responseparziale - restituisca un singolo
OperationOutcomecon status HTTP 4xx/5xx
Questo è coerente con il formato unico definito al punto 1.1: anche per gli endpoint Bundle, l'errore non è "un Bundle con entry in errore" ma una risposta OperationOutcome a sé stante.
2 — Esempi per flusso¶
Per ogni flusso viene fornito un esempio di risposta di fallimento realistico, basato sui dati del caso già usati negli altri documenti (Paziente ROSAVIOLA DALMINA, CF RSVDMN11A41H620X, T4MED Appt.ID T00450).
2.1 — Flusso A — Inserimento nuova prenotazione (POST {base-url}, Bundle transaction)¶
Esempio 1 — campo obbligatorio mancante (end assente in Appointment)
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "required",
"details": {
"text": "Appointment.end e' un campo obbligatorio e non e' presente"
},
"diagnostics": "Bundle entry[2] (Appointment) - validazione fallita",
"expression": [ "Bundle.entry[2].resource.end" ]
}
]
}
AZIONE gt4medServices:
- Non salvare alcuna mappatura CUP↔T4MED (transazione annullata — vedi 1.3).
- Loggare l'errore con il riferimento alla prenotazione CUP (
26B001956). - Applicare la strategia di retry (max 3 tentativi, 5s di distanza, timeout 60s — vedi 05-vincoli-e-eccezioni.md) solo se il codice è
transient/timeout/5xx; un 400requiredè un errore permanente: non va ritentato, va segnalato per intervento manuale (vedi Eccezione A2).
Esempio 2 — identificativo prenotazione duplicato
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "duplicate",
"details": {
"text": "Esiste gia' un Appointment con identifier urn:local:cup:id-prenotazione|26B001956"
},
"diagnostics": "Bundle entry[2] (Appointment) - identifier duplicato",
"expression": [ "Bundle.entry[2].resource.identifier" ]
}
]
}
2.2 — Flusso B — Aggiornamento prenotazione (PUT /Appointment/{id})¶
Esempio — Appointment non trovato (T00450 non esiste su T4MED)
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "not-found",
"details": {
"text": "Nessuna risorsa Appointment trovata con id 'T00450'"
},
"diagnostics": "PUT /Appointment/T00450"
}
]
}
AZIONE gt4medServices:
- La mappatura interna (
26B001956 → T00450) punta a una risorsa che non esiste più su T4MED (possibile disallineamento, vedi Eccezione B1). - Non ritentare con lo stesso ID: segnalare il disallineamento per verifica (eventualmente proporre un re-inserimento con il Flusso A).
2.3 — Flusso C — Cancellazione prenotazione (DELETE /Appointment/{id})¶
Esempio — Appointment già concluso, non cancellabile
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "conflict",
"details": {
"text": "L'Appointment 'T00450' e' nello stato 'fulfilled' e non puo' essere cancellato"
},
"diagnostics": "DELETE /Appointment/T00450"
}
]
}
AZIONE gt4medServices:
- Su 409
conflict: non ritentare, segnalare (vedi Eccezione C1).
2.4 — Flusso D — Download PDF dati monitoraggio (POST /Patient/{cfisc}/$generate-pdf)¶
Nota: anche se la risposta di SUCCESSO è uno stream binario (
Content-Type: application/pdf), la risposta di FALLIMENTO resta comunque unOperationOutcomeinapplication/fhir+json— comportamento standard per le$operationFHIR R4: l'output dichiarato (PDF) viene restituito solo in caso di esito positivo.A seguito dei test di integrazione, l'operazione
$generate-pdfrichiede obbligatoriamente anche il parametroT4MedAppointmentId(oltre aDateFrom/DateTo), usato per limitare il telemonitoraggio restituito alla specifica prenotazione. Vedi samples/flusso-d-download-referto.md.
Esempio 1 — Patient non trovato
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "not-found",
"details": {
"text": "Nessuna risorsa Patient trovata con id 'RSVDMN11A41H620X'"
},
"diagnostics": "POST /Patient/RSVDMN11A41H620X/$generate-pdf"
}
]
}
Esempio 2 — intervallo date non valido (DateFrom successivo a DateTo)
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "business-rule",
"details": {
"text": "Il parametro 'DateFrom' e' successivo al parametro 'DateTo'"
},
"diagnostics": "POST /Patient/RSVDMN11A41H620X/$generate-pdf",
"expression": [ "Parameters.parameter.where(name='DateFrom').value" ]
}
]
}
Esempio 3 — Appointment inesistente (T4MedAppointmentId non trovato)
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "not-found",
"details": {
"text": "Nessun Appointment trovato con id '9999'"
},
"diagnostics": "POST /Patient/RSVDMN11A41H620X/$generate-pdf",
"expression": [ "Parameters.parameter.where(name='T4MedAppointmentId').value" ]
}
]
}
Esempio 4 — Appointment appartenente ad altro paziente
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "business-rule",
"details": {
"text": "L'Appointment con id '2436' non e' associato al Patient 'RSVDMN11A41H620X'"
},
"diagnostics": "POST /Patient/RSVDMN11A41H620X/$generate-pdf",
"expression": [ "Parameters.parameter.where(name='T4MedAppointmentId').value" ]
}
]
}
AZIONE gt4medServices:
- Su errore in questa fase, il merge PDF (MEDWARE + T4MED) non può essere completato: gt4medServices restituisce a gefidServices il solo referto MEDWARE, senza l'allegato dei dati di monitoraggio T4MED. gefidServices procede comunque con la firma digitale del referto — lo stesso comportamento del caso
204 No Contentdescritto di seguito. Vedi la nota sui timeout nei flussi interattivi in 05-vincoli-e-eccezioni.md.
Caso speciale — nessun dato clinico disponibile: se paziente e parametri sono corretti ma nel periodo richiesto non esistono schede di telemonitoraggio, T4MED risponde 204 No Content (senza body). Non è un errore: non si effettua il merge PDF, viene pubblicato esclusivamente il referto MEDWARE, e il flusso di firma prosegue regolarmente. Vedi samples/flusso-d-download-referto.md.
2.5 — Flusso E — Upload nuovo referto firmato, v1 (POST {base-url}, Bundle transaction)¶
Esempio 1 — DocumentReference.identifier (UniqueDocumentId) assente
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "required",
"details": {
"text": "DocumentReference.identifier (UniqueDocumentId del referto) e' obbligatorio"
},
"diagnostics": "Bundle entry[1] (DocumentReference) - validazione fallita",
"expression": [ "Bundle.entry[1].resource.identifier" ]
}
]
}
Esempio 2 — paziente non trovato per il codice fiscale indicato in subject
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "business-rule",
"details": {
"text": "Nessun Patient trovato con id 'RSVDMN11A41H620X'"
},
"diagnostics": "Bundle entry[1] (DocumentReference) - subject non risolvibile",
"expression": [ "Bundle.entry[1].resource.subject" ]
}
]
}
AZIONE gt4medServices:
- Transazione annullata: né
BinarynéDocumentReferencevengono creati su T4MED. - Il referto firmato risulterà pubblicato su REPOSITORY/FSE ma non su T4MED (vedi Eccezione E2): da segnalare per allineamento manuale.
2.6 — Flusso F — Upload referto sostitutivo, v>1 (POST {base-url}, Bundle transaction)¶
Gli scenari di errore sono gli stessi del Flusso E (campo obbligatorio mancante, paziente non trovato), con l'aggiunta del seguente scenario specifico, dovuto alla presenza di relatesTo.target:
Documento originale (relatesTo.target) non trovato
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "not-found",
"details": {
"text": "Nessuna risorsa DocumentReference trovata con id '<id-t4med-del-documento-originale>'"
},
"diagnostics": "Bundle entry[1] (DocumentReference) - relatesTo.target non risolvibile",
"expression": [ "Bundle.entry[1].resource.relatesTo[0].target" ]
}
]
}
AZIONE gt4medServices: come per il Flusso E — transazione annullata (atomicità, vedi 1.3); segnalare per allineamento manuale (Eccezione E2).
2.7 — Flusso G — Annullamento referto (PUT /DocumentReference/{id})¶
Esempio 1 — DocumentReference originale non trovato
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "not-found",
"details": {
"text": "Nessuna risorsa DocumentReference trovata con id '<id-t4med-del-documento-originale>'"
},
"diagnostics": "PUT /DocumentReference/<id-t4med-del-documento-originale>"
}
]
}
Esempio 2 — documento già annullato (status già entered-in-error)
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "conflict",
"details": {
"text": "Il DocumentReference '<id-t4med-del-documento-originale>' e' gia' nello stato 'entered-in-error'"
},
"diagnostics": "PUT /DocumentReference/<id-t4med-del-documento-originale>"
}
]
}
AZIONE gt4medServices: su 404/409 non ritentare (PUT non è una Bundle transaction, ma l'esito è comunque definitivo); segnalare il disallineamento per verifica (Eccezione E2) — il referto risulterà annullato su REPO/FSE ma non correttamente riflesso su T4MED.
2.8 — Flusso H — Aggiornamento dei soli metadati (PUT /DocumentReference/{id})¶
Stesso endpoint del Flusso G; gli scenari di errore sono analoghi.
Esempio 1 — DocumentReference originale non trovato
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "not-found",
"details": {
"text": "Nessuna risorsa DocumentReference trovata con id '<id-DocumentReference>'"
},
"diagnostics": "PUT /DocumentReference/<id-DocumentReference>"
}
]
}
Esempio 2 — documento già annullato (status già entered-in-error), non aggiornabile
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "conflict",
"details": {
"text": "Il DocumentReference '<id-DocumentReference>' e' nello stato 'entered-in-error' e non puo' essere aggiornato"
},
"diagnostics": "PUT /DocumentReference/<id-DocumentReference>"
}
]
}
AZIONE gt4medServices: su 404/409 non ritentare; segnalare il disallineamento per verifica (Eccezione E2) — il metadato risulterà aggiornato lato SINED ma non correttamente riflesso su T4MED.
3 — Riepilogo¶
| Flusso | Operazione | Errori più probabili (HTTP) |
|---|---|---|
| A | POST {base-url} (Bundle) |
400, 409, 422 |
| B | PUT /Appointment/{id} |
400, 404, 409 |
| C | DELETE /Appointment/{id} |
404, 409 |
| D | POST /Patient/{cfisc}/$generate-pdf |
404, 422 (204 No Content = caso speciale, non errore) |
| E | POST {base-url} (Bundle) |
400, 422, 409 |
| F | POST {base-url} (Bundle) |
400, 404, 422, 409 |
| G | PUT /DocumentReference/{id} |
404, 409 |
| H | PUT /DocumentReference/{id} |
404, 409 |
In tutti i casi: stesso resourceType (OperationOutcome), stesso Content-Type (application/fhir+json), stesso array issue[]. gt4medServices può quindi implementare un unico componente di parsing delle risposte di errore, condiviso da tutti e 8 i flussi, e instradare il comportamento (retry, fallback, segnalazione) in base alla coppia (HTTP status, issue[].code).
Punti non ancora confermati nel dettaglio: l'eventuale presenza di codici di errore applicativi T4MED in
issue[].details.coding(vedi placeholder in 1.1), e i codici HTTP esatti restituiti per ciascuno scenario di errore della tabella 1.2. La strutturaOperationOutcome(FHIR R4) è invece confermata come formato di riferimento per tutte le risposte di fallimento.
4 — Significato degli HTTP status code¶
Riferimento generale HTTP/REST, applicabile a tutti i flussi (A-H).
4.1 — 400 Bad Request¶
La richiesta ricevuta dal server non è formalmente valida.
Cause tipiche: JSON non valido; Bundle FHIR malformato; campi obbligatori mancanti; formato di data non corretto; identificativi non valorizzati; errori di sintassi nella richiesta.
4.2 — 401 Unauthorized¶
L'header X-API-Key è mancante o non valido.
4.3 — 403 Forbidden¶
L'X-API-Key è valida ma la richiesta proviene da un IP non autorizzato, oppure lo scope associato alla chiave non consente l'operazione richiesta.
4.4 — 404 Not Found¶
La risorsa richiesta non esiste oppure non è stata trovata.
Cause tipiche: Appointment inesistente; Patient inesistente; DocumentReference inesistente; identificativo errato; risorsa già cancellata.
Esempio: PUT /Appointment/12345 quando l'appuntamento 12345 non è presente nel sistema.
4.5 — 405 Method Not Allowed¶
L'endpoint esiste ma il metodo HTTP utilizzato non è consentito su quell'endpoint.
4.6 — 409 Conflict¶
La richiesta è formalmente corretta ma entra in conflitto con lo stato corrente delle informazioni presenti nel sistema.
Cause tipiche: appuntamento già esistente; prenotazione già cancellata; modifica concorrente da parte di un altro operatore; versione della risorsa non più aggiornata; referto già acquisito; duplicazione di identificativi univoci.
Esempio: creazione di una prenotazione già presente nel sistema.
4.7 — 422 Unprocessable Entity¶
La richiesta è formalmente valida ma non supera i controlli funzionali o le regole di business.
Cause tipiche: dati clinici incoerenti; paziente non eleggibile; appuntamento non modificabile; documento non conforme; referto privo dei requisiti previsti; regole applicative non soddisfatte.
Esempio: richiesta di prenotazione valida dal punto di vista sintattico ma riferita ad una prestazione non consentita.
4.8 — 500 Internal Server Error¶
Errore interno del sistema (eccezione non gestita, errore applicativo, errore di configurazione, database non disponibile, servizio esterno non raggiungibile). Il client generalmente non può correggere autonomamente il problema.
4.9 — 503 Service Unavailable¶
Servizio temporaneamente non disponibile (manutenzione, sovraccarico, dipendenza esterna non raggiungibile, timeout infrastrutturale). Normalmente il client può riprovare l'operazione successivamente.