Zielstellung

Teilnehmende an der Antibiotika Resistenz Surveillance (ARS) können mit dem Feature Bulk-Upload große Mengen von retrospektiven Sendungen übermitteln. Für solche großen Datenmengen sollte nicht der ARS-Endpunkt für den synchronen Normalbetrieb genutzt werden, da dieser über ein striktes Rate Limiting verfügt und die Verarbeitung der Sendungen synchron erfolgt, so dass bei zahlreichen Sendungen mit einer großen Dauer des Uploads zu rechnen ist. Nachfolgend werden die Schnittstellen für den ARS-Bulk-Upload beschrieben.

Vorbereitung


Übersicht des Ablaufs

@startuml

hide footbox

<style>
  sequenceDiagram {
   
    Padding: 100;
    MinimumWidth: 150;
    LineColor: #010E52;
    RoundCorner: 20;
    participant {
      FontColor: white;
      FontSize: 14;
      FontStyle: bold;
      BackgroundColor: #010E52;
    }
    arrow {
      FontColor: #010E52;
      LineColor: #010E52;
    }
    note {
      LineColor: #010E52;
      FontColor: #010E52;
      FontStyle: bold;
      RoundCorner: 0;
    }
  }
</style>

participant "\nPrimary System\n" as PS
participant "\nARS Batch Service\n" as ARS

PS -> ARS: ""POST …/batch/bundle""
ARS --> PS: ""201 CREATED""\n ""Bundle.link.url: …/batch/upload/<UUID>""

|||

loop until all parcels are sent
  PS -> ARS: ""POST …/batch/upload/<UUID>""
  ARS --> PS: ""200 OK""
end
 

|||

PS -> ARS: ""POST ../batch/fhir/bundle/<UUID>/$close""
ARS --> PS: ""202 Accepted""\n""Content-Location: ../batch/fhir/bundle/<UUID>/$statistics""

PS -> PS: wait retry afer time

|||

loop until 200 OK
  PS -> ARS:  ""GET ../batch/fhir/bundle/<UUID>/$statistics""
  ARS --> PS: ""202 Accepted""

  PS -> PS: wait retry afer time
end

|||

PS -> ARS:  ""GET ../batch/fhir/bundle/<UUID>/$statistics""
ARS --> PS: ""200 OK""

PS -> ARS:  ""GET ../batch/fhir/bundle/<UUID>/$results?query=success""
ARS --> PS: ""200 OK""

PS -> ARS:  ""GET ../batch/fhir/bundle/<UUID>/$results?query=error""
ARS --> PS: ""200 OK""


@enduml

Übersicht Endpunkte

UmgebungBasis-URL
Produktion
https://demis.rki.de/surveillance/antibiotic-resistance/
Test / Integration
Informationen: Endpunkte, Zertifikate, User und Passwort


TypeRoute
POST/v1/batch/fhir/bundle
POST/v1/batch/upload/{batchId}
POST/v1/batch/fhir/bundle/{batchId}/$close
GET/v1/batch/fhir/bundle/{batchId}/$statistics
GET/v1/batch/fhir/bundle/{batchId}/$results
POST/v1/fhir/$process-notification (für ARS - Upload der Sendungen (synchron))

Bitte beachten Sie, dass v1 als Schnittstellenversion für jeden Request verwendet werden muss.

Verarbeitungsschritte

Schritt 1: Erzeugung eines leeren Batch Bundles zum Start des Bulk Uploads

Zunächst wird ein neuer Batch Job angelegt. Das erfolgt über eine FHIR create Operation durch Senden eines leeren Batch Bundles, d.h. ohne Entries.

POST /surveillance/antibiotic-resistance/v1/batch/fhir/bundle
Content-Type: application/fhir+json

{
  "resourceType" : "Bundle",
  "type" : "batch"
}


Der ARS-Bulk-Service antwortet mit dem erzeugten Batch Bundle, welches die Id des Jobs als Id der Bundle Ressource enthält. Unter Bundle.link.url findet der Client die URL des Endpunktes an den die ARS-Sendungen übertragen werden müssen.

HTTP/1.1 201 Created

{
  "resourceType" : "Bundle",
  "id": 42,
  "meta" : {
    "lastUpdated" : "2025-11-18T01:45:30Z"
  },
  "relation" : "batch",
  "link": {
     "relation": "edit", 
      "url": "https://demis.rki.de/surveillance/antibiotic-resistance/v1/batch/upload/<UUID>"
  }
}

Achtung: Batches werden, wenn sie nicht geschlossen wurden, für eine Dauer von 14 Tagen offen gehalten und stehen anschließend nicht mehr zur Verfügung.

Schritt 2: Hinzufügen der ARS Sendungen zum Job

Danach werden zyklisch die ARS Sendungen übertragen. Das erfolgt durch einen POST-Request, welcher die ARS-Sendungen als ndjson beinhaltet. Je Request können Sendungen bis zu einer maximalen Request-Größe von 10 MB übertragen werden.

