From d5ed4558c75aac8a59a9ae029213751a45b3ec3d Mon Sep 17 00:00:00 2001 From: Francisco Videira Date: Tue, 10 May 2022 13:37:00 +0000 Subject: [PATCH] [ERSSUP-61674]-[JW/AO]-[Retrieve Binary R4 API design]-[FV] --- sandbox/src/routes/index.js | 6 +++- sandbox/src/routes/r4/retrieveBinary.js | 34 +++++++++++++++++++ sandbox/src/routes/r4/retrieveBinaryHelper.js | 25 ++++++++++++++ scripts/populate_placeholders.py | 1 + scripts/validate_oas_examples.py | 3 +- ...uest-pre-signed-url-for-file-download.yaml | 28 +++++++++++++++ .../pathParameters/AttachmentUuid.yaml | 8 +++++ .../responses/retrieveBinary/307Response.yaml | 12 +++++++ .../responses/retrieveBinary/400Response.yaml | 20 +++++++++++ specification/e-referrals-service-api.yaml | 3 ++ 10 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 sandbox/src/routes/r4/retrieveBinary.js create mode 100644 sandbox/src/routes/r4/retrieveBinaryHelper.js create mode 100644 specification/components/r4/schemas/endpoints/a042-request-pre-signed-url-for-file-download.yaml create mode 100644 specification/components/r4/schemas/pathParameters/AttachmentUuid.yaml create mode 100644 specification/components/r4/schemas/responses/retrieveBinary/307Response.yaml create mode 100644 specification/components/r4/schemas/responses/retrieveBinary/400Response.yaml diff --git a/sandbox/src/routes/index.js b/sandbox/src/routes/index.js index 043ddf66a..204e1eb78 100644 --- a/sandbox/src/routes/index.js +++ b/sandbox/src/routes/index.js @@ -42,6 +42,8 @@ const retrieveHealthcareService = require('./r4/retrieveHealthcareService') const searchForHealthcareServices = require('./r4/searchForHealthcareServices') const searchServiceRequest = require('./r4/searchServiceRequest') const requestUploadUri = require('./r4/requestUploadUri') +const retrieveBinary = require('./r4/retrieveBinary') +const retrieveBinaryHelper = require('./r4/retrieveBinaryHelper') const routes = [].concat( getStatus, @@ -80,7 +82,9 @@ const routes = [].concat( retrieveAppointment, retrieveAdviceAndGuidanceOverviewPdf, searchServiceRequest, - requestUploadUri + requestUploadUri, + retrieveBinary, + retrieveBinaryHelper ) module.exports = routes diff --git a/sandbox/src/routes/r4/retrieveBinary.js b/sandbox/src/routes/r4/retrieveBinary.js new file mode 100644 index 000000000..e6b5f84fb --- /dev/null +++ b/sandbox/src/routes/r4/retrieveBinary.js @@ -0,0 +1,34 @@ +const businessFunctionValidator = require('../../services/businessFunctionValidator') + +module.exports = [ + /** + * Sandbox implementation for retrieveBinary A039 (R4) endpoint + */ + { + method: 'GET', + path: '/FHIR/R4/Binary/{attachmentUuid}', + handler: (request, h) => { + + const allowedBusinessFunctions = ["REFERRING_CLINICIAN", "REFERRING_CLINICIAN_ADMIN", "SERVICE_PROVIDER_CLINICIAN", "SERVICE_PROVIDER_CLINICIAN_ADMIN"] + + const validationResult = businessFunctionValidator.validateBusinessFunction(request, h, allowedBusinessFunctions) + if (validationResult) { + return validationResult + } + + const uuid = request.params.attachmentUuid; + const url = request.url.href; + const objectStore = "/ObjectStore/RetrieveBinary/d497bbe3-f88b-45f1-b3d4-9c563e4c0f5f"; + const location = url.split('/FHIR')[0] + objectStore; + + if (uuid === '704c3791-0873-45e9-9a04-b51996f8d93f' && request.method === 'get') { + const response = h.response().code(307) + response.headers["Location"] = location; + return response + } else { + return h.file('SandboxErrorOutcome.json').code(422); + } + + } + } +] diff --git a/sandbox/src/routes/r4/retrieveBinaryHelper.js b/sandbox/src/routes/r4/retrieveBinaryHelper.js new file mode 100644 index 000000000..e72ccc3c5 --- /dev/null +++ b/sandbox/src/routes/r4/retrieveBinaryHelper.js @@ -0,0 +1,25 @@ +module.exports = [ + /** + * Sandbox implementation for retrieveBinary (R4) endpoint helper, + * with an ObjectStore 'mock', allowing redirection and example file retrieval. + */ + { + method: 'GET', + path: '/ObjectStore/RetrieveBinary/{fileDownloadUuid}', + handler: (request, h) => { + + const uuid = request.params.fileDownloadUuid + const exampleResponsePath = 'retrieveAttachment/responses/example_attachment.pdf' + const filename = 'example_attachment.pdf' + const responseCode = 200 + + if (uuid === 'd497bbe3-f88b-45f1-b3d4-9c563e4c0f5f') { + return h.file(exampleResponsePath, { + mode: 'attachment', + filename: filename, + etagMethod: false + }).code(responseCode); + } + } + } +] diff --git a/scripts/populate_placeholders.py b/scripts/populate_placeholders.py index 5f8a40ab7..7a92bc59a 100644 --- a/scripts/populate_placeholders.py +++ b/scripts/populate_placeholders.py @@ -47,6 +47,7 @@ def main(): "[[HYPERLINK_A040]]": "[A040 - Retrieve e-RS-Specific Practitioner Information](#api-Default-a040-retrieve-practitioner-info)", "[[HYPERLINK_A041]]": "[A041 - Search for service requests](#api-Default-a041-search-service-request)", "[[HYPERLINK_A043]]": "[A043 - Retrieve advice and guidance overview PDF](#api-Default-a043-retrieve-advice-and-guidance-overview-pdf)", + "[[HYPERLINK_A042]]": "[A042 - Request pre-signed URL to download file from document store](#api-Default-a042-request-pre-signed-url-for-file-download)", "[[HYPERLINK_ONBOARDING]]": "[onboarding](#api-description__onboarding)", "[[HYPERLINK_STABLE]]": "[stable](https://digital.nhs.uk/developer/guides-and-documentation/reference-guide#api-status)", "[[HYPERLINK_BETA]]": "[beta](https://digital.nhs.uk/developer/guides-and-documentation/reference-guide#api-status)", diff --git a/scripts/validate_oas_examples.py b/scripts/validate_oas_examples.py index 2375b7079..2e21cf899 100644 --- a/scripts/validate_oas_examples.py +++ b/scripts/validate_oas_examples.py @@ -36,7 +36,7 @@ http_methods = ["post", "put", "patch", "get", "head", "delete"] # List containing http success response codes -http_success_codes = ["200", "201"] +http_success_codes = ["200", "201", "307"] # Open OAS JSON file try: @@ -149,6 +149,7 @@ def get_success_code(endpoint, http_method): ].keys() ) filtered_code = filter(lambda x: x in http_success_codes, endpoint_return_codes) + return list(filtered_code)[0] diff --git a/specification/components/r4/schemas/endpoints/a042-request-pre-signed-url-for-file-download.yaml b/specification/components/r4/schemas/endpoints/a042-request-pre-signed-url-for-file-download.yaml new file mode 100644 index 000000000..af3c937ad --- /dev/null +++ b/specification/components/r4/schemas/endpoints/a042-request-pre-signed-url-for-file-download.yaml @@ -0,0 +1,28 @@ +security: + - bearerAuth: [] +description: | + ### TODO Add later +summary: A042 - Request pre-signed URL to download file from document store +operationId: a042-request-pre-signed-url-for-file-download +parameters: + - $ref: '../headers/request/BearerAuthorization.yaml' + - $ref: '../headers/request/BusinessFunction.yaml' + - $ref: '../headers/request/CorrelationID.yaml' + - $ref: '../headers/request/OdsCode.yaml' + - $ref: '../headers/request/OnBehalfOfUserID.yaml' + - $ref: '../pathParameters/AttachmentUuid.yaml' +responses: + '307': + $ref: '../responses/retrieveBinary/307Response.yaml' + '400': + $ref: '../responses/retrieveBinary/400Response.yaml' + '401': + $ref: '../responses/R4-Unauthorized.yaml' + '403': + $ref: '../responses/R4-Forbidden.yaml' + '404': + $ref: '../responses/R4-NotFound.yaml' + '429': + $ref: '../responses/R4-TooManyRequests.yaml' + '500': + $ref: '../responses/R4-InternalServerError.yaml' diff --git a/specification/components/r4/schemas/pathParameters/AttachmentUuid.yaml b/specification/components/r4/schemas/pathParameters/AttachmentUuid.yaml new file mode 100644 index 000000000..58ed1617b --- /dev/null +++ b/specification/components/r4/schemas/pathParameters/AttachmentUuid.yaml @@ -0,0 +1,8 @@ +in: path +name: id +description: | + Reference for an attachment, as provided in the response from [[HYPERLINK_A039]]. +required: true +schema: + type: string + example: '704c3791-0873-45e9-9a04-b51996f8d93f' diff --git a/specification/components/r4/schemas/responses/retrieveBinary/307Response.yaml b/specification/components/r4/schemas/responses/retrieveBinary/307Response.yaml new file mode 100644 index 000000000..1bc1499ff --- /dev/null +++ b/specification/components/r4/schemas/responses/retrieveBinary/307Response.yaml @@ -0,0 +1,12 @@ +description: Response redirects user agent to the large file attachment URL in the Object Store via the Location header. +headers: + x-correlation-id: + $ref: '../../headers/response/CorrelationID.yaml' + x-request-id: + $ref: '../../headers/response/RequestID.yaml' + Location: + description: The large file attachment location in the Object Store. + required: true + schema: + type: string + example: '' diff --git a/specification/components/r4/schemas/responses/retrieveBinary/400Response.yaml b/specification/components/r4/schemas/responses/retrieveBinary/400Response.yaml new file mode 100644 index 000000000..e0e96314d --- /dev/null +++ b/specification/components/r4/schemas/responses/retrieveBinary/400Response.yaml @@ -0,0 +1,20 @@ +description: | + Where status code 400 (Bad Request) is returned then an [NHSDigital-OperationOutcome](https://fhir.nhs.uk/StructureDefinition/NHSDigital-OperationOutcome) will be included in the body, as detailed below. + Check diagnostics property for specific information regarding the error. + + | issue.details.coding.code | issue.code | Description | + | ------------------------- | ------------ | ----------------------------------------------------- | + | REC_BAD_REQUEST | required | TODO:63315 | +headers: + x-correlation-id: + $ref: '../../headers/response/CorrelationID.yaml' + x-request-id: + $ref: '../../headers/response/RequestID.yaml' + Content-Type: + $ref: '../../headers/response/ContentTypeFhirJson.yaml' +content: + application/fhir+json: + schema: + $ref: '../../NHSDigital-OperationOutcome.yaml' + example: + $ref: '../../../examples/NHSDigital-OperationOutcome.json' diff --git a/specification/e-referrals-service-api.yaml b/specification/e-referrals-service-api.yaml index 01ffca0df..1eec78a4e 100644 --- a/specification/e-referrals-service-api.yaml +++ b/specification/e-referrals-service-api.yaml @@ -385,6 +385,9 @@ paths: /R4/ServiceRequest/{id}/$ers.generateUploadURI: post: $ref: 'components/r4/schemas/endpoints/a039-request-pre-signed-url-for-file-upload.yaml' + /R4/Binary/{id}: + get: + $ref: 'components/r4/schemas/endpoints/a042-request-pre-signed-url-for-file-download.yaml' components: securitySchemes: bearerAuth: