Skip to content

Commit f596c88

Browse files
[ERSSUP-80439]-[JW/AP/DW]-[Finalise OAS and sandbox of R4 retrieve binary endpoint]-[FV]
1 parent f4721d7 commit f596c88

File tree

66 files changed

+641
-335
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+641
-335
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<AssignMessage async="false" continueOnError="false" enabled="true" name="AssignMessage.AddBaseUrlHeader">
2+
<Set>
3+
<Headers>
4+
<Header name="x-ers-sandbox-baseurl">https://{request.header.Host}/{proxy.basepath}</Header>
5+
</Headers>
6+
</Set>
7+
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
8+
<AssignTo createNew="false"/>
9+
</AssignMessage>

proxies/sandbox/apiproxy/targets/sandbox.xml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@
77
<Response/>
88
</PostFlow>
99
<PreFlow name="PreFlow">
10-
<Request/>
11-
<Response></Response>
10+
<Request>
11+
<Step>
12+
<Name>AssignMessage.AddBaseUrlHeader</Name>
13+
</Step>
14+
</Request>
15+
<Response/>
1216
</PreFlow>
1317
<HTTPTargetConnection>{{ HOSTED_TARGET_CONNECTION }}</HTTPTargetConnection>
1418
</TargetEndpoint>

sandbox/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
FROM node:18.3.0-alpine3.14
22

3-
ENV npm_config_cache /home/node/app/.npm
3+
ENV npm_config_cache=/home/node/app/.npm
44

55
WORKDIR /app
66

sandbox/src/app.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,24 @@ const Inert = require('@hapi/inert')
44
const process = require('process')
55
const routes = require('./routes')
66

7+
/*
8+
The purpose of this logic is to mirror the transformations the API proxy currently applies to responses.
9+
This allows the sandbox to have the same behaviour locally.
10+
*/
711
const addCommonHeaders = function (request, response) {
812
// if a response doesn't include any headers provide an empty object to allow for the common headers to be appended.
913
if (!response.headers) {
1014
response.headers = {}
1115
}
1216

17+
// API proxy always adds x-correlation-id to responses.
1318
if (request.headers["x-correlation-id"]) {
1419
response.headers["X-Correlation-ID"] = request.headers["x-correlation-id"]
1520
}
16-
response.headers["X-Request-ID"] = '58621d65-d5ad-4c3a-959f-0438e355990e-1'
21+
22+
if (!request.path.includes("/ObjectStore")) {
23+
response.headers["X-Request-ID"] = '58621d65-d5ad-4c3a-959f-0438e355990e-1'
24+
}
1725
}
1826