Bitte verwenden Sie hierfür unverändert die gleiche FHIR-Struktur, die Sie auch für die synchrone Schnitstelle verwenden. Wandeln Sie diese jedoch in ein ndjson um.

Für den Fall, dass ein HTTP-Request nicht (vollständig) verarbeitet werden kann ist es notwendig die Notification-Bundle-IDs im HTTP-Header zu übertragen. Die Reihenfolge der IDs im Header muss dabei mit der Reihenfolge der IDs der Sendungen in der FHIR-Ressource übereinstimmen. Falls beispielsweise Sendungen von der WAF abgelehnt werden oder einzelne Sendungen nicht valide gemäß FHIR-Profil sind werden diese IDs gemeinsam mit einer kurzen Erklärung des aufgetretenen Fehlers in der Ergebnis-Statistik verauskunftet.

Umsetzungshinweis: HTTP-Requests in DEMIS haben eine maximale Größe von 10 MB. Wir empfehlen jeweils fünf Sendungen pro HTTP-Request in einem Bundle zu übertragen. Sollte der ARS-Dienst mit einem HTTP Status Code 413 "Payload Too Large" oder 431 "Request Header Fields Too Large" antworten, dann bitte die Sendungen einzeln übertragen.

Request:

POST /surveillance/antibiotic-resistance/v1/batch/upload/<UUID>
Content-Type: application/fhir+ndjson
X-Document-Ids: EC857E2C-4863-436E-82AF-6E7F6A9307CE,08E73CB0-AA5A-4A02-85A4-CD8D7B8C2EB5,...

