Skip to content

Commit b11469a

Browse files
authored
CCM-12223: count routing configs endpoint (#712)
1 parent d7a5885 commit b11469a

File tree

19 files changed

+1273
-436
lines changed

19 files changed

+1273
-436
lines changed

infrastructure/terraform/modules/backend-api/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ No requirements.
3838
| Name | Source | Version |
3939
|------|--------|---------|
4040
| <a name="module_authorizer_lambda"></a> [authorizer\_lambda](#module\_authorizer\_lambda) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.22/terraform-lambda.zip | n/a |
41+
| <a name="module_count_routing_configs_lambda"></a> [count\_routing\_configs\_lambda](#module\_count\_routing\_configs\_lambda) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.22/terraform-lambda.zip | n/a |
4142
| <a name="module_create_template_lambda"></a> [create\_template\_lambda](#module\_create\_template\_lambda) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.22/terraform-lambda.zip | n/a |
4243
| <a name="module_delete_template_lambda"></a> [delete\_template\_lambda](#module\_delete\_template\_lambda) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.22/terraform-lambda.zip | n/a |
4344
| <a name="module_get_client_lambda"></a> [get\_client\_lambda](#module\_get\_client\_lambda) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.22/terraform-lambda.zip | n/a |

infrastructure/terraform/modules/backend-api/iam_role_api_gateway_execution_role.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ data "aws_iam_policy_document" "api_gateway_execution_policy" {
5050
resources = [
5151
module.authorizer_lambda.function_arn,
5252
module.upload_letter_template_lambda.function_arn,
53+
module.count_routing_configs_lambda.function_arn,
5354
module.create_template_lambda.function_arn,
5455
module.delete_template_lambda.function_arn,
5556
module.get_client_lambda.function_arn,

infrastructure/terraform/modules/backend-api/locals.tf

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,21 @@ locals {
1111
client_ssm_path_pattern = "arn:aws:ssm:${var.region}:${var.aws_account_id}:parameter${local.client_ssm_path_prefix}/*"
1212

1313
openapi_spec = templatefile("${path.module}/spec.tmpl.json", {
14-
APIG_EXECUTION_ROLE_ARN = aws_iam_role.api_gateway_execution_role.arn
15-
AUTHORIZER_LAMBDA_ARN = module.authorizer_lambda.function_arn
16-
AWS_REGION = var.region
17-
CREATE_LAMBDA_ARN = module.create_template_lambda.function_arn
18-
DELETE_LAMBDA_ARN = module.delete_template_lambda.function_arn
19-
GET_CLIENT_LAMBDA_ARN = module.get_client_lambda.function_arn
20-
GET_LAMBDA_ARN = module.get_template_lambda.function_arn
21-
GET_ROUTING_CONFIG_LAMBDA_ARN = module.get_routing_config_lambda.function_arn
22-
LIST_LAMBDA_ARN = module.list_template_lambda.function_arn
23-
LIST_ROUTING_CONFIGS_LAMBDA_ARN = module.list_routing_configs_lambda.function_arn
24-
REQUEST_PROOF_LAMBDA_ARN = module.request_proof_lambda.function_arn
25-
SUBMIT_LAMBDA_ARN = module.submit_template_lambda.function_arn
26-
UPDATE_LAMBDA_ARN = module.update_template_lambda.function_arn
27-
UPLOAD_LETTER_LAMBDA_ARN = module.upload_letter_template_lambda.function_arn
14+
APIG_EXECUTION_ROLE_ARN = aws_iam_role.api_gateway_execution_role.arn
15+
AUTHORIZER_LAMBDA_ARN = module.authorizer_lambda.function_arn
16+
AWS_REGION = var.region
17+
COUNT_ROUTING_CONFIGS_LAMBDA_ARN = module.count_routing_configs_lambda.function_arn
18+
CREATE_LAMBDA_ARN = module.create_template_lambda.function_arn
19+
DELETE_LAMBDA_ARN = module.delete_template_lambda.function_arn
20+
GET_CLIENT_LAMBDA_ARN = module.get_client_lambda.function_arn
21+
GET_LAMBDA_ARN = module.get_template_lambda.function_arn
22+
GET_ROUTING_CONFIG_LAMBDA_ARN = module.get_routing_config_lambda.function_arn
23+
LIST_LAMBDA_ARN = module.list_template_lambda.function_arn
24+
LIST_ROUTING_CONFIGS_LAMBDA_ARN = module.list_routing_configs_lambda.function_arn
25+
REQUEST_PROOF_LAMBDA_ARN = module.request_proof_lambda.function_arn
26+
SUBMIT_LAMBDA_ARN = module.submit_template_lambda.function_arn
27+
UPDATE_LAMBDA_ARN = module.update_template_lambda.function_arn
28+
UPLOAD_LETTER_LAMBDA_ARN = module.upload_letter_template_lambda.function_arn
2829
})
2930

3031
backend_lambda_environment_variables = {
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
module "count_routing_configs_lambda" {
2+
source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.22/terraform-lambda.zip"
3+
4+
project = var.project
5+
environment = var.environment
6+
component = var.component
7+
aws_account_id = var.aws_account_id
8+
region = var.region
9+
10+
kms_key_arn = var.kms_key_arn
11+
12+
function_name = "count-routing-configs"
13+
14+
function_module_name = "count-routing-configs"
15+
handler_function_name = "handler"
16+
description = "Count Routing Configs API endpoint"
17+
18+
memory = 512
19+
timeout = 3
20+
runtime = "nodejs20.x"
21+
22+
log_retention_in_days = var.log_retention_in_days
23+
24+
iam_policy_document = {
25+
body = data.aws_iam_policy_document.count_routing_configs_lambda_policy.json
26+
}
27+
28+
lambda_env_vars = local.backend_lambda_environment_variables
29+
function_s3_bucket = var.function_s3_bucket
30+
function_code_base_path = local.lambdas_dir
31+
function_code_dir = "backend-api/dist/count-routing-configs"
32+
33+
send_to_firehose = var.send_to_firehose
34+
log_destination_arn = var.log_destination_arn
35+
log_subscription_role_arn = var.log_subscription_role_arn
36+
}
37+
38+
data "aws_iam_policy_document" "count_routing_configs_lambda_policy" {
39+
statement {
40+
sid = "AllowDynamoAccess"
41+
effect = "Allow"
42+
43+
actions = [
44+
"dynamodb:Query",
45+
]
46+
47+
resources = [
48+
aws_dynamodb_table.routing_configuration.arn,
49+
]
50+
}
51+
52+
statement {
53+
sid = "AllowKMSAccess"
54+
effect = "Allow"
55+
56+
actions = [
57+
"kms:Decrypt",
58+
"kms:DescribeKey",
59+
"kms:Encrypt",
60+
"kms:GenerateDataKey*",
61+
"kms:ReEncrypt*",
62+
]
63+
64+
resources = [
65+
var.kms_key_arn
66+
]
67+
}
68+
}

infrastructure/terraform/modules/backend-api/spec.tmpl.json

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,29 @@
376376
],
377377
"type": "object"
378378
},
379+
"CountSuccess": {
380+
"properties": {
381+
"data": {
382+
"properties": {
383+
"count": {
384+
"type": "integer"
385+
}
386+
},
387+
"required": [
388+
"count"
389+
],
390+
"type": "object"
391+
},
392+
"statusCode": {
393+
"type": "integer"
394+
}
395+
},
396+
"required": [
397+
"data",
398+
"statusCode"
399+
],
400+
"type": "object"
401+
},
379402
"CreateUpdateTemplate": {
380403
"allOf": [
381404
{
@@ -1117,6 +1140,70 @@
11171140
}
11181141
}
11191142
},
1143+
"/v1/routing-configurations/count": {
1144+
"get": {
1145+
"description": "Get a count of routing configs",
1146+
"parameters": [
1147+
{
1148+
"description": "Filter by a single active status",
1149+
"in": "query",
1150+
"name": "status",
1151+
"schema": {
1152+
"$ref": "#/components/schemas/RoutingConfigStatusActive"
1153+
}
1154+
}
1155+
],
1156+
"responses": {
1157+
"200": {
1158+
"content": {
1159+
"application/json": {
1160+
"schema": {
1161+
"$ref": "#/components/schemas/CountSuccess"
1162+
}
1163+
}
1164+
},
1165+
"description": "200 response",
1166+
"headers": {
1167+
"Content-Type": {
1168+
"schema": {
1169+
"type": "string"
1170+
}
1171+
}
1172+
}
1173+
},
1174+
"default": {
1175+
"content": {
1176+
"application/json": {
1177+
"schema": {
1178+
"$ref": "#/components/schemas/Failure"
1179+
}
1180+
}
1181+
},
1182+
"description": "Error"
1183+
}
1184+
},
1185+
"security": [
1186+
{
1187+
"authorizer": []
1188+
}
1189+
],
1190+
"summary": "Count routing configs",
1191+
"x-amazon-apigateway-integration": {
1192+
"contentHandling": "CONVERT_TO_TEXT",
1193+
"credentials": "${APIG_EXECUTION_ROLE_ARN}",
1194+
"httpMethod": "POST",
1195+
"passthroughBehavior": "WHEN_NO_TEMPLATES",
1196+
"responses": {
1197+
".*": {
1198+
"statusCode": "200"
1199+
}
1200+
},
1201+
"timeoutInMillis": 29000,
1202+
"type": "AWS_PROXY",
1203+
"uri": "arn:aws:apigateway:${AWS_REGION}:lambda:path/2015-03-31/functions/${COUNT_ROUTING_CONFIGS_LAMBDA_ARN}/invocations"
1204+
}
1205+
}
1206+
},
11201207
"/v1/template": {
11211208
"post": {
11221209
"description": "Create a template",

lambdas/backend-api/build.sh

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ npx esbuild \
1515
--outdir=dist \
1616
--external:pdfjs-dist \
1717
src/templates/copy-scanned-object-to-internal.ts \
18-
src/templates/upload-letter.ts \
18+
src/templates/count-routing-configs.ts \
1919
src/templates/create.ts \
20-
src/templates/delete-failed-scanned-object.ts \
2120
src/templates/delete.ts \
22-
src/templates/get-client.ts \
21+
src/templates/delete-failed-scanned-object.ts \
2322
src/templates/get.ts \
23+
src/templates/get-client.ts \
2424
src/templates/get-routing-config.ts \
2525
src/templates/list.ts \
2626
src/templates/list-routing-configs.ts \
@@ -29,6 +29,7 @@ npx esbuild \
2929
src/templates/set-letter-upload-virus-scan-status.ts \
3030
src/templates/submit.ts \
3131
src/templates/update.ts \
32+
src/templates/upload-letter.ts \
3233
src/templates/validate-letter-template-files.ts
3334

3435
cp -r ../../utils/utils/src/email-templates ./dist/submit
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import type { APIGatewayProxyEvent, Context } from 'aws-lambda';
2+
import { mock } from 'jest-mock-extended';
3+
import type { Logger } from 'nhs-notify-web-template-management-utils/logger';
4+
import { createHandler } from '@backend-api/templates/api/count-routing-configs';
5+
import { RoutingConfigClient } from '@backend-api/templates/app/routing-config-client';
6+
7+
jest.mock('nhs-notify-web-template-management-utils/logger', () => ({
8+
logger: mock<Logger>({
9+
child: jest.fn().mockReturnThis(),
10+
}),
11+
}));
12+
13+
const setup = () => {
14+
const routingConfigClient = mock<RoutingConfigClient>();
15+
16+
const handler = createHandler({ routingConfigClient });
17+
18+
return { handler, mocks: { routingConfigClient } };
19+
};
20+
21+
describe('CountRoutingConfigs handler', () => {
22+
test.each([
23+
['undefined', undefined],
24+
['missing user', { clientId: 'client-id', user: undefined }],
25+
['missing client', { clientId: undefined, user: 'user-id' }],
26+
])(
27+
'should return 400 - Invalid request when requestContext is %s',
28+
async (_, ctx) => {
29+
const { handler, mocks } = setup();
30+
31+
const event = mock<APIGatewayProxyEvent>({
32+
requestContext: { authorizer: ctx },
33+
});
34+
35+
const result = await handler(event, mock<Context>(), jest.fn());
36+
37+
expect(result).toEqual({
38+
statusCode: 400,
39+
body: JSON.stringify({
40+
statusCode: 400,
41+
technicalMessage: 'Invalid request',
42+
}),
43+
});
44+
45+
expect(
46+
mocks.routingConfigClient.countRoutingConfigs
47+
).not.toHaveBeenCalled();
48+
}
49+
);
50+
51+
test('should return error when counting routing configs fails', async () => {
52+
const { handler, mocks } = setup();
53+
54+
mocks.routingConfigClient.countRoutingConfigs.mockResolvedValueOnce({
55+
error: {
56+
errorMeta: {
57+
code: 500,
58+
description: 'Internal server error',
59+
},
60+
},
61+
});
62+
63+
const event = mock<APIGatewayProxyEvent>();
64+
event.requestContext.authorizer = {
65+
user: 'sub',
66+
clientId: 'nhs-notify-client-id',
67+
};
68+
69+
event.queryStringParameters = {
70+
status: 'DRAFT',
71+
};
72+
73+
const result = await handler(event, mock<Context>(), jest.fn());
74+
75+
expect(result).toEqual({
76+
statusCode: 500,
77+
body: JSON.stringify({
78+
statusCode: 500,
79+
technicalMessage: 'Internal server error',
80+
}),
81+
});
82+
83+
expect(mocks.routingConfigClient.countRoutingConfigs).toHaveBeenCalledWith(
84+
'nhs-notify-client-id',
85+
{ status: 'DRAFT' }
86+
);
87+
});
88+
89+
test('should return count of routing configs', async () => {
90+
const { handler, mocks } = setup();
91+
92+
mocks.routingConfigClient.countRoutingConfigs.mockResolvedValueOnce({
93+
data: { count: 99 },
94+
});
95+
96+
const event = mock<APIGatewayProxyEvent>();
97+
event.requestContext.authorizer = {
98+
user: 'sub',
99+
clientId: 'nhs-notify-client-id',
100+
};
101+
event.queryStringParameters = {
102+
status: 'COMPLETED',
103+
};
104+
105+
const result = await handler(event, mock<Context>(), jest.fn());
106+
107+
expect(result).toEqual({
108+
statusCode: 200,
109+
body: JSON.stringify({ statusCode: 200, data: { count: 99 } }),
110+
});
111+
112+
expect(mocks.routingConfigClient.countRoutingConfigs).toHaveBeenCalledWith(
113+
'nhs-notify-client-id',
114+
{ status: 'COMPLETED' }
115+
);
116+
});
117+
});

0 commit comments

Comments
 (0)