1927
const preResponse = function (request, h) {
23.1 KB
Binary file not shown.

sandbox/src/services/businessFunctionValidator.js renamed to sandbox/src/routes/common/validationUtils.js

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
1+
/**
2+
* @file validationUtil.js
3+
* @description Provides utility functions.
4+
*/
15

2-
module.exports = {
3-
validateBusinessFunction: function (request, h, allowedBusinessFunctions) {
6+
function isValidUuid(string) {
7+
return /^[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i.test(string);
8+
}
9+
10+
function hasLegacyPrefix(string) {
11+
return string.startsWith('att-');
12+
}
13+
14+
function validateBusinessFunction(request, h, allowedBusinessFunctions) {
415
const requestedBusinessFunction = request.headers["nhsd-ers-business-function"]
516
const oboUserId = request.headers["nhsd-ers-on-behalf-of-user-id"]
617

@@ -13,7 +24,6 @@ module.exports = {
1324
if (requestedBusinessFunction === 'SERVICE_PROVIDER_CLINICIAN_ADMIN') {
1425
if (!oboUserId) {
1526
return h.response('SANDBOX_ERROR: When this endpoint is accessed using the e-RS SERVICE_PROVIDER_CLINICIAN_ADMIN Business Function then an On-Behalf-Of User ID must be provided').code(403)
16-
.code(403)
1727
}
1828
}
1929
else {
@@ -24,5 +34,10 @@ module.exports = {
2434
}
2535

2636
return undefined;
27-
}
2837
}
38+
39+
module.exports = {
40+
isValidUuid,
41+
hasLegacyPrefix,
42+
validateBusinessFunction
43+
};

sandbox/src/routes/index.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,13 @@ const retrieveOboUsers = require('./r4/retrieveOboUsers')
4242
const retrieveHealthcareService = require('./r4/retrieveHealthcareService')
4343
const searchForHealthcareServices = require('./r4/searchForHealthcareServices')
4444
const searchServiceRequest = require('./r4/searchServiceRequest')
45-
const retrieveBinary = require('./r4/retrieveBinary')
46-
const retrieveBinaryHelper = require('./r4/retrieveBinaryHelper')
45+
const retrieveAttachmentR4 = require('./r4/retrieveAttachment')
46+
47+
/**
48+
* Services
49+
*/
50+
const objectStore = require('./objectStore')
51+
4752

4853
const routes = [].concat(
4954
getStatus,
@@ -83,8 +88,8 @@ const routes = [].concat(
8388
retrieveAdviceAndGuidanceOverviewPdf,
8489
searchServiceRequest,
8590
createAdviceAndGuidance,
86-
retrieveBinary,
87-
retrieveBinaryHelper
91+
retrieveAttachmentR4,
92+
objectStore
8893
)
8994

9095
module.exports = routes

sandbox/src/routes/objectStore.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
module.exports = [
2+
/**
3+
* Sandbox implementation of an object store.
4+
*/
5+
{
6+
method: 'GET',
7+
path: '/ObjectStore/{fileId}',
8+
handler: (request, h) => {
9+
10+
const fileId = request.params.fileId;
11+
const filePath = '../mocks/r4/retrieveAttachment/example_attachment.pdf';
12+
const responseCode = 200;
13+
14+
if (fileId === 'd497bbe3-f88b-45f1-b3d4-9c563e4c0f5f') {
15+
return h.file(filePath, { etagMethod: false })
16+
.code(responseCode)
17+
.header('Content-Disposition', `attachment; filename="=?UTF-8?Q?The_filenam=C3=A9.pdf?="; filename*=UTF-8''The%20filenam%C3%A9.pdf`)
18+
.header('Content-Type', 'application/pdf');
19+
}
20+
}
21+
}
22+
]
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
const validationUtils = require('../common/validationUtils')
2+
3+
module.exports = [
4+
/**
5+
* Sandbox implementation for Retrieve attachment A042 (R4) endpoint
6+
*/
7+
{
8+
method: 'GET',
9+
path: '/FHIR/R4/Binary/{binaryId}',
10+
handler: (request, h) => {
11+
12+
const allowedBusinessFunctions = ["REFERRING_CLINICIAN", "REFERRING_CLINICIAN_ADMIN", "SERVICE_PROVIDER_CLINICIAN", "SERVICE_PROVIDER_CLINICIAN_ADMIN"];
13+
14+
const validationResult = validationUtils.validateBusinessFunction(request, h, allowedBusinessFunctions);
15+
if (validationResult) {
16+
return validationResult;
17+
}
18+
19+
const binaryId = request.params.binaryId;
20+
const objectStore = "/ObjectStore/d497bbe3-f88b-45f1-b3d4-9c563e4c0f5f";
21+
const location = request.headers['x-ers-sandbox-baseurl'] + objectStore;
22+
23+
if ((validationUtils.hasLegacyPrefix(binaryId) || validationUtils.isValidUuid(binaryId)) && request.method === 'get') {
24+
const response = h.response().code(307);
25+
response.headers["Location"] = location;
26+
return response;
27+
} else {
28+
return h.file('r4/R4-SandboxErrorOutcome.json').code(400);
29+
}
30+
}
31+
}
32+
]

sandbox/src/routes/r4/retrieveBinary.js

Lines changed: 0 additions & 34 deletions
This file was deleted.

0 commit comments

Comments
 (0)