Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions gateway-api/tests/manual-test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Manual API Test – Steel Thread

This folder contains a **manual API test** used to support the **steel thread** for the Clinical Data Gateway (CDG).

The intent of this test is to:

- Validate that a response is returned using the **expected structure**
- Support early preparation and understanding only

This is **not automated testing** and **does not prove functional completeness**.

## Steel Thread Scope

For the steel thread, CDG supports **reading a patient record for a single patient** using the following structure:

```bash
POST https://[CDG_server]/FHIR/STU3/patient/$gpc.getstructuredrecord
```

- FHIR version: **STU3**
- Format: **FHIR JSON**
- Operation: **custom GP Connect FHIR operation**
- Scope: **single patient**

No error handling, authentication edge cases, or non-happy paths are covered.

## Tooling

This manual test uses **usebruno** as the API testing tool.

Bruno is:

- Free and open source
- Installed locally

The Bruno collection for this test lives **inside this repository**, so no external workspace or account is required.

## Installing Bruno (macOS)

Bruno can be installed using Homebrew.

1. Install Homebrew:

```bash
https://brew.sh/
```

2. Install Bruno:

```bash
brew install bruno
```

3. Launch Bruno:

```bash
bruno
```

## Opening the Bruno Collection

To add it in Bruno:

1. Open Bruno
2. Select **Open Collection**
3. Navigate to:

```text
clinical-data-gateway-api/gateway-api/tests/manual-test/api-test
```

4. Open the folder

The collection is now loaded and ready to use.

## Running the Manual Test

1. Select the **Retrieve Patient Record** request in the collection
2. Set Bruno to use the local environment
3. In terminal run `node mock-response.js`. Output should read `Mock Retrieve Patient Record server running at http://localhost:8080`
4. Send the request

A successful response should return a **FHIR STU3 response** that aligns with the expected steel-thread response shape.

