Skip to content

Commit fbede50

Browse files
further sandbox examples including handling request body
1 parent e690d02 commit fbede50

File tree

16 files changed

+392
-28
lines changed

16 files changed

+392
-28
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,4 @@ dist
2424
.DS_Store
2525
.reports
2626
/sandbox/*.log
27+
/sandbox-staging

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ bundle-oas:
7474

7575
generate-sandbox:
7676
$(MAKE) build-json-oas-spec APIM_ENV=sandbox
77-
jq --slurpfile status sandbox/HealthcheckEndpoint.json '.paths += $status[0]' build/notify-supplier.json > tmp.json && mv tmp.json build/notify-supplier.json
77+
jq --slurpfile status sandbox/HealthcheckEndpoint.json '.paths += $$status[0]' build/notify-supplier.json > tmp.json && mv tmp.json build/notify-supplier.json
7878
npm run generate-sandbox
7979

8080
serve-swagger:

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
"bundle-oas": "mkdir -p build && redocly bundle specification/api/notify-supplier-phase1.yml --dereferenced -k --remove-unused-components --ext yml > build/notify-supplier.yml",
5151
"generate": "npm run generate:cs --buildver=$npm_config_buildver && npm run generate:html && npm run generate:ts --buildver=$npm_config_buildver && npm run generate:python",
5252
"generate-dependencies": "npm run generate-dependencies --workspaces --if-present",
53-
"generate-sandbox": "openapi-generator-cli generate -g nodejs-express-server -i build/notify-supplier.yml --skip-validate-spec -o sandbox",
53+
"generate-sandbox": "openapi-generator-cli generate -g nodejs-express-server -i build/notify-supplier.json --skip-validate-spec -o sandbox-staging",
5454
"generate:cs": "./sdk/generate-cs.sh $npm_config_buildver",
5555
"generate:cs-server": "./server/generate-cs-server.sh $npm_config_buildver",
5656
"generate:html": "docker run --rm --user $(id -u) -v ${PWD}:/local openapitools/openapi-generator-cli generate -i /local/build/notify-supplier.yml -g html -o /local/sdk/html --skip-validate-spec",

sandbox/api/openapi.yaml

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,18 @@ paths:
6969
- FORWARDED
7070
type: string
7171
style: form
72+
- description: |-
73+
The ordinal number of the page of results to be retrieved. If omitted, the
74+
first page of results will be returned. Use the links section in the response
75+
body to determine whether any further pages of results exist.
76+
explode: true
77+
in: query
78+
name: page
79+
required: false
80+
schema:
81+
example: 1
82+
type: number
83+
style: form
7284
responses:
7385
"200":
7486
content:
@@ -197,7 +209,7 @@ paths:
197209
id: 2WL5eYSWGzCHlGmzNxuqVusPxDg
198210
type: Letter
199211
schema:
200-
$ref: "#/components/schemas/listLetters_200_response"
212+
$ref: "#/components/schemas/postLetters_200_response"
201213
description: Letter Resources Updated successfully
202214
"404":
203215
content:
@@ -972,6 +984,38 @@ paths:
972984
x-eov-operation-handler: controllers/DefaultController
973985
components:
974986
schemas:
987+
listLetters_200_response_links:
988+
additionalProperties: false
989+
description: Contains links to other data pages
990+
properties:
991+
last:
992+
description: URI of final page of data
993+
example: https://dev.api.service.nhs.uk/nhs-notify-supplier/letters?status=PENDING&page=10
994+
format: uri
995+
type: string
996+
next:
997+
description: URI of next page of data
998+
example: https://dev.api.service.nhs.uk/nhs-notify-supplier/letters?status=PENDING&page=5
999+
format: uri
1000+
type: string
1001+
prev:
1002+
description: URI of prev page of data
1003+
example: https://dev.api.service.nhs.uk/nhs-notify-supplier/letters?status=PENDING&page=7
1004+
format: uri
1005+
type: string
1006+
self:
1007+
description: URI of current page of data
1008+
example: https://dev.api.service.nhs.uk/nhs-notify-supplier/letters?status=PENDING&page=6
1009+
format: uri
1010+
type: string
1011+
type: object
1012+
postLetters_200_response:
1013+
properties:
1014+
data:
1015+
items:
1016+
$ref: "#/components/schemas/listLetters_200_response_data_inner"
1017+
type: array
1018+
type: object
9751019
createMI_request_data:
9761020
properties:
9771021
type:
@@ -1086,6 +1130,8 @@ components:
10861130
items:
10871131
$ref: "#/components/schemas/listLetters_200_response_data_inner"
10881132
type: array
1133+
links:
1134+
$ref: "#/components/schemas/listLetters_200_response_links"
10891135
type: object
10901136
getLetterStatus_200_response:
10911137
properties:
@@ -1094,6 +1140,8 @@ components:
10941140
type: object
10951141
postLetters_request_data_inner_attributes:
10961142
properties:
1143+
specificationId:
1144+
type: string
10971145
status:
10981146
default: PENDING
10991147
description: The supplier status of an individual letter

sandbox/controllers/Controller.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class Controller {
6161
if (codeGenDefinedBodyName !== undefined) {
6262
return codeGenDefinedBodyName;
6363
}
64-
const refObjectPath = request.openapi.schema.requestBody.content['application/json'].schema.$ref;
64+
const refObjectPath = request.openapi.schema.requestBody.content['application/vnd.api+json'].schema.$ref;
6565
if (refObjectPath !== undefined && refObjectPath.length > 0) {
6666
return (refObjectPath.substr(refObjectPath.lastIndexOf('/') + 1));
6767
}
@@ -72,7 +72,7 @@ class Controller {
7272
const requestParams = {};
7373
if (request.openapi.schema.requestBody !== null) {
7474
const { content } = request.openapi.schema.requestBody;
75-
if (content['application/json'] !== undefined) {
75+
if (content['application/vnd.api+json'] !== undefined) {
7676
const requestBodyName = camelCase(this.getRequestBodyName(request));
7777
requestParams[requestBodyName] = request.body;
7878
} else if (content['multipart/form-data'] !== undefined) {
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
{
2+
"data": [
3+
{
4+
"attributes": {
5+
"requestedProductionStatus": "ACTIVE",
6+
"specificationId": "2WL5eYSWGzCHlGmzNxuqVusPxDg",
7+
"status": "PENDING"
8+
},
9+
"id": "31B68ctLKWlhxsoil13zANnOXDs",
10+
"type": "Letter"
11+
},
12+
{
13+
"attributes": {
14+
"requestedProductionStatus": "ACTIVE",
15+
"specificationId": "2WL5eYSWGzCHlGmzNxuqVusPxDg",
16+
"status": "PENDING"
17+
},
18+
"id": "31B68hADL5mBayE3gDOnQeQ7RGr",
19+
"type": "Letter"
20+
},
21+
{
22+
"attributes": {
23+
"requestedProductionStatus": "ACTIVE",
24+
"specificationId": "2WL5eYSWGzCHlGmzNxuqVusPxDg",
25+
"status": "PENDING"
26+
},
27+
"id": "31B68hesrGUpMmPzvBErnZ3Nx1s",
28+
"type": "Letter"
29+
},
30+
{
31+
"attributes": {
32+
"requestedProductionStatus": "ACTIVE",
33+
"specificationId": "2WL5eYSWGzCHlGmzNxuqVusPxDg",
34+
"status": "PENDING"
35+
},
36+
"id": "31B68gtwhetFGlca6JdckCLduQJ",
37+
"type": "Letter"
38+
},
39+
{
40+
"attributes": {
41+
"requestedProductionStatus": "ACTIVE",
42+
"specificationId": "2WL5eYSWGzCHlGmzNxuqVusPxDg",
43+
"status": "PENDING"
44+
},
45+
"id": "31B68fX5yazsb8XtbIKvnH7lyFV",
46+
"type": "Letter"
47+
},
48+
{
49+
"attributes": {
50+
"requestedProductionStatus": "ACTIVE",
51+
"specificationId": "2WL5eYSWGzCHlGmzNxuqVusPxDg",
52+
"status": "PENDING"
53+
},
54+
"id": "31B68cdGh1HVxxqsSTVezoulItF",
55+
"type": "Letter"
56+
},
57+
{
58+
"attributes": {
59+
"requestedProductionStatus": "ACTIVE",
60+
"specificationId": "2WL5eYSWGzCHlGmzNxuqVusPxDg",
61+
"status": "PENDING"
62+
},
63+
"id": "31B68ctCLllXxrmkrrcent290Jv",
64+
"type": "Letter"
65+
}
66+
],
67+
"links": {
68+
"last": "https://api.service.nhs.uk/nhs-notify-supplier/letters?status=PENDING&page=10",
69+
"prev": "https://api.service.nhs.uk/nhs-notify-supplier/letters?status=PENDING&page=9",
70+
"self": "https://api.service.nhs.uk/nhs-notify-supplier/letters?status=PENDING&page=10"
71+
}
72+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
{
2+
"data": [
3+
{
4+
"attributes": {
5+
"requestedProductionStatus": "ACTIVE",
6+
"specificationId": "2WL5eYSWGzCHlGmzNxuqVusPxDg",
7+
"status": "PENDING"
8+
},
9+
"id": "31B68ctLKWlhxsoil13zANnOXDs",
10+
"type": "Letter"
11+
},
12+
{
13+
"attributes": {
14+
"requestedProductionStatus": "ACTIVE",
15+
"specificationId": "2WL5eYSWGzCHlGmzNxuqVusPxDg",
16+
"status": "PENDING"
17+
},
18+
"id": "31B68hADL5mBayE3gDOnQeQ7RGr",
19+
"type": "Letter"
20+
},
21+
{
22+
"attributes": {
23+
"requestedProductionStatus": "ACTIVE",
24+
"specificationId": "2WL5eYSWGzCHlGmzNxuqVusPxDg",
25+
"status": "PENDING"
26+
},
27+
"id": "31B68hesrGUpMmPzvBErnZ3Nx1s",
28+
"type": "Letter"
29+
},
30+
{
31+
"attributes": {
32+
"requestedProductionStatus": "ACTIVE",
33+
"specificationId": "2WL5eYSWGzCHlGmzNxuqVusPxDg",
34+
"status": "PENDING"
35+
},
36+
"id": "31B68gtwhetFGlca6JdckCLduQJ",
37+
"type": "Letter"
38+
},
39+
{
40+
"attributes": {
41+
"requestedProductionStatus": "ACTIVE",
42+
"specificationId": "2WL5eYSWGzCHlGmzNxuqVusPxDg",
43+
"status": "PENDING"
44+
},
45+
"id": "31B68fX5yazsb8XtbIKvnH7lyFV",
46+
"type": "Letter"
47+
},
48+
{
49+
"attributes": {
50+
"requestedProductionStatus": "ACTIVE",
51+
"specificationId": "2WL5eYSWGzCHlGmzNxuqVusPxDg",
52+
"status": "PENDING"
53+
},
54+
"id": "31B68cdGh1HVxxqsSTVezoulItF",
55+
"type": "Letter"
56+
},
57+
{
58+
"attributes": {
59+
"requestedProductionStatus": "ACTIVE",
60+
"specificationId": "2WL5eYSWGzCHlGmzNxuqVusPxDg",
61+
"status": "PENDING"
62+
},
63+
"id": "31B68ctCLllXxrmkrrcent290Jv",
64+
"type": "Letter"
65+
}
66+
],
67+
"links": {
68+
"last": "https://api.service.nhs.uk/nhs-notify-supplier/letters?status=PENDING&page=10",
69+
"next": "https://api.service.nhs.uk/nhs-notify-supplier/letters?status=PENDING&page=6",
70+
"prev": "https://api.service.nhs.uk/nhs-notify-supplier/letters?status=PENDING&page=4",
71+
"self": "https://api.service.nhs.uk/nhs-notify-supplier/letters?status=PENDING&page=5"
72+
}
73+
}

sandbox/data/examples/getLetters/responses/getLetters_pending.json

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,67 @@
66
"specificationId": "2WL5eYSWGzCHlGmzNxuqVusPxDg",
77
"status": "PENDING"
88
},
9-
"id": "2WL5eYSWGzCHlGmzNxuqVusPxDg",
9+
"id": "31B68ctLKWlhxsoil13zANnOXDs",
10+
"type": "Letter"
11+
},
12+
{
13+
"attributes": {
14+
"requestedProductionStatus": "ACTIVE",
15+
"specificationId": "2WL5eYSWGzCHlGmzNxuqVusPxDg",
16+
"status": "PENDING"
17+
},
18+
"id": "31B68hADL5mBayE3gDOnQeQ7RGr",
19+
"type": "Letter"
20+
},
21+
{
22+
"attributes": {
23+
"requestedProductionStatus": "ACTIVE",
24+
"specificationId": "2WL5eYSWGzCHlGmzNxuqVusPxDg",
25+
"status": "PENDING"
26+
},
27+
"id": "31B68hesrGUpMmPzvBErnZ3Nx1s",
28+
"type": "Letter"
29+
},
30+
{
31+
"attributes": {
32+
"requestedProductionStatus": "ACTIVE",
33+
"specificationId": "2WL5eYSWGzCHlGmzNxuqVusPxDg",
34+
"status": "PENDING"
35+
},
36+
"id": "31B68gtwhetFGlca6JdckCLduQJ",
37+
"type": "Letter"
38+
},
39+
{
40+
"attributes": {
41+
"requestedProductionStatus": "ACTIVE",
42+
"specificationId": "2WL5eYSWGzCHlGmzNxuqVusPxDg",
43+
"status": "PENDING"
44+
},
45+
"id": "31B68fX5yazsb8XtbIKvnH7lyFV",
46+
"type": "Letter"
47+
},
48+
{
49+
"attributes": {
50+
"requestedProductionStatus": "ACTIVE",
51+
"specificationId": "2WL5eYSWGzCHlGmzNxuqVusPxDg",
52+
"status": "PENDING"
53+
},
54+
"id": "31B68cdGh1HVxxqsSTVezoulItF",
55+
"type": "Letter"
56+
},
57+
{
58+
"attributes": {
59+
"requestedProductionStatus": "ACTIVE",
60+
"specificationId": "2WL5eYSWGzCHlGmzNxuqVusPxDg",
61+
"status": "PENDING"
62+
},
63+
"id": "31B68ctCLllXxrmkrrcent290Jv",
1064
"type": "Letter"
1165
}
12-
]
66+
],
67+
"links": {
68+
"last": "https://api.service.nhs.uk/nhs-notify-supplier/letters?status=PENDING&page=10",
69+
"next": "https://api.service.nhs.uk/nhs-notify-supplier/letters?status=PENDING&page=2",
70+
"self": "https://api.service.nhs.uk/nhs-notify-supplier/letters?status=PENDING&page=1"
71+
}
1372
}

sandbox/expressServer.js

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ const bodyParser = require('body-parser');
1111
const OpenApiValidator = require('express-openapi-validator');
1212
const logger = require('./logger');
1313
const config = require('./config');
14+
const getRawBody = require('raw-body');
15+
const contentType = require('content-type');
1416

1517
class ExpressServer {
1618
constructor(port, openApiYaml) {
@@ -29,8 +31,11 @@ class ExpressServer {
2931
// this.setupAllowedMedia();
3032
this.app.use(cors());
3133
this.app.use(bodyParser.json({ limit: '14MB' }));
32-
this.app.use(express.json());
33-
this.app.use(express.urlencoded({ extended: false }));
34+
this.app.use(express.json({
35+
type: ['application/json', 'application/vnd.api+json']
36+
}));
37+
this.app.use(express.urlencoded({ extended: true }));
38+
3439
this.app.use(cookieParser());
3540
// Simple test to see that the server is up and responding
3641
this.app.get('/hello', (req, res) => res.send(`Hello World. path: ${this.openApiPath}`));
@@ -53,6 +58,21 @@ class ExpressServer {
5358
fileUploader: { dest: config.FILE_UPLOAD_PATH },
5459
}),
5560
);
61+
this.app.use((err, req, res, next) => {
62+
// Log full error
63+
console.error('OpenAPI validation error:', err);
64+
65+
// Handle OpenAPI validation errors
66+
if (err.status && err.errors) {
67+
res.status(err.status).json({
68+
message: err.message,
69+
errors: err.errors,
70+
});
71+
} else {
72+
// Fallback error handler
73+
next(err);
74+
}
75+
});
5676
}
5777

5878
launch() {

0 commit comments

Comments
 (0)