Skip to content

Commit 2ae8486

Browse files
Add post letters endpoint
1 parent ec75f5e commit 2ae8486

36 files changed

+1738
-234
lines changed

infrastructure/terraform/components/api/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ No requirements.
4040
| <a name="module_kms"></a> [kms](#module\_kms) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.20/terraform-kms.zip | n/a |
4141
| <a name="module_logging_bucket"></a> [logging\_bucket](#module\_logging\_bucket) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.20/terraform-s3bucket.zip | n/a |
4242
| <a name="module_patch_letter"></a> [patch\_letter](#module\_patch\_letter) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip | n/a |
43+
| <a name="module_post_letters_processor"></a> [post\_letters\_processor](#module\_post\_letters\_processor) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip | n/a |
44+
| <a name="module_post_letters_queue"></a> [post\_letters\_queue](#module\_post\_letters\_queue) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-sqs.zip | n/a |
45+
| <a name="module_post_letters_receiver"></a> [post\_letters\_receiver](#module\_post\_letters\_receiver) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip | n/a |
4346
| <a name="module_post_mi"></a> [post\_mi](#module\_post\_mi) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip | n/a |
4447
| <a name="module_s3bucket_test_letters"></a> [s3bucket\_test\_letters](#module\_s3bucket\_test\_letters) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.20/terraform-s3bucket.zip | n/a |
4548
| <a name="module_supplier_ssl"></a> [supplier\_ssl](#module\_supplier\_ssl) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.20/terraform-ssl.zip | n/a |

infrastructure/terraform/components/api/iam_role_api_gateway_execution_role.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ data "aws_iam_policy_document" "api_gateway_execution_policy" {
5353
module.get_letter_data.function_arn,
5454
module.get_letters.function_arn,
5555
module.patch_letter.function_arn,
56+
module.post_letters.function_arn,
5657
module.post_mi.function_arn
5758
]
5859
}

infrastructure/terraform/components/api/locals.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ locals {
1212
GET_LETTERS_LAMBDA_ARN = module.get_letters.function_arn
1313
GET_LETTER_DATA_LAMBDA_ARN = module.get_letter_data.function_arn
1414
PATCH_LETTER_LAMBDA_ARN = module.patch_letter.function_arn
15+
POST_LETTERS_LAMBDA_ARN = module.post_letters.function_arn
1516
POST_MI_LAMBDA_ARN = module.post_mi.function_arn
1617
})
1718

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
module "post_letters_processor" {
2+
source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip"
3+
4+
function_name = "post_letters_processor"
5+
description = "Processes letter status updates"
6+
7+
aws_account_id = var.aws_account_id
8+
component = var.component
9+
environment = var.environment
10+
project = var.project
11+
region = var.region
12+
group = var.group
13+
14+
log_retention_in_days = var.log_retention_in_days
15+
kms_key_arn = module.kms.key_arn
16+
17+
iam_policy_document = {
18+
body = data.aws_iam_policy_document.post_letters_processor.json
19+
}
20+
21+
function_s3_bucket = local.acct.s3_buckets["lambda_function_artefacts"]["id"]
22+
function_code_base_path = local.aws_lambda_functions_dir_path
23+
function_code_dir = "api-handler/dist"
24+
function_include_common = true
25+
handler_function_name = "postLetters"
26+
runtime = "nodejs22.x"
27+
memory = 128
28+
timeout = 5
29+
log_level = var.log_level
30+
31+
force_lambda_code_deploy = var.force_lambda_code_deploy
32+
enable_lambda_insights = false
33+
34+
send_to_firehose = true
35+
log_destination_arn = local.destination_arn
36+
log_subscription_role_arn = local.acct.log_subscription_role_arn
37+
38+
lambda_env_vars = merge(local.common_lambda_env_vars, {})
39+
}
40+
41+
data "aws_iam_policy_document" "post_letters_processor" {
42+
statement {
43+
sid = "KMSPermissions"
44+
effect = "Allow"
45+
46+
actions = [
47+
"kms:Decrypt",
48+
"kms:GenerateDataKey",
49+
]
50+
51+
resources = [
52+
module.kms.key_arn, ## Requires shared kms module
53+
]
54+
}
55+
56+
statement {
57+
sid = "AllowDynamoDBAccess"
58+
effect = "Allow"
59+
60+
actions = [
61+
"dynamodb:UpdateItem",
62+
]
63+
64+
resources = [
65+
aws_dynamodb_table.letters.arn,
66+
]
67+
}
68+
69+
statement {
70+
sid = "AllowQueueAccess"
71+
effect = "Allow"
72+
73+
actions = [
74+
"sqs:ReceiveMessage",
75+
"sqs:DeleteMessage",
76+
"sqs:GetQueueAttributes",
77+
"sqs:ChangeMessageVisibility"
78+
]
79+
80+
resources = [
81+
module.post_letters_queue.sqs_queue_arn
82+
]
83+
}
84+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
module "post_letters_receiver" {
2+
source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip"
3+
4+
function_name = "post_letters_receiver"
5+
description = "Receives and accepts collection of letters to update"
6+
7+
aws_account_id = var.aws_account_id
8+
component = var.component
9+
environment = var.environment
10+
project = var.project
11+
region = var.region
12+
group = var.group
13+
14+
log_retention_in_days = var.log_retention_in_days
15+
kms_key_arn = module.kms.key_arn
16+
17+
iam_policy_document = {
18+
body = data.aws_iam_policy_document.post_letters_receiver.json
19+
}
20+
21+
function_s3_bucket = local.acct.s3_buckets["lambda_function_artefacts"]["id"]
22+
function_code_base_path = local.aws_lambda_functions_dir_path
23+
function_code_dir = "api-handler/dist"
24+
function_include_common = true
25+
handler_function_name = "postLetters"
26+
runtime = "nodejs22.x"
27+
memory = 128
28+
timeout = 5
29+
log_level = var.log_level
30+
31+
force_lambda_code_deploy = var.force_lambda_code_deploy
32+
enable_lambda_insights = false
33+
34+
send_to_firehose = true
35+
log_destination_arn = local.destination_arn
36+
log_subscription_role_arn = local.acct.log_subscription_role_arn
37+
38+
lambda_env_vars = merge(local.common_lambda_env_vars, {
39+
QUEUE_URL = module.post_letters_queue.sqs_queue_url
40+
})
41+
}
42+
43+
data "aws_iam_policy_document" "post_letters_receiver" {
44+
statement {
45+
sid = "KMSPermissions"
46+
effect = "Allow"
47+
48+
actions = [
49+
"kms:Decrypt",
50+
"kms:GenerateDataKey",
51+
]
52+
53+
resources = [
54+
module.kms.key_arn, ## Requires shared kms module
55+
]
56+
}
57+
58+
statement {
59+
sid = "AllowQueueAccess"
60+
effect = "Allow"
61+
62+
actions = [
63+
"sqs:SendMessage",
64+
"sqs:GetQueueAttributes",
65+
]
66+
67+
resources = [
68+
module.post_letters_queue.sqs_queue_arn
69+
]
70+
}
71+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
module "post_letters_queue" {
2+
source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-sqs.zip"
3+
4+
name = "post_letters_queue"
5+
description = "Queues a collection of letters to update"
6+
7+
aws_account_id = var.aws_account_id
8+
component = var.component
9+
environment = var.environment
10+
project = var.project
11+
region = var.region
12+
group = var.group
13+
14+
sqs_kms_key_arn = module.kms.key_arn
15+
16+
iam_policy_document = {
17+
body = data.aws_iam_policy_document.post_letters_queue.json
18+
}
19+
}
20+
21+
data "aws_iam_policy_document" "post_letters_queue" {
22+
23+
statement {
24+
sid = "KMSPermissions"
25+
effect = "Allow"
26+
27+
actions = [
28+
"kms:Decrypt",
29+
"kms:GenerateDataKey",
30+
]
31+
32+
resources = [
33+
module.kms.key_arn, ## Requires shared kms module
34+
]
35+
}
36+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
resource "aws_lambda_event_source_mapping" "sqs_to_processor" {
2+
event_source_arn = module.post_letters_queue.sqs_queue_arn
3+
function_name = module.post_letters_processor.arn
4+
batch_size = 10
5+
maximum_batching_window_in_seconds = 1
6+
scaling_config { maximum_concurrency = 10 }
7+
}
8+
9+
depends_on = [
10+
module.post_letters_queue, # ensures queue exists
11+
module.post_letters_processor # ensures processor exists
12+
# aws_iam_role_policy.post_letters_processor, # ensures permissions exist
13+
# aws_iam_role_policy.post_letters_receiver, # ensures permissions exist
14+
]

infrastructure/terraform/components/api/resources/spec.tmpl.json

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,43 @@
5151
"type": "AWS_PROXY",
5252
"uri": "arn:aws:apigateway:${AWS_REGION}:lambda:path/2015-03-31/functions/${GET_LETTERS_LAMBDA_ARN}/invocations"
5353
}
54+
},
55+
"post": {
56+
"description": "Update the status of a collection of letters.",
57+
"operationId": "postLetters",
58+
"requestBody": {
59+
"required": true
60+
},
61+
"responses": {
62+
"202": {
63+
"description": "Acknowledges letters will be updated"
64+
},
65+
"400": {
66+
"description": "Bad request, invalid input data"
67+
},
68+
"500": {
69+
"description": "Server error"
70+
}
71+
},
72+
"security": [
73+
{
74+
"LambdaAuthorizer": []
75+
}
76+
],
77+
"x-amazon-apigateway-integration": {
78+
"contentHandling": "CONVERT_TO_TEXT",
79+
"credentials": "${APIG_EXECUTION_ROLE_ARN}",
80+
"httpMethod": "POST",
81+
"passthroughBehavior": "WHEN_NO_TEMPLATES",
82+
"responses": {
83+
".*": {
84+
"statusCode": "200"
85+
}
86+
},
87+
"timeoutInMillis": 29000,
88+
"type": "AWS_PROXY",
89+
"uri": "arn:aws:apigateway:${AWS_REGION}:lambda:path/2015-03-31/functions/${POST_LETTERS_LAMBDA_ARN}/invocations"
90+
}
5491
}
5592
},
5693
"/letters/{id}": {

lambdas/api-handler/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"dependencies": {
3+
"@aws-sdk/client-sqs": "^3.925.0",
34
"@internal/datastore": "*",
45
"@internal/helpers": "*",
56
"esbuild": "^0.25.11",

lambdas/api-handler/src/config/__tests__/deps.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ describe('createDependenciesContainer', () => {
3232
S3Client: jest.fn(),
3333
}));
3434

35+
jest.mock('@aws-sdk/client-sqs', () => ({
36+
SQSClient: jest.fn(),
37+
}));
38+
3539
// Repo client
3640
jest.mock('@internal/datastore', () => ({
3741
LetterRepository: jest.fn(),
@@ -45,6 +49,7 @@ describe('createDependenciesContainer', () => {
4549
test('constructs deps and wires repository config correctly', async () => {
4650
// get current mock instances
4751
const { S3Client } = jest.requireMock('@aws-sdk/client-s3') as { S3Client: jest.Mock };
52+
const { SQSClient } = jest.requireMock('@aws-sdk/client-sqs') as { SQSClient: jest.Mock };
4853
const pinoMock = jest.requireMock('pino') as { default: jest.Mock };
4954
const { LetterRepository, MIRepository } = jest.requireMock('@internal/datastore') as {
5055
LetterRepository: jest.Mock,
@@ -55,6 +60,9 @@ describe('createDependenciesContainer', () => {
5560
const deps: Deps = createDependenciesContainer();
5661

5762
expect(S3Client).toHaveBeenCalledTimes(1);
63+
64+
expect(SQSClient).toHaveBeenCalledTimes(1);
65+
5866
expect(pinoMock.default).toHaveBeenCalledTimes(1);
5967

6068
expect(LetterRepository).toHaveBeenCalledTimes(1);

0 commit comments

Comments
 (0)