From e7382e66b00f579e42dca51c7724d370cc91bb49 Mon Sep 17 00:00:00 2001 From: Ole Kristian Losvik Date: Sat, 1 Aug 2026 18:18:43 +0100 Subject: [PATCH] Eng: Add Bruno collection for manual API exploration Requests for CRUD, search, history, $validate/$expand and the scoped maintenance/import operations, with environments for local and public targets. --- eng/bruno/Fhir/History/folder.bru | 4 ++ eng/bruno/Fhir/History/instance-history.bru | 20 +++++++ eng/bruno/Fhir/History/system-history.bru | 24 +++++++++ eng/bruno/Fhir/History/type-history.bru | 24 +++++++++ eng/bruno/Fhir/History/version-read.bru | 21 ++++++++ .../Fhir/Operations/everything-instance.bru | 15 ++++++ eng/bruno/Fhir/Operations/folder.bru | 4 ++ eng/bruno/Fhir/Operations/meta-read.bru | 25 +++++++++ .../create-encounter-invalid-status.bru | 35 ++++++++++++ .../Encounter/create-encounter-valid.bru | 43 +++++++++++++++ eng/bruno/Fhir/Resources/Encounter/folder.bru | 7 +++ .../create-observation-invalid-quantity.bru | 43 +++++++++++++++ .../create-observation-invalid-status.bru | 39 ++++++++++++++ .../Observation/create-observation-valid.bru | 49 +++++++++++++++++ .../Fhir/Resources/Observation/folder.bru | 7 +++ .../search-observations-for-patient.bru | 20 +++++++ .../create-organization-valid.bru | 43 +++++++++++++++ .../Fhir/Resources/Organization/folder.bru | 7 +++ .../Organization/search-organizations.bru | 20 +++++++ .../Patient/create-patient-garbage-json.bru | 28 ++++++++++ .../Patient/create-patient-garbage-xml.bru | 28 ++++++++++ .../create-patient-invalid-gender-xml.bru | 33 ++++++++++++ .../Patient/create-patient-invalid-gender.bru | 37 +++++++++++++ .../create-patient-missing-resourcetype.bru | 34 ++++++++++++ ...eate-patient-multiple-invalid-elements.bru | 34 ++++++++++++ .../create-patient-unknown-element.bru | 32 +++++++++++ .../Patient/create-patient-valid-xml.bru | 36 +++++++++++++ .../Patient/create-patient-valid.bru | 49 +++++++++++++++++ ...create-patient-wrong-element-order-xml.bru | 33 ++++++++++++ .../Fhir/Resources/Patient/delete-patient.bru | 20 +++++++ eng/bruno/Fhir/Resources/Patient/folder.bru | 8 +++ .../Fhir/Resources/Patient/patch-patient.bru | 39 ++++++++++++++ .../Fhir/Resources/Patient/read-patient.bru | 15 ++++++ .../Patient/search-patients-post.bru | 26 +++++++++ .../Resources/Patient/search-patients.bru | 20 +++++++ .../Patient/update-patient-invalid-gender.bru | 32 +++++++++++ .../create-practitioner-invalid-gender.bru | 36 +++++++++++++ .../create-practitioner-valid.bru | 44 +++++++++++++++ .../Fhir/Resources/Practitioner/folder.bru | 7 +++ .../Practitioner/search-practitioners.bru | 20 +++++++ .../create-questionnaire-invalid-status.bru | 38 +++++++++++++ .../create-questionnaire-valid.bru | 50 +++++++++++++++++ .../Fhir/Resources/Questionnaire/folder.bru | 7 +++ .../Questionnaire/read-questionnaire.bru | 20 +++++++ ...-questionnaire-response-invalid-status.bru | 42 +++++++++++++++ .../create-questionnaire-response-valid.bru | 53 +++++++++++++++++++ .../QuestionnaireResponse/folder.bru | 7 +++ .../Task/create-task-invalid-status.bru | 33 ++++++++++++ .../Fhir/Resources/Task/create-task-valid.bru | 47 ++++++++++++++++ eng/bruno/Fhir/Resources/Task/folder.bru | 7 +++ .../Task/search-tasks-for-patient.bru | 20 +++++++ .../Resources/Task/update-task-complete.bru | 42 +++++++++++++++ eng/bruno/Fhir/Resources/folder.bru | 4 ++ .../Fhir/Terminology/create-valueset.bru | 46 ++++++++++++++++ eng/bruno/Fhir/Terminology/expand-by-url.bru | 25 +++++++++ .../Fhir/Terminology/expand-from-body.bru | 34 ++++++++++++ .../expand-stored-conflicting-url.bru | 33 ++++++++++++ eng/bruno/Fhir/Terminology/expand-stored.bru | 20 +++++++ eng/bruno/Fhir/Terminology/folder.bru | 4 ++ eng/bruno/Fhir/Validation/folder.bru | 4 ++ .../validate-patient-against-profile.bru | 38 +++++++++++++ .../validate-patient-base-fnr-ok.bru | 35 ++++++++++++ .../Validation/validate-patient-instance.bru | 38 +++++++++++++ .../validate-patient-no-basis-fnr-invalid.bru | 41 ++++++++++++++ .../validate-patient-unresolvable-profile.bru | 36 +++++++++++++ .../Validation/validate-patient-valid.bru | 38 +++++++++++++ ...te-questionnaire-cross-version-profile.bru | 40 ++++++++++++++ eng/bruno/Fhir/capability-statement.bru | 16 ++++++ eng/bruno/Fhir/folder.bru | 8 +++ eng/bruno/Ignis/Auth/get-token.bru | 33 ++++++++++++ eng/bruno/Ignis/Conformance/packages.bru | 20 +++++++ eng/bruno/Ignis/Conformance/profiles.bru | 21 ++++++++ .../Ignis/Import/archive-import-limits.bru | 16 ++++++ eng/bruno/Ignis/Import/archive-import.bru | 22 ++++++++ eng/bruno/Ignis/Maintenance/clear-store.bru | 17 ++++++ eng/bruno/Ignis/Maintenance/rebuild-index.bru | 16 ++++++ eng/bruno/Ignis/folder.bru | 9 ++++ eng/bruno/Ignis/health.bru | 19 +++++++ eng/bruno/README.md | 38 +++++++++++++ eng/bruno/bruno.json | 6 +++ eng/bruno/collection.bru | 18 +++++++ eng/bruno/environments/hapi-public.bru | 4 ++ eng/bruno/environments/ignis-local.bru | 9 ++++ eng/bruno/environments/ignis-public.bru | 9 ++++ eng/bruno/environments/spark-local.bru | 4 ++ eng/bruno/environments/spark-public.bru | 4 ++ 86 files changed, 2152 insertions(+) create mode 100644 eng/bruno/Fhir/History/folder.bru create mode 100644 eng/bruno/Fhir/History/instance-history.bru create mode 100644 eng/bruno/Fhir/History/system-history.bru create mode 100644 eng/bruno/Fhir/History/type-history.bru create mode 100644 eng/bruno/Fhir/History/version-read.bru create mode 100644 eng/bruno/Fhir/Operations/everything-instance.bru create mode 100644 eng/bruno/Fhir/Operations/folder.bru create mode 100644 eng/bruno/Fhir/Operations/meta-read.bru create mode 100644 eng/bruno/Fhir/Resources/Encounter/create-encounter-invalid-status.bru create mode 100644 eng/bruno/Fhir/Resources/Encounter/create-encounter-valid.bru create mode 100644 eng/bruno/Fhir/Resources/Encounter/folder.bru create mode 100644 eng/bruno/Fhir/Resources/Observation/create-observation-invalid-quantity.bru create mode 100644 eng/bruno/Fhir/Resources/Observation/create-observation-invalid-status.bru create mode 100644 eng/bruno/Fhir/Resources/Observation/create-observation-valid.bru create mode 100644 eng/bruno/Fhir/Resources/Observation/folder.bru create mode 100644 eng/bruno/Fhir/Resources/Observation/search-observations-for-patient.bru create mode 100644 eng/bruno/Fhir/Resources/Organization/create-organization-valid.bru create mode 100644 eng/bruno/Fhir/Resources/Organization/folder.bru create mode 100644 eng/bruno/Fhir/Resources/Organization/search-organizations.bru create mode 100644 eng/bruno/Fhir/Resources/Patient/create-patient-garbage-json.bru create mode 100644 eng/bruno/Fhir/Resources/Patient/create-patient-garbage-xml.bru create mode 100644 eng/bruno/Fhir/Resources/Patient/create-patient-invalid-gender-xml.bru create mode 100644 eng/bruno/Fhir/Resources/Patient/create-patient-invalid-gender.bru create mode 100644 eng/bruno/Fhir/Resources/Patient/create-patient-missing-resourcetype.bru create mode 100644 eng/bruno/Fhir/Resources/Patient/create-patient-multiple-invalid-elements.bru create mode 100644 eng/bruno/Fhir/Resources/Patient/create-patient-unknown-element.bru create mode 100644 eng/bruno/Fhir/Resources/Patient/create-patient-valid-xml.bru create mode 100644 eng/bruno/Fhir/Resources/Patient/create-patient-valid.bru create mode 100644 eng/bruno/Fhir/Resources/Patient/create-patient-wrong-element-order-xml.bru create mode 100644 eng/bruno/Fhir/Resources/Patient/delete-patient.bru create mode 100644 eng/bruno/Fhir/Resources/Patient/folder.bru create mode 100644 eng/bruno/Fhir/Resources/Patient/patch-patient.bru create mode 100644 eng/bruno/Fhir/Resources/Patient/read-patient.bru create mode 100644 eng/bruno/Fhir/Resources/Patient/search-patients-post.bru create mode 100644 eng/bruno/Fhir/Resources/Patient/search-patients.bru create mode 100644 eng/bruno/Fhir/Resources/Patient/update-patient-invalid-gender.bru create mode 100644 eng/bruno/Fhir/Resources/Practitioner/create-practitioner-invalid-gender.bru create mode 100644 eng/bruno/Fhir/Resources/Practitioner/create-practitioner-valid.bru create mode 100644 eng/bruno/Fhir/Resources/Practitioner/folder.bru create mode 100644 eng/bruno/Fhir/Resources/Practitioner/search-practitioners.bru create mode 100644 eng/bruno/Fhir/Resources/Questionnaire/create-questionnaire-invalid-status.bru create mode 100644 eng/bruno/Fhir/Resources/Questionnaire/create-questionnaire-valid.bru create mode 100644 eng/bruno/Fhir/Resources/Questionnaire/folder.bru create mode 100644 eng/bruno/Fhir/Resources/Questionnaire/read-questionnaire.bru create mode 100644 eng/bruno/Fhir/Resources/QuestionnaireResponse/create-questionnaire-response-invalid-status.bru create mode 100644 eng/bruno/Fhir/Resources/QuestionnaireResponse/create-questionnaire-response-valid.bru create mode 100644 eng/bruno/Fhir/Resources/QuestionnaireResponse/folder.bru create mode 100644 eng/bruno/Fhir/Resources/Task/create-task-invalid-status.bru create mode 100644 eng/bruno/Fhir/Resources/Task/create-task-valid.bru create mode 100644 eng/bruno/Fhir/Resources/Task/folder.bru create mode 100644 eng/bruno/Fhir/Resources/Task/search-tasks-for-patient.bru create mode 100644 eng/bruno/Fhir/Resources/Task/update-task-complete.bru create mode 100644 eng/bruno/Fhir/Resources/folder.bru create mode 100644 eng/bruno/Fhir/Terminology/create-valueset.bru create mode 100644 eng/bruno/Fhir/Terminology/expand-by-url.bru create mode 100644 eng/bruno/Fhir/Terminology/expand-from-body.bru create mode 100644 eng/bruno/Fhir/Terminology/expand-stored-conflicting-url.bru create mode 100644 eng/bruno/Fhir/Terminology/expand-stored.bru create mode 100644 eng/bruno/Fhir/Terminology/folder.bru create mode 100644 eng/bruno/Fhir/Validation/folder.bru create mode 100644 eng/bruno/Fhir/Validation/validate-patient-against-profile.bru create mode 100644 eng/bruno/Fhir/Validation/validate-patient-base-fnr-ok.bru create mode 100644 eng/bruno/Fhir/Validation/validate-patient-instance.bru create mode 100644 eng/bruno/Fhir/Validation/validate-patient-no-basis-fnr-invalid.bru create mode 100644 eng/bruno/Fhir/Validation/validate-patient-unresolvable-profile.bru create mode 100644 eng/bruno/Fhir/Validation/validate-patient-valid.bru create mode 100644 eng/bruno/Fhir/Validation/validate-questionnaire-cross-version-profile.bru create mode 100644 eng/bruno/Fhir/capability-statement.bru create mode 100644 eng/bruno/Fhir/folder.bru create mode 100644 eng/bruno/Ignis/Auth/get-token.bru create mode 100644 eng/bruno/Ignis/Conformance/packages.bru create mode 100644 eng/bruno/Ignis/Conformance/profiles.bru create mode 100644 eng/bruno/Ignis/Import/archive-import-limits.bru create mode 100644 eng/bruno/Ignis/Import/archive-import.bru create mode 100644 eng/bruno/Ignis/Maintenance/clear-store.bru create mode 100644 eng/bruno/Ignis/Maintenance/rebuild-index.bru create mode 100644 eng/bruno/Ignis/folder.bru create mode 100644 eng/bruno/Ignis/health.bru create mode 100644 eng/bruno/README.md create mode 100644 eng/bruno/bruno.json create mode 100644 eng/bruno/collection.bru create mode 100644 eng/bruno/environments/hapi-public.bru create mode 100644 eng/bruno/environments/ignis-local.bru create mode 100644 eng/bruno/environments/ignis-public.bru create mode 100644 eng/bruno/environments/spark-local.bru create mode 100644 eng/bruno/environments/spark-public.bru diff --git a/eng/bruno/Fhir/History/folder.bru b/eng/bruno/Fhir/History/folder.bru new file mode 100644 index 00000000..eceecfbc --- /dev/null +++ b/eng/bruno/Fhir/History/folder.bru @@ -0,0 +1,4 @@ +meta { + name: History + seq: 1 +} diff --git a/eng/bruno/Fhir/History/instance-history.bru b/eng/bruno/Fhir/History/instance-history.bru new file mode 100644 index 00000000..18e5447e --- /dev/null +++ b/eng/bruno/Fhir/History/instance-history.bru @@ -0,0 +1,20 @@ +meta { + name: Instance history + type: http + seq: 1 +} + +get { + url: {{fhirBase}}/Patient/{{patientId}}/_history + body: none + auth: inherit +} + +assert { + res.status: eq 200 + res.body.resourceType: eq Bundle +} + +docs { + Every version of one patient, as a `history` `Bundle`. Needs `patientId`. +} diff --git a/eng/bruno/Fhir/History/system-history.bru b/eng/bruno/Fhir/History/system-history.bru new file mode 100644 index 00000000..147534b4 --- /dev/null +++ b/eng/bruno/Fhir/History/system-history.bru @@ -0,0 +1,24 @@ +meta { + name: System history + type: http + seq: 3 +} + +get { + url: {{fhirBase}}/_history?_count=5 + body: none + auth: inherit +} + +params:query { + _count: 5 +} + +assert { + res.status: eq 200 + res.body.resourceType: eq Bundle +} + +docs { + Version history across every resource type on the server. +} diff --git a/eng/bruno/Fhir/History/type-history.bru b/eng/bruno/Fhir/History/type-history.bru new file mode 100644 index 00000000..0b4a8787 --- /dev/null +++ b/eng/bruno/Fhir/History/type-history.bru @@ -0,0 +1,24 @@ +meta { + name: Type history + type: http + seq: 2 +} + +get { + url: {{fhirBase}}/Patient/_history?_count=5 + body: none + auth: inherit +} + +params:query { + _count: 5 +} + +assert { + res.status: eq 200 + res.body.resourceType: eq Bundle +} + +docs { + Version history across all patients. +} diff --git a/eng/bruno/Fhir/History/version-read.bru b/eng/bruno/Fhir/History/version-read.bru new file mode 100644 index 00000000..272829dc --- /dev/null +++ b/eng/bruno/Fhir/History/version-read.bru @@ -0,0 +1,21 @@ +meta { + name: Read version + type: http + seq: 4 +} + +get { + url: {{fhirBase}}/Patient/{{patientId}}/_history/{{patientVersionId}} + body: none + auth: inherit +} + +assert { + res.status: eq 200 + res.body.resourceType: eq Patient +} + +docs { + Reads one specific version. Needs `patientId` and `patientVersionId`, both saved by + **Create Patient (valid)**. +} diff --git a/eng/bruno/Fhir/Operations/everything-instance.bru b/eng/bruno/Fhir/Operations/everything-instance.bru new file mode 100644 index 00000000..d3b91fa5 --- /dev/null +++ b/eng/bruno/Fhir/Operations/everything-instance.bru @@ -0,0 +1,15 @@ +meta { + name: Everything (instance) + type: http + seq: 1 +} + +get { + url: {{fhirBase}}/Patient/{{patientId}}/$everything + body: none + auth: inherit +} + +docs { + All resources related to the patient instance, as a `Bundle`. Needs `patientId`. +} diff --git a/eng/bruno/Fhir/Operations/folder.bru b/eng/bruno/Fhir/Operations/folder.bru new file mode 100644 index 00000000..f8fbbe4d --- /dev/null +++ b/eng/bruno/Fhir/Operations/folder.bru @@ -0,0 +1,4 @@ +meta { + name: Operations + seq: 3 +} diff --git a/eng/bruno/Fhir/Operations/meta-read.bru b/eng/bruno/Fhir/Operations/meta-read.bru new file mode 100644 index 00000000..35708917 --- /dev/null +++ b/eng/bruno/Fhir/Operations/meta-read.bru @@ -0,0 +1,25 @@ +meta { + name: Meta (read) + type: http + seq: 2 +} + +post { + url: {{fhirBase}}/Patient/{{patientId}}/$meta + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Parameters" + } +} + +docs { + The resource's `meta` (tags, profiles, security labels) as `Parameters`. Needs `patientId`. +} diff --git a/eng/bruno/Fhir/Resources/Encounter/create-encounter-invalid-status.bru b/eng/bruno/Fhir/Resources/Encounter/create-encounter-invalid-status.bru new file mode 100644 index 00000000..c4034c5d --- /dev/null +++ b/eng/bruno/Fhir/Resources/Encounter/create-encounter-invalid-status.bru @@ -0,0 +1,35 @@ +meta { + name: Create Encounter (invalid status code) + type: http + seq: 2 +} + +post { + url: {{fhirBase}}/Encounter + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Encounter", + "status": "closed", + "class": { + "system": "http://terminology.hl7.org/CodeSystem/v3-ActCode", + "code": "AMB" + } + } +} + +assert { + res.status: eq 400 + res.body.resourceType: eq OperationOutcome +} + +docs { + `status` must be an `EncounterStatus` code. Expect `400` at `Encounter.status`. +} diff --git a/eng/bruno/Fhir/Resources/Encounter/create-encounter-valid.bru b/eng/bruno/Fhir/Resources/Encounter/create-encounter-valid.bru new file mode 100644 index 00000000..27760d08 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Encounter/create-encounter-valid.bru @@ -0,0 +1,43 @@ +meta { + name: Create Encounter (valid) + type: http + seq: 1 +} + +post { + url: {{fhirBase}}/Encounter + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Encounter", + "status": "finished", + "class": { + "system": "http://terminology.hl7.org/CodeSystem/v3-ActCode", + "code": "AMB", + "display": "ambulatory" + }, + "subject": { + "reference": "Patient/{{patientId}}" + } + } +} + +vars:pre-request { + patientId: 123 +} + +assert { + res.status: eq 201 + res.body.resourceType: eq Encounter +} + +docs { + An ambulatory encounter for the patient. Expect `201`. +} diff --git a/eng/bruno/Fhir/Resources/Encounter/folder.bru b/eng/bruno/Fhir/Resources/Encounter/folder.bru new file mode 100644 index 00000000..93c7f262 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Encounter/folder.bru @@ -0,0 +1,7 @@ +meta { + name: Encounter +} + +docs { + Create examples for `Encounter`. Needs `patientId`. +} diff --git a/eng/bruno/Fhir/Resources/Observation/create-observation-invalid-quantity.bru b/eng/bruno/Fhir/Resources/Observation/create-observation-invalid-quantity.bru new file mode 100644 index 00000000..638a7eea --- /dev/null +++ b/eng/bruno/Fhir/Resources/Observation/create-observation-invalid-quantity.bru @@ -0,0 +1,43 @@ +meta { + name: Create Observation (invalid quantity value) + type: http + seq: 3 +} + +post { + url: {{fhirBase}}/Observation + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Observation", + "status": "final", + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "8867-4" + } + ] + }, + "valueQuantity": { + "value": "not-a-number", + "unit": "beats/minute" + } + } +} + +assert { + res.status: eq 400 + res.body.resourceType: eq OperationOutcome +} + +docs { + `valueQuantity.value` must be a number, not a string. Expect `400`. +} diff --git a/eng/bruno/Fhir/Resources/Observation/create-observation-invalid-status.bru b/eng/bruno/Fhir/Resources/Observation/create-observation-invalid-status.bru new file mode 100644 index 00000000..7420e8f1 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Observation/create-observation-invalid-status.bru @@ -0,0 +1,39 @@ +meta { + name: Create Observation (invalid status code) + type: http + seq: 2 +} + +post { + url: {{fhirBase}}/Observation + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Observation", + "status": "done", + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "8867-4" + } + ] + } + } +} + +assert { + res.status: eq 400 + res.body.resourceType: eq OperationOutcome +} + +docs { + `status` must be an `ObservationStatus` code. Expect `400` at `Observation.status`. +} diff --git a/eng/bruno/Fhir/Resources/Observation/create-observation-valid.bru b/eng/bruno/Fhir/Resources/Observation/create-observation-valid.bru new file mode 100644 index 00000000..5aef5e90 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Observation/create-observation-valid.bru @@ -0,0 +1,49 @@ +meta { + name: Create Observation (valid) + type: http + seq: 1 +} + +post { + url: {{fhirBase}}/Observation + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Observation", + "status": "final", + "code": { + "coding": [ + { + "system": "http://loinc.org", + "code": "8867-4", + "display": "Heart rate" + } + ] + }, + "subject": { + "reference": "Patient/{{patientId}}" + }, + "valueQuantity": { + "value": 72, + "unit": "beats/minute", + "system": "http://unitsofmeasure.org", + "code": "/min" + } + } +} + +assert { + res.status: eq 201 + res.body.resourceType: eq Observation +} + +docs { + A heart-rate observation for the patient. Expect `201`. +} diff --git a/eng/bruno/Fhir/Resources/Observation/folder.bru b/eng/bruno/Fhir/Resources/Observation/folder.bru new file mode 100644 index 00000000..5416d0e1 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Observation/folder.bru @@ -0,0 +1,7 @@ +meta { + name: Observation +} + +docs { + Create and search examples for `Observation`. Needs `patientId`. +} diff --git a/eng/bruno/Fhir/Resources/Observation/search-observations-for-patient.bru b/eng/bruno/Fhir/Resources/Observation/search-observations-for-patient.bru new file mode 100644 index 00000000..0205f088 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Observation/search-observations-for-patient.bru @@ -0,0 +1,20 @@ +meta { + name: Search Observations for patient + type: http + seq: 4 +} + +get { + url: {{fhirBase}}/Observation?subject=Patient/{{patientId}} + body: none + auth: inherit +} + +assert { + res.status: eq 200 + res.body.resourceType: eq Bundle +} + +docs { + Expect `200` with a `searchset` `Bundle`. +} diff --git a/eng/bruno/Fhir/Resources/Organization/create-organization-valid.bru b/eng/bruno/Fhir/Resources/Organization/create-organization-valid.bru new file mode 100644 index 00000000..381de124 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Organization/create-organization-valid.bru @@ -0,0 +1,43 @@ +meta { + name: Create Organization (valid) + type: http + seq: 1 +} + +post { + url: {{fhirBase}}/Organization + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Organization", + "name": "Incendi Clinic", + "telecom": [ + { + "system": "phone", + "value": "+47 22 22 22 22" + } + ] + } +} + +assert { + res.status: eq 201 + res.body.resourceType: eq Organization +} + +script:post-response { + if (res.body && res.body.id) { + bru.setVar("organizationId", res.body.id); + } +} + +docs { + Expect `201`. Saves `organizationId`. +} diff --git a/eng/bruno/Fhir/Resources/Organization/folder.bru b/eng/bruno/Fhir/Resources/Organization/folder.bru new file mode 100644 index 00000000..14b11695 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Organization/folder.bru @@ -0,0 +1,7 @@ +meta { + name: Organization +} + +docs { + Create and search examples for `Organization`. +} diff --git a/eng/bruno/Fhir/Resources/Organization/search-organizations.bru b/eng/bruno/Fhir/Resources/Organization/search-organizations.bru new file mode 100644 index 00000000..3b9cc454 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Organization/search-organizations.bru @@ -0,0 +1,20 @@ +meta { + name: Search Organizations by name + type: http + seq: 2 +} + +get { + url: {{fhirBase}}/Organization?name=Incendi + body: none + auth: inherit +} + +assert { + res.status: eq 200 + res.body.resourceType: eq Bundle +} + +docs { + Expect `200` with a `searchset` `Bundle`. +} diff --git a/eng/bruno/Fhir/Resources/Patient/create-patient-garbage-json.bru b/eng/bruno/Fhir/Resources/Patient/create-patient-garbage-json.bru new file mode 100644 index 00000000..9a3d2036 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Patient/create-patient-garbage-json.bru @@ -0,0 +1,28 @@ +meta { + name: Create Patient (garbage body, JSON route) + type: http + seq: 6 +} + +post { + url: {{fhirBase}}/Patient + body: text + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:text { + this is not json +} + +assert { + res.status: eq 400 + res.body.resourceType: eq OperationOutcome +} + +docs { + Not JSON at all, sent as `application/fhir+json`. Expect `400` with the parser message. +} diff --git a/eng/bruno/Fhir/Resources/Patient/create-patient-garbage-xml.bru b/eng/bruno/Fhir/Resources/Patient/create-patient-garbage-xml.bru new file mode 100644 index 00000000..3ad7a6fc --- /dev/null +++ b/eng/bruno/Fhir/Resources/Patient/create-patient-garbage-xml.bru @@ -0,0 +1,28 @@ +meta { + name: Create Patient (garbage body, XML route) + type: http + seq: 11 +} + +post { + url: {{fhirBase}}/Patient + body: text + auth: inherit +} + +headers { + Content-Type: application/fhir+xml + Accept: application/fhir+xml +} + +body:text { + this is not xml +} + +assert { + res.status: eq 400 +} + +docs { + Not XML at all, sent as `application/fhir+xml`. Expect `400` with the parser message. +} diff --git a/eng/bruno/Fhir/Resources/Patient/create-patient-invalid-gender-xml.bru b/eng/bruno/Fhir/Resources/Patient/create-patient-invalid-gender-xml.bru new file mode 100644 index 00000000..a988897b --- /dev/null +++ b/eng/bruno/Fhir/Resources/Patient/create-patient-invalid-gender-xml.bru @@ -0,0 +1,33 @@ +meta { + name: Create Patient (invalid gender code, XML) + type: http + seq: 9 +} + +post { + url: {{fhirBase}}/Patient + body: xml + auth: inherit +} + +headers { + Content-Type: application/fhir+xml + Accept: application/fhir+xml +} + +body:xml { + + + + + + +} + +assert { + res.status: eq 400 +} + +docs { + Same invalid `gender` on the XML route; the `OperationOutcome` comes back as XML. +} diff --git a/eng/bruno/Fhir/Resources/Patient/create-patient-invalid-gender.bru b/eng/bruno/Fhir/Resources/Patient/create-patient-invalid-gender.bru new file mode 100644 index 00000000..38426644 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Patient/create-patient-invalid-gender.bru @@ -0,0 +1,37 @@ +meta { + name: Create Patient (invalid gender code) + type: http + seq: 2 +} + +post { + url: {{fhirBase}}/Patient + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Patient", + "name": [ + { + "family": "Test" + } + ], + "gender": "mann" + } +} + +assert { + res.status: eq 400 + res.body.resourceType: eq OperationOutcome +} + +docs { + `gender` is bound to `AdministrativeGender`. Expect `400` with + `expression: ["Patient.gender"]`. +} diff --git a/eng/bruno/Fhir/Resources/Patient/create-patient-missing-resourcetype.bru b/eng/bruno/Fhir/Resources/Patient/create-patient-missing-resourcetype.bru new file mode 100644 index 00000000..6c2a8d88 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Patient/create-patient-missing-resourcetype.bru @@ -0,0 +1,34 @@ +meta { + name: Create Patient (missing resourceType) + type: http + seq: 5 +} + +post { + url: {{fhirBase}}/Patient + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "name": [ + { + "family": "Test" + } + ] + } +} + +assert { + res.status: eq 400 + res.body.resourceType: eq OperationOutcome +} + +docs { + Valid JSON, no `resourceType`. Expect `400` with `code: structure`. +} diff --git a/eng/bruno/Fhir/Resources/Patient/create-patient-multiple-invalid-elements.bru b/eng/bruno/Fhir/Resources/Patient/create-patient-multiple-invalid-elements.bru new file mode 100644 index 00000000..d3a53a43 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Patient/create-patient-multiple-invalid-elements.bru @@ -0,0 +1,34 @@ +meta { + name: Create Patient (multiple invalid elements) + type: http + seq: 3 +} + +post { + url: {{fhirBase}}/Patient + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Patient", + "gender": "bogus", + "birthDate": "not-a-date", + "active": true + } +} + +assert { + res.status: eq 400 + res.body.resourceType: eq OperationOutcome +} + +docs { + Two bad elements. Expect `400` with one issue each — the parser does not stop at + the first. +} diff --git a/eng/bruno/Fhir/Resources/Patient/create-patient-unknown-element.bru b/eng/bruno/Fhir/Resources/Patient/create-patient-unknown-element.bru new file mode 100644 index 00000000..ee6b263f --- /dev/null +++ b/eng/bruno/Fhir/Resources/Patient/create-patient-unknown-element.bru @@ -0,0 +1,32 @@ +meta { + name: Create Patient (unknown element) + type: http + seq: 4 +} + +post { + url: {{fhirBase}}/Patient + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Patient", + "favoriteColor": "blue", + "active": true + } +} + +assert { + res.status: eq 400 + res.body.resourceType: eq OperationOutcome +} + +docs { + `favoriteColor` is not a `Patient` element. The parser is strict, so expect `400`. +} diff --git a/eng/bruno/Fhir/Resources/Patient/create-patient-valid-xml.bru b/eng/bruno/Fhir/Resources/Patient/create-patient-valid-xml.bru new file mode 100644 index 00000000..926dcdb0 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Patient/create-patient-valid-xml.bru @@ -0,0 +1,36 @@ +meta { + name: Create Patient (valid, XML) + type: http + seq: 8 +} + +post { + url: {{fhirBase}}/Patient + body: xml + auth: inherit +} + +headers { + Content-Type: application/fhir+xml + Accept: application/fhir+xml +} + +body:xml { + + + + + + + + +} + +assert { + res.status: eq 201 +} + +docs { + Happy path on the XML route. FHIR XML is order-sensitive: `name`, then `gender`, + then `birthDate`. +} diff --git a/eng/bruno/Fhir/Resources/Patient/create-patient-valid.bru b/eng/bruno/Fhir/Resources/Patient/create-patient-valid.bru new file mode 100644 index 00000000..6ce3fda8 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Patient/create-patient-valid.bru @@ -0,0 +1,49 @@ +meta { + name: Create Patient (valid) + type: http + seq: 1 +} + +post { + url: {{fhirBase}}/Patient + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Patient", + "name": [ + { + "family": "Test", + "given": ["Ada"] + } + ], + "gender": "female", + "birthDate": "1980-01-01", + "active": true + } +} + +assert { + res.status: eq 201 + res.body.resourceType: eq Patient +} + +script:post-response { + // Stash the new id and version so the other examples can reuse them. + if (res.body && res.body.id) { + bru.setVar("patientId", res.body.id); + } + if (res.body && res.body.meta && res.body.meta.versionId) { + bru.setVar("patientVersionId", res.body.meta.versionId); + } +} + +docs { + Happy path. Expect `201`. Saves `patientId` for the other requests. +} diff --git a/eng/bruno/Fhir/Resources/Patient/create-patient-wrong-element-order-xml.bru b/eng/bruno/Fhir/Resources/Patient/create-patient-wrong-element-order-xml.bru new file mode 100644 index 00000000..379903a4 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Patient/create-patient-wrong-element-order-xml.bru @@ -0,0 +1,33 @@ +meta { + name: Create Patient (wrong element order, XML) + type: http + seq: 10 +} + +post { + url: {{fhirBase}}/Patient + body: xml + auth: inherit +} + +headers { + Content-Type: application/fhir+xml + Accept: application/fhir+xml +} + +body:xml { + + + + + + +} + +assert { + res.status: eq 400 +} + +docs { + `gender` before `name`. Expect `400` — element order matters in XML, not in JSON. +} diff --git a/eng/bruno/Fhir/Resources/Patient/delete-patient.bru b/eng/bruno/Fhir/Resources/Patient/delete-patient.bru new file mode 100644 index 00000000..fc489a1b --- /dev/null +++ b/eng/bruno/Fhir/Resources/Patient/delete-patient.bru @@ -0,0 +1,20 @@ +meta { + name: Delete Patient + type: http + seq: 16 +} + +delete { + url: {{fhirBase}}/Patient/{{patientId}} + body: none + auth: inherit +} + +assert { + res.status: lt 300 +} + +docs { + Deletes the patient. Run last — the other requests need `patientId`. A later read + returns `410 Gone`. +} diff --git a/eng/bruno/Fhir/Resources/Patient/folder.bru b/eng/bruno/Fhir/Resources/Patient/folder.bru new file mode 100644 index 00000000..039b7712 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Patient/folder.bru @@ -0,0 +1,8 @@ +meta { + name: Patient +} + +docs { + Success and failure bodies for `Patient`. Failures are `400` with one + `OperationOutcome` issue per invalid element. +} diff --git a/eng/bruno/Fhir/Resources/Patient/patch-patient.bru b/eng/bruno/Fhir/Resources/Patient/patch-patient.bru new file mode 100644 index 00000000..a02c6df9 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Patient/patch-patient.bru @@ -0,0 +1,39 @@ +meta { + name: Patch Patient + type: http + seq: 14 +} + +patch { + url: {{fhirBase}}/Patient/{{patientId}} + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Parameters", + "parameter": [ + { + "name": "operation", + "part": [ + { "name": "type", "valueCode": "replace" }, + { "name": "path", "valueString": "Patient.active" }, + { "name": "value", "valueBoolean": false } + ] + } + ] + } +} + +assert { + res.status: eq 200 +} + +docs { + FHIRPath patch setting `active` to `false`. Needs `patientId`. +} diff --git a/eng/bruno/Fhir/Resources/Patient/read-patient.bru b/eng/bruno/Fhir/Resources/Patient/read-patient.bru new file mode 100644 index 00000000..d712840b --- /dev/null +++ b/eng/bruno/Fhir/Resources/Patient/read-patient.bru @@ -0,0 +1,15 @@ +meta { + name: Read Patient + type: http + seq: 12 +} + +get { + url: {{fhirBase}}/Patient/{{patientId}} + body: none + auth: inherit +} + +docs { + Reads a `Patient` by id. Needs `patientId` from **Create Patient (valid)**. +} diff --git a/eng/bruno/Fhir/Resources/Patient/search-patients-post.bru b/eng/bruno/Fhir/Resources/Patient/search-patients-post.bru new file mode 100644 index 00000000..c5dc081b --- /dev/null +++ b/eng/bruno/Fhir/Resources/Patient/search-patients-post.bru @@ -0,0 +1,26 @@ +meta { + name: Search Patients (POST) + type: http + seq: 15 +} + +post { + url: {{fhirBase}}/Patient/_search + body: formUrlEncoded + auth: inherit +} + +body:form-urlencoded { + name: Test + _count: 10 +} + +assert { + res.status: eq 200 + res.body.resourceType: eq Bundle +} + +docs { + Search parameters in a form body instead of the query string. Same result as + **Search Patients**. +} diff --git a/eng/bruno/Fhir/Resources/Patient/search-patients.bru b/eng/bruno/Fhir/Resources/Patient/search-patients.bru new file mode 100644 index 00000000..bf49a54f --- /dev/null +++ b/eng/bruno/Fhir/Resources/Patient/search-patients.bru @@ -0,0 +1,20 @@ +meta { + name: Search Patients + type: http + seq: 13 +} + +get { + url: {{fhirBase}}/Patient?name=Test&_count=10 + body: none + auth: inherit +} + +params:query { + name: Test + _count: 10 +} + +docs { + Type-level search. Expect `200` with a `searchset` `Bundle`. +} diff --git a/eng/bruno/Fhir/Resources/Patient/update-patient-invalid-gender.bru b/eng/bruno/Fhir/Resources/Patient/update-patient-invalid-gender.bru new file mode 100644 index 00000000..9840e197 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Patient/update-patient-invalid-gender.bru @@ -0,0 +1,32 @@ +meta { + name: Update Patient (invalid gender code) + type: http + seq: 7 +} + +put { + url: {{fhirBase}}/Patient/{{patientId}} + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Patient", + "id": "{{patientId}}", + "gender": "bogus" + } +} + +assert { + res.status: eq 400 + res.body.resourceType: eq OperationOutcome +} + +docs { + Per-element errors work the same on update as on create. Needs `patientId`. +} diff --git a/eng/bruno/Fhir/Resources/Practitioner/create-practitioner-invalid-gender.bru b/eng/bruno/Fhir/Resources/Practitioner/create-practitioner-invalid-gender.bru new file mode 100644 index 00000000..ea70593f --- /dev/null +++ b/eng/bruno/Fhir/Resources/Practitioner/create-practitioner-invalid-gender.bru @@ -0,0 +1,36 @@ +meta { + name: Create Practitioner (invalid gender code) + type: http + seq: 2 +} + +post { + url: {{fhirBase}}/Practitioner + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Practitioner", + "name": [ + { + "family": "Losen" + } + ], + "gender": "doctor" + } +} + +assert { + res.status: eq 400 + res.body.resourceType: eq OperationOutcome +} + +docs { + Expect `400` with `expression: ["Practitioner.gender"]`. +} diff --git a/eng/bruno/Fhir/Resources/Practitioner/create-practitioner-valid.bru b/eng/bruno/Fhir/Resources/Practitioner/create-practitioner-valid.bru new file mode 100644 index 00000000..df7af909 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Practitioner/create-practitioner-valid.bru @@ -0,0 +1,44 @@ +meta { + name: Create Practitioner (valid) + type: http + seq: 1 +} + +post { + url: {{fhirBase}}/Practitioner + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Practitioner", + "name": [ + { + "family": "Losen", + "given": ["Leo"], + "prefix": ["Dr."] + } + ], + "gender": "female" + } +} + +assert { + res.status: eq 201 + res.body.resourceType: eq Practitioner +} + +script:post-response { + if (res.body && res.body.id) { + bru.setVar("practitionerId", res.body.id); + } +} + +docs { + Expect `201`. Saves `practitionerId`. +} diff --git a/eng/bruno/Fhir/Resources/Practitioner/folder.bru b/eng/bruno/Fhir/Resources/Practitioner/folder.bru new file mode 100644 index 00000000..29b6ced3 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Practitioner/folder.bru @@ -0,0 +1,7 @@ +meta { + name: Practitioner +} + +docs { + Create and search examples for `Practitioner`. +} diff --git a/eng/bruno/Fhir/Resources/Practitioner/search-practitioners.bru b/eng/bruno/Fhir/Resources/Practitioner/search-practitioners.bru new file mode 100644 index 00000000..9a234e27 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Practitioner/search-practitioners.bru @@ -0,0 +1,20 @@ +meta { + name: Search Practitioners by name + type: http + seq: 3 +} + +get { + url: {{fhirBase}}/Practitioner?name=Losen + body: none + auth: inherit +} + +assert { + res.status: eq 200 + res.body.resourceType: eq Bundle +} + +docs { + Expect `200` with a `searchset` `Bundle`. +} diff --git a/eng/bruno/Fhir/Resources/Questionnaire/create-questionnaire-invalid-status.bru b/eng/bruno/Fhir/Resources/Questionnaire/create-questionnaire-invalid-status.bru new file mode 100644 index 00000000..b4925d1a --- /dev/null +++ b/eng/bruno/Fhir/Resources/Questionnaire/create-questionnaire-invalid-status.bru @@ -0,0 +1,38 @@ +meta { + name: Create Questionnaire (invalid status code) + type: http + seq: 2 +} + +post { + url: {{fhirBase}}/Questionnaire + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Questionnaire", + "status": "published", + "item": [ + { + "linkId": "q1", + "text": "Do you smoke?", + "type": "boolean" + } + ] + } +} + +assert { + res.status: eq 400 + res.body.resourceType: eq OperationOutcome +} + +docs { + `status` must be a `PublicationStatus` code. Expect `400` at `Questionnaire.status`. +} diff --git a/eng/bruno/Fhir/Resources/Questionnaire/create-questionnaire-valid.bru b/eng/bruno/Fhir/Resources/Questionnaire/create-questionnaire-valid.bru new file mode 100644 index 00000000..861d850e --- /dev/null +++ b/eng/bruno/Fhir/Resources/Questionnaire/create-questionnaire-valid.bru @@ -0,0 +1,50 @@ +meta { + name: Create Questionnaire (valid) + type: http + seq: 1 +} + +post { + url: {{fhirBase}}/Questionnaire + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Questionnaire", + "status": "active", + "title": "Intake questionnaire", + "item": [ + { + "linkId": "q1", + "text": "Have you had food last 6 hours?", + "type": "boolean" + }, + { + "linkId": "q2", + "text": "Known allergies", + "type": "string" + } + ] + } +} + +assert { + res.status: eq 201 + res.body.resourceType: eq Questionnaire +} + +script:post-response { + if (res.body && res.body.id) { + bru.setVar("questionnaireId", res.body.id); + } +} + +docs { + Expect `201`. Saves `questionnaireId`. +} diff --git a/eng/bruno/Fhir/Resources/Questionnaire/folder.bru b/eng/bruno/Fhir/Resources/Questionnaire/folder.bru new file mode 100644 index 00000000..2c589d7a --- /dev/null +++ b/eng/bruno/Fhir/Resources/Questionnaire/folder.bru @@ -0,0 +1,7 @@ +meta { + name: Questionnaire +} + +docs { + Create and read examples for `Questionnaire`. +} diff --git a/eng/bruno/Fhir/Resources/Questionnaire/read-questionnaire.bru b/eng/bruno/Fhir/Resources/Questionnaire/read-questionnaire.bru new file mode 100644 index 00000000..0017c640 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Questionnaire/read-questionnaire.bru @@ -0,0 +1,20 @@ +meta { + name: Read Questionnaire + type: http + seq: 3 +} + +get { + url: {{fhirBase}}/Questionnaire/{{questionnaireId}} + body: none + auth: inherit +} + +assert { + res.status: eq 200 + res.body.resourceType: eq Questionnaire +} + +docs { + Needs `questionnaireId`. Expect `200` with `meta.versionId` and an `ETag` header. +} diff --git a/eng/bruno/Fhir/Resources/QuestionnaireResponse/create-questionnaire-response-invalid-status.bru b/eng/bruno/Fhir/Resources/QuestionnaireResponse/create-questionnaire-response-invalid-status.bru new file mode 100644 index 00000000..3806c5aa --- /dev/null +++ b/eng/bruno/Fhir/Resources/QuestionnaireResponse/create-questionnaire-response-invalid-status.bru @@ -0,0 +1,42 @@ +meta { + name: Create QuestionnaireResponse (invalid status code) + type: http + seq: 2 +} + +post { + url: {{fhirBase}}/QuestionnaireResponse + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "QuestionnaireResponse", + "status": "done", + "item": [ + { + "linkId": "q1", + "answer": [ + { + "valueBoolean": true + } + ] + } + ] + } +} + +assert { + res.status: eq 400 + res.body.resourceType: eq OperationOutcome +} + +docs { + `status` must be a `QuestionnaireResponseStatus` code. Expect `400` at + `QuestionnaireResponse.status`. +} diff --git a/eng/bruno/Fhir/Resources/QuestionnaireResponse/create-questionnaire-response-valid.bru b/eng/bruno/Fhir/Resources/QuestionnaireResponse/create-questionnaire-response-valid.bru new file mode 100644 index 00000000..22081906 --- /dev/null +++ b/eng/bruno/Fhir/Resources/QuestionnaireResponse/create-questionnaire-response-valid.bru @@ -0,0 +1,53 @@ +meta { + name: Create QuestionnaireResponse (valid) + type: http + seq: 1 +} + +post { + url: {{fhirBase}}/QuestionnaireResponse + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "QuestionnaireResponse", + "status": "completed", + "subject": { + "reference": "Patient/{{patientId}}" + }, + "item": [ + { + "linkId": "q1", + "answer": [ + { + "valueBoolean": false + } + ] + }, + { + "linkId": "q2", + "answer": [ + { + "valueString": "Penicillin" + } + ] + } + ] + } +} + +assert { + res.status: eq 201 + res.body.resourceType: eq QuestionnaireResponse +} + +docs { + Expect `201`. `questionnaire` is omitted on purpose — its type differs across FHIR + versions. +} diff --git a/eng/bruno/Fhir/Resources/QuestionnaireResponse/folder.bru b/eng/bruno/Fhir/Resources/QuestionnaireResponse/folder.bru new file mode 100644 index 00000000..28c6f78d --- /dev/null +++ b/eng/bruno/Fhir/Resources/QuestionnaireResponse/folder.bru @@ -0,0 +1,7 @@ +meta { + name: QuestionnaireResponse +} + +docs { + Create examples for `QuestionnaireResponse`. Needs `questionnaireId` and `patientId`. +} diff --git a/eng/bruno/Fhir/Resources/Task/create-task-invalid-status.bru b/eng/bruno/Fhir/Resources/Task/create-task-invalid-status.bru new file mode 100644 index 00000000..98938eb7 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Task/create-task-invalid-status.bru @@ -0,0 +1,33 @@ +meta { + name: Create Task (invalid status code) + type: http + seq: 2 +} + +post { + url: {{fhirBase}}/Task + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Task", + "status": "todo", + "intent": "order", + "description": "Follow up on abnormal heart rate observation" + } +} + +assert { + res.status: eq 400 + res.body.resourceType: eq OperationOutcome +} + +docs { + `status` must be a `TaskStatus` code. Expect `400` at `Task.status`. +} diff --git a/eng/bruno/Fhir/Resources/Task/create-task-valid.bru b/eng/bruno/Fhir/Resources/Task/create-task-valid.bru new file mode 100644 index 00000000..320e534c --- /dev/null +++ b/eng/bruno/Fhir/Resources/Task/create-task-valid.bru @@ -0,0 +1,47 @@ +meta { + name: Create Task (valid) + type: http + seq: 1 +} + +post { + url: {{fhirBase}}/Task + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Task", + "status": "requested", + "intent": "order", + "description": "Follow up on abnormal heart rate observation", + "for": { + "reference": "Patient/{{patientId}}" + }, + "owner": { + "reference": "Practitioner/{{practitionerId}}" + }, + "authoredOn": "2026-07-22T10:00:00Z" + } +} + +assert { + res.status: eq 201 + res.body.resourceType: eq Task +} + +script:post-response { + if (res.body && res.body.id) { + bru.setVar("taskId", res.body.id); + } +} + +docs { + A follow-up task for the patient, owned by the practitioner. Expect `201`. + Saves `taskId`. +} diff --git a/eng/bruno/Fhir/Resources/Task/folder.bru b/eng/bruno/Fhir/Resources/Task/folder.bru new file mode 100644 index 00000000..f25dab9a --- /dev/null +++ b/eng/bruno/Fhir/Resources/Task/folder.bru @@ -0,0 +1,7 @@ +meta { + name: Task +} + +docs { + Create, update and search examples for `Task`. Needs `patientId` and `practitionerId`. +} diff --git a/eng/bruno/Fhir/Resources/Task/search-tasks-for-patient.bru b/eng/bruno/Fhir/Resources/Task/search-tasks-for-patient.bru new file mode 100644 index 00000000..fc5e966f --- /dev/null +++ b/eng/bruno/Fhir/Resources/Task/search-tasks-for-patient.bru @@ -0,0 +1,20 @@ +meta { + name: Search Tasks for patient + type: http + seq: 4 +} + +get { + url: {{fhirBase}}/Task?patient=Patient/{{patientId}} + body: none + auth: inherit +} + +assert { + res.status: eq 200 + res.body.resourceType: eq Bundle +} + +docs { + Tasks where `Task.for` references the patient. Expect `200` with a `searchset` `Bundle`. +} diff --git a/eng/bruno/Fhir/Resources/Task/update-task-complete.bru b/eng/bruno/Fhir/Resources/Task/update-task-complete.bru new file mode 100644 index 00000000..5a338df9 --- /dev/null +++ b/eng/bruno/Fhir/Resources/Task/update-task-complete.bru @@ -0,0 +1,42 @@ +meta { + name: Update Task (mark completed) + type: http + seq: 3 +} + +put { + url: {{fhirBase}}/Task/{{taskId}} + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Task", + "id": "{{taskId}}", + "status": "completed", + "intent": "order", + "description": "Follow up on abnormal heart rate observation", + "for": { + "reference": "Patient/{{patientId}}" + }, + "owner": { + "reference": "Practitioner/{{practitionerId}}" + }, + "authoredOn": "2026-07-22T10:00:00Z", + "lastModified": "2026-07-22T12:00:00Z" + } +} + +assert { + res.status: eq 200 + res.body.resourceType: eq Task +} + +docs { + Moves the task to `completed`. Needs `taskId`. Expect `200` with a bumped `meta.versionId`. +} diff --git a/eng/bruno/Fhir/Resources/folder.bru b/eng/bruno/Fhir/Resources/folder.bru new file mode 100644 index 00000000..3886d121 --- /dev/null +++ b/eng/bruno/Fhir/Resources/folder.bru @@ -0,0 +1,4 @@ +meta { + name: Resources + seq: 4 +} diff --git a/eng/bruno/Fhir/Terminology/create-valueset.bru b/eng/bruno/Fhir/Terminology/create-valueset.bru new file mode 100644 index 00000000..1dce4583 --- /dev/null +++ b/eng/bruno/Fhir/Terminology/create-valueset.bru @@ -0,0 +1,46 @@ +meta { + name: Create ValueSet (valid) + type: http + seq: 3 +} + +post { + url: {{fhirBase}}/ValueSet + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "ValueSet", + "url": "http://example.org/ValueSet/gender-subset", + "status": "active", + "compose": { + "include": [ + { + "system": "http://hl7.org/fhir/administrative-gender", + "concept": [{ "code": "male" }, { "code": "female" }] + } + ] + } + } +} + +assert { + res.status: eq 201 + res.body.resourceType: eq ValueSet +} + +script:post-response { + if (res.body && res.body.id) { + bru.setVar("valueSetId", res.body.id); + } +} + +docs { + Expect `201`. Saves `valueSetId` for the stored-expansion requests. +} diff --git a/eng/bruno/Fhir/Terminology/expand-by-url.bru b/eng/bruno/Fhir/Terminology/expand-by-url.bru new file mode 100644 index 00000000..16feb170 --- /dev/null +++ b/eng/bruno/Fhir/Terminology/expand-by-url.bru @@ -0,0 +1,25 @@ +meta { + name: Expand ValueSet by url + type: http + seq: 1 +} + +get { + url: {{fhirBase}}/ValueSet/$expand?url=http://hl7.org/fhir/ValueSet/administrative-gender + body: none + auth: inherit +} + +params:query { + url: http://hl7.org/fhir/ValueSet/administrative-gender +} + +assert { + res.status: eq 200 + res.body.resourceType: eq ValueSet +} + +docs { + Expands a canonical that resolves from the loaded packages. `filter`, `offset` and + `count` narrow the result. +} diff --git a/eng/bruno/Fhir/Terminology/expand-from-body.bru b/eng/bruno/Fhir/Terminology/expand-from-body.bru new file mode 100644 index 00000000..4d10a708 --- /dev/null +++ b/eng/bruno/Fhir/Terminology/expand-from-body.bru @@ -0,0 +1,34 @@ +meta { + name: Expand ValueSet from body + type: http + seq: 2 +} + +post { + url: {{fhirBase}}/ValueSet/$expand + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Parameters", + "parameter": [ + { "name": "url", "valueUri": "http://hl7.org/fhir/ValueSet/administrative-gender" }, + { "name": "filter", "valueString": "fem" } + ] + } +} + +assert { + res.status: eq 200 + res.body.resourceType: eq ValueSet +} + +docs { + Same operation via a `Parameters` body, which also accepts an inline `valueSet`. +} diff --git a/eng/bruno/Fhir/Terminology/expand-stored-conflicting-url.bru b/eng/bruno/Fhir/Terminology/expand-stored-conflicting-url.bru new file mode 100644 index 00000000..70d26e2d --- /dev/null +++ b/eng/bruno/Fhir/Terminology/expand-stored-conflicting-url.bru @@ -0,0 +1,33 @@ +meta { + name: Expand stored ValueSet (conflicting url) + type: http + seq: 5 +} + +post { + url: {{fhirBase}}/ValueSet/{{valueSetId}}/$expand + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Parameters", + "parameter": [ + { "name": "url", "valueUri": "http://hl7.org/fhir/ValueSet/administrative-gender" } + ] + } +} + +assert { + res.status: eq 400 +} + +docs { + The id in the path already identifies the ValueSet, so `url` or `valueSet` in the + body is rejected. Modifier parameters like `filter` are fine. +} diff --git a/eng/bruno/Fhir/Terminology/expand-stored.bru b/eng/bruno/Fhir/Terminology/expand-stored.bru new file mode 100644 index 00000000..03b14285 --- /dev/null +++ b/eng/bruno/Fhir/Terminology/expand-stored.bru @@ -0,0 +1,20 @@ +meta { + name: Expand stored ValueSet + type: http + seq: 4 +} + +get { + url: {{fhirBase}}/ValueSet/{{valueSetId}}/$expand + body: none + auth: inherit +} + +assert { + res.status: eq 200 + res.body.resourceType: eq ValueSet +} + +docs { + Expands a ValueSet held in the store. Needs `valueSetId` from **Create ValueSet**. +} diff --git a/eng/bruno/Fhir/Terminology/folder.bru b/eng/bruno/Fhir/Terminology/folder.bru new file mode 100644 index 00000000..77304103 --- /dev/null +++ b/eng/bruno/Fhir/Terminology/folder.bru @@ -0,0 +1,4 @@ +meta { + name: Terminology + seq: 5 +} diff --git a/eng/bruno/Fhir/Validation/folder.bru b/eng/bruno/Fhir/Validation/folder.bru new file mode 100644 index 00000000..093bf42e --- /dev/null +++ b/eng/bruno/Fhir/Validation/folder.bru @@ -0,0 +1,4 @@ +meta { + name: Validation + seq: 6 +} diff --git a/eng/bruno/Fhir/Validation/validate-patient-against-profile.bru b/eng/bruno/Fhir/Validation/validate-patient-against-profile.bru new file mode 100644 index 00000000..f48bd8c6 --- /dev/null +++ b/eng/bruno/Fhir/Validation/validate-patient-against-profile.bru @@ -0,0 +1,38 @@ +meta { + name: Validate Patient against profile + type: http + seq: 2 +} + +post { + url: {{fhirBase}}/Patient/$validate?profile=http://hl7.org/fhir/StructureDefinition/Patient + body: json + auth: inherit +} + +params:query { + profile: http://hl7.org/fhir/StructureDefinition/Patient +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Patient", + "name": [ + { + "family": "Test", + "given": ["Ada"] + } + ], + "gender": "female", + "birthDate": "1990-01-01" + } +} + +docs { + Validates against an explicit `?profile=` canonical. `meta.profile` on the resource + is validated too. +} diff --git a/eng/bruno/Fhir/Validation/validate-patient-base-fnr-ok.bru b/eng/bruno/Fhir/Validation/validate-patient-base-fnr-ok.bru new file mode 100644 index 00000000..a44bc9f6 --- /dev/null +++ b/eng/bruno/Fhir/Validation/validate-patient-base-fnr-ok.bru @@ -0,0 +1,35 @@ +meta { + name: Validate Patient against base (same FNR body — passes) + type: http + seq: 5 +} + +post { + url: {{fhirBase}}/Patient/$validate + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Patient", + "identifier": [ + { + "system": "urn:oid:2.16.578.1.12.4.1.4.1" + } + ] + } +} + +assert { + res.status: eq 200 + res.body.resourceType: eq OperationOutcome +} + +docs { + The same body against base R4, which allows a missing `Identifier.value` — passes. +} diff --git a/eng/bruno/Fhir/Validation/validate-patient-instance.bru b/eng/bruno/Fhir/Validation/validate-patient-instance.bru new file mode 100644 index 00000000..3fa1a47f --- /dev/null +++ b/eng/bruno/Fhir/Validation/validate-patient-instance.bru @@ -0,0 +1,38 @@ +meta { + name: Validate Patient (instance) + type: http + seq: 6 +} + +post { + url: {{fhirBase}}/Patient/{{patientId}}/$validate + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Patient", + "name": [ + { + "family": "Test", + "given": ["Ada"] + } + ], + "gender": "female" + } +} + +assert { + res.status: eq 200 + res.body.resourceType: eq OperationOutcome +} + +docs { + Instance-level `$validate`. The body is still what gets validated; the id only + addresses the endpoint. Needs `patientId`. +} diff --git a/eng/bruno/Fhir/Validation/validate-patient-no-basis-fnr-invalid.bru b/eng/bruno/Fhir/Validation/validate-patient-no-basis-fnr-invalid.bru new file mode 100644 index 00000000..b76343e1 --- /dev/null +++ b/eng/bruno/Fhir/Validation/validate-patient-no-basis-fnr-invalid.bru @@ -0,0 +1,41 @@ +meta { + name: Validate Patient against no-basis (FNR without value) + type: http + seq: 4 +} + +post { + url: {{fhirBase}}/Patient/$validate?profile=http://hl7.no/fhir/StructureDefinition/no-basis-Patient + body: json + auth: inherit +} + +params:query { + profile: http://hl7.no/fhir/StructureDefinition/no-basis-Patient +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Patient", + "identifier": [ + { + "system": "urn:oid:2.16.578.1.12.4.1.4.1" + } + ] + } +} + +assert { + res.status: eq 200 + res.body.resourceType: eq OperationOutcome + res.body.issue[0].severity: eq error +} + +docs { + The FNR slice in no-basis-Patient requires `value`, omitted here — expect an `error` + on `identifier[FNR]`. Needs `hl7.fhir.no.basis` loaded on the server. +} diff --git a/eng/bruno/Fhir/Validation/validate-patient-unresolvable-profile.bru b/eng/bruno/Fhir/Validation/validate-patient-unresolvable-profile.bru new file mode 100644 index 00000000..e51cd4ff --- /dev/null +++ b/eng/bruno/Fhir/Validation/validate-patient-unresolvable-profile.bru @@ -0,0 +1,36 @@ +meta { + name: Validate Patient (unresolvable profile) + type: http + seq: 3 +} + +post { + url: {{fhirBase}}/Patient/$validate?profile=http://example.org/StructureDefinition/DoesNotExist + body: json + auth: inherit +} + +params:query { + profile: http://example.org/StructureDefinition/DoesNotExist +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Patient", + "name": [ + { + "family": "Test", + "given": ["Ada"] + } + ] + } +} + +docs { + Unknown `?profile=` canonical. Expect `200` with an issue saying the profile could + not be resolved. +} diff --git a/eng/bruno/Fhir/Validation/validate-patient-valid.bru b/eng/bruno/Fhir/Validation/validate-patient-valid.bru new file mode 100644 index 00000000..b7aec6c3 --- /dev/null +++ b/eng/bruno/Fhir/Validation/validate-patient-valid.bru @@ -0,0 +1,38 @@ +meta { + name: Validate Patient (valid) + type: http + seq: 1 +} + +post { + url: {{fhirBase}}/Patient/$validate + body: json + auth: inherit +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Patient", + "name": [ + { + "family": "Test", + "given": ["Ada"] + } + ], + "gender": "female", + "birthDate": "1990-01-01" + } +} + +vars:pre-request { + baseUrl: https://localhost:5201/ +} + +docs { + Validates against the base `Patient` type. Expect `200` with an information-only + `OperationOutcome`. +} diff --git a/eng/bruno/Fhir/Validation/validate-questionnaire-cross-version-profile.bru b/eng/bruno/Fhir/Validation/validate-questionnaire-cross-version-profile.bru new file mode 100644 index 00000000..d998109c --- /dev/null +++ b/eng/bruno/Fhir/Validation/validate-questionnaire-cross-version-profile.bru @@ -0,0 +1,40 @@ +meta { + name: Validate Questionnaire (cross-version profile) + type: http + seq: 7 +} + +post { + url: {{fhirBase}}/Questionnaire/$validate?profile=http://hl7.org/fhir/5.0/StructureDefinition/profile-Questionnaire + body: json + auth: inherit +} + +params:query { + profile: http://hl7.org/fhir/5.0/StructureDefinition/profile-Questionnaire +} + +headers { + Content-Type: application/fhir+json +} + +body:json { + { + "resourceType": "Questionnaire", + "status": "draft", + "title": "Cross-version validation example" + } +} + +assert { + res.status: eq 200 + res.body.resourceType: eq OperationOutcome + res.body.issue[0].code: eq not-supported +} + +docs { + A cross-version profile pins an extension version the loaded packages do not carry, so + its schema will not compile. Expect `200` with a `not-supported` error naming the + missing dependency — not a `500`. These profiles are kept out of `$profiles`, so the + canonical has to be typed by hand. Needs `hl7.fhir.uv.xver-r5.r4` loaded. +} diff --git a/eng/bruno/Fhir/capability-statement.bru b/eng/bruno/Fhir/capability-statement.bru new file mode 100644 index 00000000..ffc216d5 --- /dev/null +++ b/eng/bruno/Fhir/capability-statement.bru @@ -0,0 +1,16 @@ +meta { + name: Capability statement + type: http + seq: 2 +} + +get { + url: {{fhirBase}}/metadata + body: none + auth: none +} + +docs { + The server's `CapabilityStatement`. + Anonymous — no token needed. +} diff --git a/eng/bruno/Fhir/folder.bru b/eng/bruno/Fhir/folder.bru new file mode 100644 index 00000000..991b6b2e --- /dev/null +++ b/eng/bruno/Fhir/folder.bru @@ -0,0 +1,8 @@ +meta { + name: Fhir + seq: 2 +} + +docs { + Resource CRUD, search, operations and validation. All requests target `{{fhirBase}}`. +} diff --git a/eng/bruno/Ignis/Auth/get-token.bru b/eng/bruno/Ignis/Auth/get-token.bru new file mode 100644 index 00000000..ce9f6f3b --- /dev/null +++ b/eng/bruno/Ignis/Auth/get-token.bru @@ -0,0 +1,33 @@ +meta { + name: Get token + type: http + seq: 1 +} + +post { + url: {{tokenUrl}} + body: formUrlEncoded + auth: none +} + +headers { + Accept: application/json +} + +body:form-urlencoded { + grant_type: client_credentials + client_id: {{clientId}} + client_secret: {{clientSecret}} +} + +script:post-response { + // Store the token so the collection's Bearer auth ({{accessToken}}) can use it. + if (res.body && res.body.access_token) { + bru.setVar("accessToken", res.body.access_token); + } +} + +docs { + OAuth2 `client_credentials` against `/connect/token`. Stores `accessToken` for every + other request — run this first, and again on 401. +} diff --git a/eng/bruno/Ignis/Conformance/packages.bru b/eng/bruno/Ignis/Conformance/packages.bru new file mode 100644 index 00000000..5f092fdf --- /dev/null +++ b/eng/bruno/Ignis/Conformance/packages.bru @@ -0,0 +1,20 @@ +meta { + name: Loaded packages + type: http + seq: 2 +} + +get { + url: {{fhirBase}}/$packages + body: none + auth: inherit +} + +assert { + res.status: eq 200 + res.body.resourceType: eq Parameters +} + +docs { + FHIR packages installed on the server, one `package` parameter each. +} diff --git a/eng/bruno/Ignis/Conformance/profiles.bru b/eng/bruno/Ignis/Conformance/profiles.bru new file mode 100644 index 00000000..85a57978 --- /dev/null +++ b/eng/bruno/Ignis/Conformance/profiles.bru @@ -0,0 +1,21 @@ +meta { + name: Supported profiles + type: http + seq: 1 +} + +get { + url: {{fhirBase}}/StructureDefinition/$profiles + body: none + auth: inherit +} + +assert { + res.status: eq 200 + res.body.resourceType: eq Bundle +} + +docs { + Resource-constraint profiles from the loaded packages, as a `searchset` `Bundle` of + metadata-only `StructureDefinition`s. +} diff --git a/eng/bruno/Ignis/Import/archive-import-limits.bru b/eng/bruno/Ignis/Import/archive-import-limits.bru new file mode 100644 index 00000000..8b720b4e --- /dev/null +++ b/eng/bruno/Ignis/Import/archive-import-limits.bru @@ -0,0 +1,16 @@ +meta { + name: Archive import limits + type: http + seq: 1 +} + +get { + url: {{fhirBase}}/$archive-import + body: none + auth: inherit +} + +docs { + Configured upload limits as a `Parameters` resource. Requires `operations.import` + and the `AllowImport` flag. +} diff --git a/eng/bruno/Ignis/Import/archive-import.bru b/eng/bruno/Ignis/Import/archive-import.bru new file mode 100644 index 00000000..79572f42 --- /dev/null +++ b/eng/bruno/Ignis/Import/archive-import.bru @@ -0,0 +1,22 @@ +meta { + name: Archive import + type: http + seq: 2 +} + +post { + url: {{fhirBase}}/$archive-import + body: multipartForm + auth: inherit +} + +body:multipart-form { + file: @file(path/to/archive.zip) +} + +docs { + Uploads a zip of FHIR resources for background ingestion; point the + `body:multipart-form` block at a real file first. Expect `202` with the operation id. + + Requires `operations.import` and the `AllowImport` flag. +} diff --git a/eng/bruno/Ignis/Maintenance/clear-store.bru b/eng/bruno/Ignis/Maintenance/clear-store.bru new file mode 100644 index 00000000..cf58ac76 --- /dev/null +++ b/eng/bruno/Ignis/Maintenance/clear-store.bru @@ -0,0 +1,17 @@ +meta { + name: Clear store (destructive) + type: http + seq: 2 +} + +post { + url: {{fhirBase}}/$clear-store + body: none + auth: inherit +} + +docs { + ⚠️ DESTRUCTIVE — wipes the entire FHIR store. Dev only. + + Requires `maintenance/database.destructive` and the `AllowClearStore` flag. +} diff --git a/eng/bruno/Ignis/Maintenance/rebuild-index.bru b/eng/bruno/Ignis/Maintenance/rebuild-index.bru new file mode 100644 index 00000000..33324f6b --- /dev/null +++ b/eng/bruno/Ignis/Maintenance/rebuild-index.bru @@ -0,0 +1,16 @@ +meta { + name: Rebuild index + type: http + seq: 1 +} + +post { + url: {{fhirBase}}/$rebuild-index + body: none + auth: inherit +} + +docs { + Rebuilds the search index from store contents. Requires the + `maintenance/database.write` scope — see README → Scopes. +} diff --git a/eng/bruno/Ignis/folder.bru b/eng/bruno/Ignis/folder.bru new file mode 100644 index 00000000..cc182ef2 --- /dev/null +++ b/eng/bruno/Ignis/folder.bru @@ -0,0 +1,9 @@ +meta { + name: Ignis + seq: 1 +} + +docs { + Ignis-specific endpoints: auth, loaded profiles and packages, archive import, + maintenance and health. +} diff --git a/eng/bruno/Ignis/health.bru b/eng/bruno/Ignis/health.bru new file mode 100644 index 00000000..4e5e5cad --- /dev/null +++ b/eng/bruno/Ignis/health.bru @@ -0,0 +1,19 @@ +meta { + name: Health + type: http + seq: 1 +} + +get { + url: {{baseUrl}}/healthz + body: none + auth: none +} + +vars:pre-request { + baseUrl: https://localhost:5201 +} + +docs { + Liveness probe. Anonymous — returns `ok`. +} diff --git a/eng/bruno/README.md b/eng/bruno/README.md new file mode 100644 index 00000000..a91a1362 --- /dev/null +++ b/eng/bruno/README.md @@ -0,0 +1,38 @@ +# Ignis FHIR server — Bruno collection + +[Bruno](https://www.usebruno.com/) requests for poking at a running Ignis FHIR +API by hand. + +## Setup + +1. **Open Collection** → this `eng/bruno` folder, then select the + **ignis-local** environment. +2. Fill in `clientSecret` in the environment editor. It's a Bruno _secret + variable_ (never committed); the dev value matches `ignis-client` in + `appsettings.json`. +3. Disable TLS verification for the collection (self-signed dev cert). +4. Run the API, then run **Auth → Get token**: it stores `accessToken`, which + every request sends as a Bearer header. Re-run it on 401. + +## Scoped operations + +Most requests need no scope. Exceptions: + +| Request | Scope | Also needs | +| ---------------------------------- | ---------------------------------- | ---------------------- | +| Maintenance → Rebuild index | `maintenance/database.write` | — | +| Maintenance → Clear store | `maintenance/database.destructive` | `AllowClearStore` flag | +| Import → Archive import (+ limits) | `operations.import` | `AllowImport` flag | + +The default token has no scopes, so these return `403`. To fix: add the scopes +to the `ignis-client` entry's `AllowedScopes` in `appsettings.local.json` +(otherwise the token request fails with `invalid_scope`), then add a +space-separated `scope` field to the **Get token** body and re-run it. A missing +feature flag returns `404`/`503`. + +## Gotchas + +- Keep `baseUrl` and `tokenUrl` on the same `https://localhost:5201` origin — an + http→https redirect drops the `Authorization` header (→ 401). +- Bruno's built-in collection OAuth2 didn't attach the token reliably, hence the + explicit Get token request + Bearer variable. diff --git a/eng/bruno/bruno.json b/eng/bruno/bruno.json new file mode 100644 index 00000000..f117733b --- /dev/null +++ b/eng/bruno/bruno.json @@ -0,0 +1,6 @@ +{ + "version": "1", + "name": "Ignis FHIR server", + "type": "collection", + "ignore": ["node_modules", ".git"] +} diff --git a/eng/bruno/collection.bru b/eng/bruno/collection.bru new file mode 100644 index 00000000..ca0fb8f0 --- /dev/null +++ b/eng/bruno/collection.bru @@ -0,0 +1,18 @@ +headers { + Accept: application/fhir+json +} + +auth { + mode: bearer +} + +auth:bearer { + token: {{accessToken}} +} + +docs { + # Ignis FHIR API + + Select the **ignis-local** environment, then run **Ignis → Auth → Get token** first — + every request inherits its Bearer token. Setup, scopes and TLS: see the README. +} diff --git a/eng/bruno/environments/hapi-public.bru b/eng/bruno/environments/hapi-public.bru new file mode 100644 index 00000000..ef4cfcba --- /dev/null +++ b/eng/bruno/environments/hapi-public.bru @@ -0,0 +1,4 @@ +vars { + baseUrl: https://hapi.fhir.org + fhirBase: https://hapi.fhir.org/baseR4 +} diff --git a/eng/bruno/environments/ignis-local.bru b/eng/bruno/environments/ignis-local.bru new file mode 100644 index 00000000..193841a9 --- /dev/null +++ b/eng/bruno/environments/ignis-local.bru @@ -0,0 +1,9 @@ +vars { + baseUrl: https://localhost:5201 + fhirBase: https://localhost:5201/fhir + tokenUrl: https://localhost:5201/connect/token + clientId: ignis-client +} +vars:secret [ + clientSecret +] diff --git a/eng/bruno/environments/ignis-public.bru b/eng/bruno/environments/ignis-public.bru new file mode 100644 index 00000000..05e5d927 --- /dev/null +++ b/eng/bruno/environments/ignis-public.bru @@ -0,0 +1,9 @@ +vars { + baseUrl: https://ignis.incendi.no + fhirBase: https://ignis.incendi.no/fhir + tokenUrl: https://ignis.incendi.no/connect/token + clientId: ignis-client +} +vars:secret [ + clientSecret +] diff --git a/eng/bruno/environments/spark-local.bru b/eng/bruno/environments/spark-local.bru new file mode 100644 index 00000000..3c9a2a56 --- /dev/null +++ b/eng/bruno/environments/spark-local.bru @@ -0,0 +1,4 @@ +vars { + baseUrl: https://localhost:5001 + fhirBase: https://localhost:5001/fhir +} diff --git a/eng/bruno/environments/spark-public.bru b/eng/bruno/environments/spark-public.bru new file mode 100644 index 00000000..d9df64df --- /dev/null +++ b/eng/bruno/environments/spark-public.bru @@ -0,0 +1,4 @@ +vars { + baseUrl: https://spark.incendi.no + fhirBase: https://spark.incendi.no/fhir +}