{"resource": {"resourceType": "Bundle","id": "90F0F3A5-4D36-4AD1-8D2E-1879887F4468","meta": {"profile": ["https://demis.rki.de/fhir/ars/StructureDefinition/Bundle"]},"type": "document", ... \n
{"resource": {"resourceType": "Bundle","id": "3f1ae7ab-9c21-4619-b9b9-0e746edc6eab","meta": {"profile": ["https://demis.rki.de/fhir/ars/StructureDefinition/Bundle"]},"type": "document", ... \n
{"resource": {"resourceType": "Bundle","id": "4cc94192-70e4-49b6-81b2-67e4031246e6","meta": {"profile": ["https://demis.rki.de/fhir/ars/StructureDefinition/Bundle"]},"type": "document", ... \n
{"resource": {"resourceType": "Bundle","id": "7625a51c-48bb-47c2-b37c-574d3621ec5f","meta": {"profile": ["https://demis.rki.de/fhir/ars/StructureDefinition/Bundle"]},"type": "document", ... \n
{"resource": {"resourceType": "Bundle","id": "fb22c8b0-6197-4709-b920-f92c5af1b2e8","meta": {"profile": ["https://demis.rki.de/fhir/ars/StructureDefinition/Bundle"]},"type": "document", ... \n


Im Erfolgsfall wird jeder dieser POST-Requests einfach mit HTTP-Status 202 OK beantwortet.

HTTP/1.1 202 OK

Fehlersituationen

UrsacheHTTP-Status-CodeBeschreibung
Ungültige Anzahl oder Format von Document-IDs im Header400 Bad Request

Die Anzahl der übertragenen Document-IDs im HTTP-Header X-Document-Ids stimmt nicht mit der Anzahl der ARS-Sendungen überein. Der Request ist zu korrigieren und erneut zu senden.

Es ist ein Fehler bei der internen Verarbeitung aufgetreten500 Internal Server Error

Eine oder mehrere Nachrichten konnten durch interne Fehler nicht verarbeitet werden. Der Request ist erneut zu senden. 

Im Fehlerfall kann es in der Statistik zu Duplikationen kommen. Dies kann ignoriert werden.

Schritt 3: Upload abschließen

Wurden alle ARS-Bundle-Sendungen übermittelt, wird der Batch-Upload abgeschlossen.

POST /surveillance/antibiotic-resistance/v1/batch/fhir/bundle/<UUID>/$close
Content-Type: application/fhir+json
Content-Length: 0

Der Content-Type ergibt fachlich an dieser Stelle keinen Sinn, ist jedoch aktuell technisch erforderlich. Wir werden dies zukünftig korrigieren.


Die Übertragung der Sendungen ist abgeschlossen, was durch den HTTP-Status 202 "Accepted" signalisiert wird. Die Response enthält im HTTP-Header Content-Location die URL des Endpunktes, über welche das Ergebnis des Batch Jobs abgerufen werden kann. Nach welcher Zeit zuerst das Ergebnis abgefragt werden sollte, steht im retry-after header.

HTTP/1.1 202 Accepted
Content-Location: https://demis.rki.de/surveillance/antibiotic-resistance/v1/batch/fhir/bundle/<UUID>/$statistics
retry-after: 300

Hinweise:

Schritt 4: Abfrage der Ergebnisse des Jobs

Die Ergebnisse des Batch Jobs können mittels GET-Request auf den Statistik-Endpunkt der Ressource abgefragt werden:

GET /surveillance/antibiotic-resistance/v1/batch/fhir/bundle/<UUID>/$statistics

Wenn der Job noch nicht abgeschlossen ist, wird weiterhin der HTTP-Status 202 Accepted zurück geliefert und ein Progress-Status. 

HTTP/1.1 202 Accepted
X-Total: 100000
X-Progress: 20%
Retry-After: 1800

Der Statistik-Endpunkt wird dann im Polling so oft aufgerufen bis das Ergebnis des Jobs zurück geliefert wird. Über den Header "Retry-After" wird der Client informiert, nach wie vielen Sekunden der nächste Request an den Statistik-Endpunkt gesendet werden sollte. Es ist zu beachten, dass ein grobes Missachten des Retry-After-Headers dazu führt, dass Anfragen an den Endpunkt abgelehnt werden. X-Total verauskunftet die Gesamtanzahl der Nachrichten im Batch. Der Header X-Progress gibt an, wie viel Prozent der Nachrichten bereits verarbeitet wurden.

GET /surveillance/antibiotic-resistance/v1/batch/fhir/bundle/<UUID>/$statistics

Wurden alle Sendungen des Batches verarbeitet, dann wird das Ergebnis als Ressource vom Typ Parameters mit HTTP-Status 200 OK zurück geliefert.

HTTP/1.1 200 OK

{
  "resourceType": "Parameters",
  "parameter": [
    { "name": "batchId", "valueString": "<UUID>" },
    { "name": "batchClosedAt", "valueDateTime": "2025-10-23T09:15:59Z" },
    { "name": "resultsAvailableUntil", "valueDateTime": "2025-10-24T09:15:59Z" },
    { "name": "total", "valueInteger": 1000000 },
    {
      "name": "success",
      "part": [
        { "name": "url", "valueUri": "https://[...]/surveillance/antibiotic-resistance/v1/batch/fhir/bundle/42/$results?query=success" },
        { "name": "contentType", "valueString": "text/csv" },
        { "name": "count", "valueInteger": 995000 }
      ]
    },
    {
      "name": "error",
      "part": [
        { "name": "url", "valueUri": "https://[...]/surveillance/antibiotic-resistance/v1/batch/fhir/bundle/42/$results?query=error" },
        { "name": "contentType", "valueString": "text/csv" },
        { "name": "count", "valueInteger": 5000 },
        {
          "name": "countsByErrorCode",
          "part": [
            { "name": "WAF", "valueInteger": 1500 },
            { "name": "VALIDATION", "valueInteger": 3200 },
            { "name": "INVALID", "valueInteger": 20 }, 
            { "name": "INTERNAL_ERROR", "valueInteger": 280 }
          ]
        }
      ]
    }
  ]
}

Das Ergebnis der Batch-Verarbeitung wird als Statistik zurückgegeben. Die IDs der Sendungen, die erfolgreich verarbeitet werden konnten, können über den Link in parameter.where(name = 'success').part.where(name = 'url').value als CSV heruntergeladen werden. Die Einzelergebnisse für die Sendungen, die nicht erfolgreich verarbeitet werden konnten, können über den Link in parameter.where(name = 'error').part.where(name = 'url').value abgerufen werden. Um Netzwerk-Bandbreite zu sparen sollen die Detail-Ergebnisse gzip-komprimiert abgefragt werden. Dazu ist der HTTP-Header Accept-Encoding mit dem Wert gzip zu setzen. Wenn der Header nicht gesendet wird, werden die Detail-Ergebnisse unkomprimiert übertragen.

GET /surveillance/antibiotic-resistance/v1/batch/fhir/bundle/<UUID>/$results?query=success
Accept-Encoding: gzip
Document id (Client);Document id (RKI);Validation warnings
8C6DAAAD-82F6-46BA-A0E6-078AAF04BA63;295afbb4-c975-4b65-b236-d735e39c9812;40
19FEA1D7-64DF-49A3-9DD6-889624C2FD6E;275192e7-5183-4a4c-b16d-c345f24e0d17;26
GET /surveillance/antibiotic-resistance/v1/batch/fhir/bundle/42/$results?query=error
Accept-Encoding: gzip
Document id (Client);Error reason;Validation errors;Validation warnings;Details
A427CB93-D739-4E21-A5A1-465F95C68D83;VALIDATION;1;53;
19FEA1D7-64DF-49A3-9DD6-889624C2FD6E;INVALID;;;INVALID_PSEUDONYMS
232CEB29-3667-4407-BA04-5161BB399BB7;WAF;;;
1F15D1E1-FE25-4346-BA8E-9BC0F1BC3CC9;VALIDATION;1;105;
40461B4C-54B5-4B0E-9D17-AFC7E15044C3;VALIDATION;1;40;
3C1A577C-B436-447F-BF43-FBADDD4EF872;WAF;;;