Skip to content

Commit b0c69f2

Browse files
Add post letters endpoint (#231)
* Add post letters endpoint * Fix names * Fix event mapper * Fix sqs * Fix arn * Fix sqs name * Fix param * Fix attempt * Fix attempt sqs * Fix attempt await * Clean up tests * Naming and minor refactor * Add duplicate validation * Change handler name * Fix unit tests
1 parent 4302a12 commit b0c69f2

40 files changed

+1835
-254
lines changed

infrastructure/terraform/components/api/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,11 @@ No requirements.
3838
| <a name="module_get_letter_data"></a> [get\_letter\_data](#module\_get\_letter\_data) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip | n/a |
3939
| <a name="module_get_letters"></a> [get\_letters](#module\_get\_letters) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip | n/a |
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 |
41+
| <a name="module_letter_status_update"></a> [letter\_status\_update](#module\_letter\_status\_update) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip | n/a |
42+
| <a name="module_letter_status_updates_queue"></a> [letter\_status\_updates\_queue](#module\_letter\_status\_updates\_queue) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-sqs.zip | n/a |
4143
| <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 |
4244
| <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 |
45+
| <a name="module_post_letters"></a> [post\_letters](#module\_post\_letters) | 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 |
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
resource "aws_lambda_event_source_mapping" "status_updates_sqs_to_status_update_handler" {
2+
event_source_arn = module.letter_status_updates_queue.sqs_queue_arn
3+
function_name = module.letter_status_update.function_arn
4+
batch_size = 10
5+
maximum_batching_window_in_seconds = 1
6+
scaling_config { maximum_concurrency = 10 }
7+
8+
depends_on = [
9+
module.letter_status_updates_queue, # ensures queue exists
10+
module.letter_status_update # ensures update handler exists
11+
]
12+
}

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: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ locals {
55
root_domain_nameservers = local.acct.route53_zone_nameservers["supplier-api"]
66

77
openapi_spec = templatefile("${path.module}/resources/spec.tmpl.json", {
8-
APIG_EXECUTION_ROLE_ARN = aws_iam_role.api_gateway_execution_role.arn
9-
AWS_REGION = var.region
10-
AUTHORIZER_LAMBDA_ARN = module.authorizer_lambda.function_arn
11-
GET_LETTER_LAMBDA_ARN = module.get_letter.function_arn
12-
GET_LETTERS_LAMBDA_ARN = module.get_letters.function_arn
13-
GET_LETTER_DATA_LAMBDA_ARN = module.get_letter_data.function_arn
14-
PATCH_LETTER_LAMBDA_ARN = module.patch_letter.function_arn
15-
POST_MI_LAMBDA_ARN = module.post_mi.function_arn
8+
APIG_EXECUTION_ROLE_ARN = aws_iam_role.api_gateway_execution_role.arn
9+
AWS_REGION = var.region
10+
AUTHORIZER_LAMBDA_ARN = module.authorizer_lambda.function_arn
11+
GET_LETTER_LAMBDA_ARN = module.get_letter.function_arn
12+
GET_LETTERS_LAMBDA_ARN = module.get_letters.function_arn
13+
GET_LETTER_DATA_LAMBDA_ARN = module.get_letter_data.function_arn
14+
PATCH_LETTER_LAMBDA_ARN = module.patch_letter.function_arn
15+
POST_LETTERS_LAMBDA_ARN = module.post_letters.function_arn
16+
POST_MI_LAMBDA_ARN = module.post_mi.function_arn
1617
})
1718

1819
destination_arn = "arn:aws:logs:${var.region}:${var.shared_infra_account_id}:destination:nhs-main-obs-firehose-logs"
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
module "letter_status_update" {
2+
source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip"
3+
4+
function_name = "letter_status_update"
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.letter_status_update.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 = "letterStatusUpdate"
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" "letter_status_update" {
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:GetItem",
62+
"dynamodb:Query",
63+
"dynamodb:UpdateItem",
64+
]
65+
66+
resources = [
67+
aws_dynamodb_table.letters.arn,
68+
]
69+
}
70+
71+
statement {
72+
sid = "AllowQueueAccess"
73+
effect = "Allow"
74+
75+
actions = [
76+
"sqs:ReceiveMessage",
77+
"sqs:DeleteMessage",
78+
"sqs:GetQueueAttributes",
79+
"sqs:ChangeMessageVisibility"
80+
]
81+
82+
resources = [
83+
module.letter_status_updates_queue.sqs_queue_arn
84+
]
85+
}
86+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
module "post_letters" {
2+
source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip"
3+
4+
function_name = "post_letters"
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.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.letter_status_updates_queue.sqs_queue_url,
40+
MAX_LIMIT = var.max_get_limit
41+
})
42+
}
43+
44+
data "aws_iam_policy_document" "post_letters" {
45+
statement {
46+
sid = "KMSPermissions"
47+
effect = "Allow"
48+
49+
actions = [
50+
"kms:Decrypt",
51+
"kms:GenerateDataKey",
52+
]
53+
54+
resources = [
55+
module.kms.key_arn, ## Requires shared kms module
56+
]
57+
}
58+
59+
statement {
60+
sid = "AllowQueueAccess"
61+
effect = "Allow"
62+
63+
actions = [
64+
"sqs:SendMessage",
65+
"sqs:GetQueueAttributes",
66+
]
67+
68+
resources = [
69+
module.letter_status_updates_queue.sqs_queue_arn
70+
]
71+
}
72+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Queue to transport update letter status messages
2+
module "letter_status_updates_queue" {
3+
source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-sqs.zip"
4+
5+
name = "letter_status_updates_queue"
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+
13+
sqs_kms_key_arn = module.kms.key_arn
14+
15+
create_dlq = true
16+
}

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}": {

internal/datastore/src/types.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,16 @@ erDiagram
3131
erDiagram
3232
MI {
3333
string id
34-
string supplierId
35-
string specificationId
36-
string groupId
3734
string lineItem
35+
string timestamp
3836
number quantity
37+
string specificationId
38+
string groupId
3939
number stockRemaining
40+
string supplierId
4041
string createdAt
4142
string updatedAt
43+
number ttl "min: -9007199254740991, max: 9007199254740991"
4244
}
4345
```
4446

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",

0 commit comments

Comments
 (0)