```json
POST {{environment}}/FHIR/STU3/patient/$gpc.getstructuredrecord
Content-Type: application/fhir+json
Accept: application/fhir+json
{
"resourceType": "Parameters",
"parameter": [
{
"name": "patientNHSNumber",
"valueIdentifier": {
"system": "https://fhir.nhs.uk/Id/nhs-number",
"value": "9999999999"
}
}
]
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
meta {
name: Retrieve Patient Record
type: http
seq: 3
}

post {
url: {{environment}}/FHIR/STU3/patient/$gpc.getstructuredrecord
body: text
auth: inherit
}

headers {
Ssp-TraceID: {{$guid}}
Ssp-From: 200000000359
Ssp-To: 918999198738
Accept: application/fhir+json
Ssp-InteractionId: urn:nhs:names:services:gpconnect:fhir:operation:gpc.getstructuredrecord-1
Authorization: Bearer {{jwt_token}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there something somewhere to set

{{jwt_token}}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not yet - I left it in until we had an environment to use it on and then tidy the headers up from there

Content-Type: application/fhir+json
}

body:text {
{"resourceType":"Parameters","parameter":[{"name":"patientNHSNumber","valueIdentifier":{"system":"https://fhir.nhs.uk/Id/nhs-number","value":"9690938118"}},{"name":"includeAllergies","part":[{"name":"includeResolvedAllergies","valueBoolean":true}]}]}
}

settings {
encodeUrl: true
timeout: 0
}

docs {
Required JWT Scope: patient/*.read
}

example {
name: Example 200 Response

request: {
url: {{environment}}/B82617/STU3/1/gpconnect/structured/fhir/Patient/$gpc.getstructuredrecord
method: POST
mode: text
headers: {
Ssp-TraceID: 369ae31c-8bfc-4df1-9861-1640c914c7f5
Ssp-From: 200000000359
Ssp-To: 918999198738
Accept: application/fhir+json
Ssp-InteractionId: urn:nhs:names:services:gpconnect:fhir:operation:gpc.getstructuredrecord-1
}

body:text: {
{"resourceType":"Parameters","parameter":[{"name":"patientNHSNumber","valueIdentifier":{"system":"https://fhir.nhs.uk/Id/nhs-number","value":"9690938118"}},{"name":"includeAllergies","part":[{"name":"includeResolvedAllergies","valueBoolean":true}]}]}
}
}

response: {
headers: {
Transfer-Encoding: chunked
Connection: keep-alive
Strict-Transport-Security: max-age=31536000
Cache-Control: no-store
Date: Mon, 15 Sep 2025 15:14:46 GMT
Location: https://{{environment}}/B82617/STU3/1/gpconnect/fhir/Bundle/369ae31c-8bfc-4df1-9861-1640c914c7f5
Server: nginx
X-Powered-By: HAPI FHIR 3.0.0 REST Server (FHIR Server; FHIR 3.0.1/DSTU3)
Content-Type: application/fhir+json; charset=UTF-8
}

status: {
code: OK
text: 200
}
body: {
type: text
content: '''
{"resourceType":"Bundle","id":"369ae31c-8bfc-4df1-9861-1640c914c7f5","meta":{"profile":["https://fhir.nhs.uk/STU3/StructureDefinition/GPConnect-StructuredRecord-Bundle-1"]},"type":"collection","entry":[{"resource":{"resourceType":"Patient","id":"16","meta":{"versionId":"1521806400000","profile":["https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-Patient-1"]},"extension":[{"url":"https://fhir.nhs.uk/STU3/StructureDefinition/Extension-CareConnect-GPC-RegistrationDetails-1","extension":[{"url":"registrationPeriod","valuePeriod":{"start":"1962-07-13T00:00:00+01:00"}}]},{"url":"https://fhir.nhs.uk/STU3/StructureDefinition/Extension-CareConnect-GPC-NHSCommunication-1","extension":[{"url":"language","valueCodeableConcept":{"coding":[{"system":"https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-HumanLanguage-1","code":"en","display":"English"}]}},{"url":"preferred","valueBoolean":false},{"url":"modeOfCommunication","valueCodeableConcept":{"coding":[{"system":"https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-LanguageAbilityMode-1","code":"RWR","display":"Received written"}]}},{"url":"communicationProficiency","valueCodeableConcept":{"coding":[{"system":"https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-LanguageAbilityProficiency-1","code":"E","display":"Excellent"}]}},{"url":"interpreterRequired","valueBoolean":false}]}],"identifier":[{"extension":[{"url":"https://fhir.nhs.uk/STU3/StructureDefinition/Extension-CareConnect-GPC-NHSNumberVerificationStatus-1","valueCodeableConcept":{"coding":[{"system":"https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-NHSNumberVerificationStatus-1","code":"01","display":"Number present and verified"}]}}],"system":"https://fhir.nhs.uk/Id/nhs-number","value":"9690938118"}],"active":true,"name":[{"use":"official","text":"Sibyl CRAINE","family":"CRAINE","given":["Sibyl"],"prefix":["MRS"]}],"telecom":[{"system":"phone","value":"01454587554","use":"home"}],"gender":"female","birthDate":"1983-11-24","address":[{"use":"home","type":"physical","line":["1 LANGHAM WALK"],"city":"STOCKTON-ON-TEES","district":"CLEVELAND","postalCode":"TS19 7NX"}],"generalPractitioner":[{"reference":"Practitioner/1"}],"managingOrganization":{"reference":"Organization/7"}}},{"resource":{"resourceType":"List","meta":{"profile":["https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-List-1"]},"extension":[{"url":"https://fhir.nhs.uk/STU3/StructureDefinition/Extension-CareConnect-GPC-ListWarningCode-1","valueCode":"confidential-items"},{"url":"https://fhir.nhs.uk/STU3/StructureDefinition/Extension-CareConnect-GPC-ListWarningCode-1","valueCode":"data-in-transit"},{"url":"https://fhir.nhs.uk/STU3/StructureDefinition/Extension-CareConnect-GPC-ClinicalSetting-1","valueCodeableConcept":{"coding":[{"system":"http://snomed.info/sct","code":"1060971000000108","display":"General practice service"}]}}],"status":"current","mode":"snapshot","title":"Allergies and adverse reactions","code":{"coding":[{"system":"http://snomed.info/sct","code":"886921000000105","display":"Allergies and adverse reactions"}]},"subject":{"identifier":{"system":"https://fhir.nhs.uk/Id/nhs-number","value":"9690938118"}},"note":[{"text":"Items excluded due to confidentiality and/or patient preferences.\r\nPatient record transfer from previous GP practice not yet complete; information recorded before 08-Sep-2025 may be missing.\r\nInformation not available"}],"emptyReason":{"coding":[{"system":"https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-ListEmptyReasonCode-1","code":"no-content-recorded","display":"No Content Recorded"}]}}},{"resource":{"resourceType":"List","meta":{"profile":["https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-List-1"]},"contained":[{"resourceType":"AllergyIntolerance","id":"11","meta":{"profile":["https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-AllergyIntolerance-1"]},"extension":[{"url":"https://fhir.nhs.uk/STU3/StructureDefinition/Extension-CareConnect-GPC-AllergyIntoleranceEnd-1","extension":[{"url":"endDate","valueDateTime":"2016-07-01T12:00:00+01:00"},{"url":"reasonEnded","valueString":"No information available"}]}],"identifier":[{"system":"https://fhir.nhs.uk/Id/cross-care-setting-identifier","value":"b6c0cd9c-8600-11f0-9e03-00505692d4aa"}],"clinicalStatus":"resolved","verificationStatus":"unconfirmed","category":["medication"],"code":{"coding":[{"system":"http://snomed.info/sct","code":"294716003","display":"Biphasic insulin allergy (disorder)"}]},"patient":{"reference":"Patient/16"},"onsetDateTime":"2016-05-01T12:00:00+01:00","assertedDate":"2016-06-01T12:00:00+01:00","recorder":{"reference":"Practitioner/5"},"lastOccurrence":"2016-07-01T12:00:00+01:00","note":[{"text":"Vomiting and diarrhoea"}],"reaction":[{"manifestation":[{"coding":[{"system":"http://snomed.info/sct","code":"49237006","display":"Allergic diarrhea (disorder)"}]}],"description":"Vomiting and diarrhoea"}]},{"resourceType":"AllergyIntolerance","id":"12","meta":{"profile":["https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-AllergyIntolerance-1"]},"extension":[{"url":"https://fhir.nhs.uk/STU3/StructureDefinition/Extension-CareConnect-GPC-AllergyIntoleranceEnd-1","extension":[{"url":"endDate","valueDateTime":"2016-07-02T12:00:00+01:00"},{"url":"reasonEnded","valueString":"No information available"}]}],"identifier":[{"system":"https://fhir.nhs.uk/Id/cross-care-setting-identifier","value":"b6c0ce77-8600-11f0-9e03-00505692d4aa"}],"clinicalStatus":"resolved","verificationStatus":"unconfirmed","category":["medication"],"code":{"coding":[{"system":"http://snomed.info/sct","code":"294716003","display":"Biphasic insulin allergy (disorder)"}]},"patient":{"reference":"Patient/16"},"onsetDateTime":"2016-05-02T12:00:00+01:00","assertedDate":"2016-06-02T12:00:00+01:00","recorder":{"reference":"Practitioner/5"},"lastOccurrence":"2016-07-02T12:00:00+01:00","note":[{"text":"Vomiting and diarrhoea"}],"reaction":[{"manifestation":[{"coding":[{"system":"http://snomed.info/sct","code":"49237006","display":"Allergic diarrhea (disorder)"}]}],"description":"Vomiting and diarrhoea"}]}],"extension":[{"url":"https://fhir.nhs.uk/STU3/StructureDefinition/Extension-CareConnect-GPC-ListWarningCode-1","valueCode":"confidential-items"},{"url":"https://fhir.nhs.uk/STU3/StructureDefinition/Extension-CareConnect-GPC-ListWarningCode-1","valueCode":"data-in-transit"},{"url":"https://fhir.nhs.uk/STU3/StructureDefinition/Extension-CareConnect-GPC-ClinicalSetting-1","valueCodeableConcept":{"coding":[{"system":"http://snomed.info/sct","code":"1060971000000108","display":"General practice service"}]}}],"status":"current","mode":"snapshot","title":"Ended allergies","code":{"coding":[{"system":"http://snomed.info/sct","code":"1103671000000101","display":"Ended allergies"}]},"subject":{"identifier":{"system":"https://fhir.nhs.uk/Id/nhs-number","value":"9690938118"}},"note":[{"text":"Items excluded due to confidentiality and/or patient preferences.\r\nPatient record transfer from previous GP practice not yet complete; information recorded before 08-Sep-2025 may be missing."}],"entry":[{"item":{"reference":"#11"}},{"item":{"reference":"#12"}}]}},{"resource":{"resourceType":"Practitioner","id":"1","meta":{"versionId":"1469444400000","lastUpdated":"2016-07-25T12:00:00.000+01:00","profile":["https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-Practitioner-1"]},"extension":[{"url":"https://fhir.nhs.uk/STU3/StructureDefinition/Extension-CareConnect-GPC-NHSCommunication-1","extension":[{"url":"language","valueCodeableConcept":{"coding":[{"system":"https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-HumanLanguage-1","code":"de","display":"German"}]}}]},{"url":"https://fhir.nhs.uk/STU3/StructureDefinition/Extension-CareConnect-GPC-NHSCommunication-1","extension":[{"url":"language","valueCodeableConcept":{"coding":[{"system":"https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-HumanLanguage-1","code":"en","display":"English"}]}}]}],"identifier":[{"system":"https://fhir.nhs.uk/Id/sds-user-id","value":"G13579135"}],"name":[{"use":"usual","family":"Gilbert","given":["Nichole"],"prefix":["Miss"]}],"gender":"female"}},{"resource":{"resourceType":"Practitioner","id":"5","meta":{"versionId":"1469444400000","lastUpdated":"2016-07-25T12:00:00.000+01:00","profile":["https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-Practitioner-1"]},"extension":[{"url":"https://fhir.nhs.uk/STU3/StructureDefinition/Extension-CareConnect-GPC-NHSCommunication-1","extension":[{"url":"language","valueCodeableConcept":{"coding":[{"system":"https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-HumanLanguage-1","code":"en","display":"English"}]}}]}],"identifier":[{"system":"https://fhir.nhs.uk/Id/sds-user-id","value":"G22222226"},{"system":"https://fhir.nhs.uk/Id/sds-role-profile-id","value":"PT2222"},{"system":"https://fhir.nhs.uk/Id/sds-role-profile-id","value":"PT4444"}],"name":[{"use":"usual","family":"Parsons","given":["Melissa"],"prefix":["Mrs"]}],"gender":"female"}},{"resource":{"resourceType":"PractitionerRole","id":"PT2222","meta":{"profile":["https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-PractitionerRole-1"]},"practitioner":{"reference":"Practitioner/5"},"organization":{"reference":"Organization/2"},"code":[{"coding":[{"system":"https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-SDSJobRoleName-1","code":"R0042","display":"paediatrician"}]}]}},{"resource":{"resourceType":"PractitionerRole","id":"PT4444","meta":{"profile":["https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-PractitionerRole-1"]},"practitioner":{"reference":"Practitioner/5"},"organization":{"reference":"Organization/2"},"code":[{"coding":[{"system":"https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-SDSJobRoleName-1","code":"R0042","display":"paediatrician"}]}]}},{"resource":{"resourceType":"Organization","id":"2","meta":{"versionId":"1469444400000","lastUpdated":"2016-07-25T12:00:00.000+01:00","profile":["https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-Organization-1"]},"identifier":[{"system":"https://fhir.nhs.uk/Id/ods-organization-code","value":"R1A14"}],"name":"Test GP Care Trust","telecom":[{"system":"phone","value":"12345678","use":"work"}],"address":[{"use":"work","line":["24 Back Lane","Farsley"],"city":"Leeds","district":"West Yorkshire","postalCode":"GPC 113"}]}},{"resource":{"resourceType":"Organization","id":"7","meta":{"versionId":"1469444400000","lastUpdated":"2016-07-25T12:00:00.000+01:00","profile":["https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-Organization-1"]},"identifier":[{"system":"https://fhir.nhs.uk/Id/ods-organization-code","value":"B82617"}],"name":"COXWOLD SURGERY","telecom":[{"system":"phone","value":"12345678","use":"work"}],"address":[{"use":"work","line":["NHS NPFIT Test Data Manager","Princes Exchange"],"city":"Leeds","district":"West Yorkshire","postalCode":"LS1 4HY"}]}}]}
'''
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
meta {
name: Set to localhost
type: http
seq: 4
}

get {
url: https://pokeapi.co/api/v2/pokemon/garchomp
body: none
auth: inherit
}

script:pre-request {
bru.setEnvVar('environment', 'localhost:8080');
}

settings {
encodeUrl: true
timeout: 0
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"version": "1",
"name": "api-gateway",
"type": "collection",
"ignore": [
"node_modules",
".git"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
const http = require('http');

const PORT = 8080;

const RESPONSE_BODY = {
"resourceType":"Bundle",
"id":"369ae31c-8bfc-4df1-9861-1640c914c7f5",
"meta":{"profile":["https://fhir.nhs.uk/STU3/StructureDefinition/GPConnect-StructuredRecord-Bundle-1"]},
"type":"collection",
"entry":[
{
"resource":{
"resourceType":"Patient",
"id":"16",
"meta":{
"versionId":"1521806400000",
"profile":["https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-Patient-1"]
},
"identifier":[
{
"system":"https://fhir.nhs.uk/Id/nhs-number",
"value":"9690938118"
}
],
"active":true,
"name":[
{
"use":"official",
"text":"Sibyl CRAINE",
"family":"CRAINE",
"given":["Sibyl"],
"prefix":["MRS"]
}
],
"gender":"female",
"birthDate":"1983-11-24"
}
}
]
};


const server = http.createServer((req, res) => {
if (
req.method === 'POST' &&
req.url === '/FHIR/STU3/patient/$gpc.getstructuredrecord'
) {
res.writeHead(200, {
'Content-Type': 'application/fhir+json'
});

res.end(JSON.stringify(RESPONSE_BODY, null, 2));
return;
}

res.writeHead(404);
res.end('Not Found');
});

server.listen(PORT, () => {
console.log(`Mock Retrieve Patient Record server running at http://localhost:${PORT}`);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
vars {
environment: 127.0.0.1:8080
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have port 8080 in this file and in the mock-response.js file - can we store it in one place and share it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah from reading up i am not sure that its possible - feel free to resolve this if you find the same

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok thanks

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,6 @@ Syft
Terraform
toolchain
Trufflehog
usebruno
VMs
[Vv]scode
Loading