Skip to content

Commit 6eb1174

Browse files
committed
feat(etl-ods): FTRS-3165 Initial change to convert CRUD API to REST
1 parent 046e204 commit 6eb1174

15 files changed

+492
-37
lines changed

docs/specification/dos-ingest.yaml

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,68 @@ paths:
429429
display: Resource does not exist
430430
text: The requested organisation was not found
431431
diagnostics: "Organisation with ODS code 'DEF456' not found"
432+
'401':
433+
description: Unauthorized - Invalid or missing authentication token
434+
headers:
435+
X-Correlation-ID:
436+
schema:
437+
type: string
438+
example: 11C46F5F-CDEF-4865-94B2-0EE0EDCC26DA
439+
description: The X-Correlation-ID from the request header, if supplied, mirrored
440+
back.
441+
X-Request-ID:
442+
schema:
443+
type: string
444+
example: 11c46f5f-cdef-4865-94b2-0ee0edcc26da
445+
description: The X-Request-ID from the request header, either generated or supplied, mirrored
446+
back.
447+
content:
448+
application/fhir+json:
449+
schema:
450+
$ref: '#/components/schemas/OperationOutcome'
451+
example:
452+
resourceType: "OperationOutcome"
453+
issue:
454+
- severity: "error"
455+
code: "security"
456+
details:
457+
coding:
458+
- system: "https://fhir.nhs.uk/R4/CodeSystem/Spine-ErrorOrWarningCode"
459+
version: "1"
460+
code: "UNAUTHORIZED"
461+
display: "Unauthorized"
462+
diagnostics: "Invalid or missing authentication token"
463+
'403':
464+
description: Forbidden - Insufficient permissions
465+
headers:
466+
X-Correlation-ID:
467+
schema:
468+
type: string
469+
example: 11C46F5F-CDEF-4865-94B2-0EE0EDCC26DA
470+
description: The X-Correlation-ID from the request header, if supplied, mirrored
471+
back.
472+
X-Request-ID:
473+
schema:
474+
type: string
475+
example: 11c46f5f-cdef-4865-94b2-0ee0edcc26da
476+
description: The X-Request-ID from the request header, either generated or supplied, mirrored
477+
back.
478+
content:
479+
application/fhir+json:
480+
schema:
481+
$ref: '#/components/schemas/OperationOutcome'
482+
example:
483+
resourceType: "OperationOutcome"
484+
issue:
485+
- severity: "error"
486+
code: "forbidden"
487+
details:
488+
coding:
489+
- system: "https://fhir.nhs.uk/R4/CodeSystem/Spine-ErrorOrWarningCode"
490+
version: "1"
491+
code: "FORBIDDEN"
492+
display: "Forbidden"
493+
diagnostics: "Insufficient permissions to access this resource"
432494
'422':
433495
description: Unprocessable Entity (e.g., ODS code validation failed)
434496
headers:
@@ -460,6 +522,37 @@ paths:
460522
display: Parameter content is invalid
461523
text: Validation failed for resource
462524
diagnostics: "Validation failed for resource."
525+
'429':
526+
description: Too many requests - Rate limit exceeded
527+
headers:
528+
X-Correlation-ID:
529+
schema:
530+
type: string
531+
example: 11C46F5F-CDEF-4865-94B2-0EE0EDCC26DA
532+
description: The X-Correlation-ID from the request header, if supplied, mirrored
533+
back.
534+
X-Request-ID:
535+
schema:
536+
type: string
537+
example: 11c46f5f-cdef-4865-94b2-0ee0edcc26da
538+
description: The X-Request-ID from the request header, either generated or supplied, mirrored
539+
back.
540+
content:
541+
application/fhir+json:
542+
schema:
543+
$ref: '#/components/schemas/OperationOutcome'
544+
example:
545+
resourceType: "OperationOutcome"
546+
issue:
547+
- severity: "error"
548+
code: "throttled"
549+
details:
550+
coding:
551+
- system: "https://fhir.hl7.org.uk/CodeSystem/UKCore-SpineErrorOrWarningCode"
552+
version: "1.0.0"
553+
code: "SEND_TOO_MANY_REQUESTS"
554+
display: "Send too many requests"
555+
diagnostics: "Rate limit exceeded. Please retry after some time."
463556
'500':
464557
description: Internal server error
465558
headers:

infrastructure/crud_apis.tfvars

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,6 @@ crud_apis_store_bucket_name = "crud-api-store"
2222
s3_versioning = false
2323

2424
# API Gateway
25-
api_gateway_authorization_type = "AWS_IAM"
26-
api_gateway_payload_format_version = "2.0"
27-
api_gateway_integration_timeout = 10000
2825
api_gateway_access_logs_retention_days = 7
2926
api_gateway_throttling_burst_limit = 100
3027
api_gateway_throttling_rate_limit = 10

infrastructure/modules/ods-mock-api/main.tf

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ resource "aws_api_gateway_method" "organization_get" {
4646
http_method = "GET"
4747
authorization = "NONE"
4848
api_key_required = true
49-
request_validator_id = aws_api_gateway_request_validator.validator.id
5049

5150
request_parameters = {
5251
"method.request.querystring._lastUpdated" = false
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
resource "aws_api_gateway_deployment" "deployment" {
2+
depends_on = [
3+
aws_api_gateway_integration.organization_get,
4+
aws_api_gateway_integration.organization_post,
5+
aws_api_gateway_integration.organization_proxy,
6+
aws_api_gateway_integration.status,
7+
aws_api_gateway_integration.healthcare_service_proxy,
8+
aws_api_gateway_integration.location_proxy,
9+
aws_api_gateway_gateway_response.default_gateway_response,
10+
]
11+
12+
rest_api_id = aws_api_gateway_rest_api.api_gateway.id
13+
14+
triggers = {
15+
redeployment = sha1(jsonencode([
16+
aws_api_gateway_resource.organization,
17+
aws_api_gateway_resource.organization_proxy,
18+
aws_api_gateway_resource.status,
19+
aws_api_gateway_resource.healthcare_service,
20+
aws_api_gateway_resource.healthcare_service_proxy,
21+
aws_api_gateway_resource.location,
22+
aws_api_gateway_resource.location_proxy,
23+
aws_api_gateway_method.organization_get,
24+
aws_api_gateway_method.organization_post,
25+
aws_api_gateway_method.organization_proxy,
26+
aws_api_gateway_method.status,
27+
aws_api_gateway_method.healthcare_service_proxy,
28+
aws_api_gateway_method.location_proxy,
29+
aws_api_gateway_integration.organization_get,
30+
aws_api_gateway_integration.organization_post,
31+
aws_api_gateway_integration.organization_proxy,
32+
aws_api_gateway_integration.status,
33+
aws_api_gateway_integration.healthcare_service_proxy,
34+
aws_api_gateway_integration.location_proxy,
35+
aws_api_gateway_gateway_response.default_gateway_response,
36+
]))
37+
}
38+
39+
lifecycle {
40+
create_before_destroy = true
41+
}
42+
}
43+
44+
resource "aws_api_gateway_method_settings" "all" {
45+
rest_api_id = aws_api_gateway_rest_api.api_gateway.id
46+
stage_name = aws_api_gateway_stage.default.stage_name
47+
method_path = "*/*"
48+
49+
settings {
50+
caching_enabled = false
51+
cache_data_encrypted = true
52+
metrics_enabled = true
53+
54+
logging_level = "INFO"
55+
data_trace_enabled = false
56+
57+
# Throttling defined at path (or endpoint) level
58+
throttling_burst_limit = var.api_gateway_throttling_burst_limit
59+
throttling_rate_limit = var.api_gateway_throttling_rate_limit
60+
}
61+
62+
depends_on = [aws_cloudwatch_log_group.api_gateway_log_group]
63+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Healthcare Service Resource
2+
resource "aws_api_gateway_resource" "healthcare_service" {
3+
rest_api_id = aws_api_gateway_rest_api.api_gateway.id
4+
parent_id = aws_api_gateway_rest_api.api_gateway.root_resource_id
5+
path_part = "healthcare-service"
6+
}
7+
8+
# Healthcare Service Proxy Resource (for any sub-paths)
9+
resource "aws_api_gateway_resource" "healthcare_service_proxy" {
10+
rest_api_id = aws_api_gateway_rest_api.api_gateway.id
11+
parent_id = aws_api_gateway_resource.healthcare_service.id
12+
path_part = "{proxy+}"
13+
}
14+
15+
# ANY /healthcare-service/{proxy+}
16+
resource "aws_api_gateway_method" "healthcare_service_proxy" {
17+
# checkov:skip=CKV_AWS_59: False positive; all the endpoints will be authenticated via mTLS
18+
rest_api_id = aws_api_gateway_rest_api.api_gateway.id
19+
resource_id = aws_api_gateway_resource.healthcare_service_proxy.id
20+
http_method = "ANY"
21+
authorization = "NONE"
22+
}
23+
24+
resource "aws_api_gateway_integration" "healthcare_service_proxy" {
25+
rest_api_id = aws_api_gateway_rest_api.api_gateway.id
26+
resource_id = aws_api_gateway_resource.healthcare_service_proxy.id
27+
http_method = aws_api_gateway_method.healthcare_service_proxy.http_method
28+
integration_http_method = "POST"
29+
type = "AWS_PROXY"
30+
uri = module.healthcare_service_api_lambda.lambda_function_invoke_arn
31+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Location Resource
2+
resource "aws_api_gateway_resource" "location" {
3+
rest_api_id = aws_api_gateway_rest_api.api_gateway.id
4+
parent_id = aws_api_gateway_rest_api.api_gateway.root_resource_id
5+
path_part = "location"
6+
}
7+
8+
# Location Proxy Resource (for any sub-paths)
9+
resource "aws_api_gateway_resource" "location_proxy" {
10+
rest_api_id = aws_api_gateway_rest_api.api_gateway.id
11+
parent_id = aws_api_gateway_resource.location.id
12+
path_part = "{proxy+}"
13+
}
14+
15+
# ANY /location/{proxy+}
16+
resource "aws_api_gateway_method" "location_proxy" {
17+
# checkov:skip=CKV_AWS_59: False positive; all the endpoints will be authenticated via mTLS
18+
rest_api_id = aws_api_gateway_rest_api.api_gateway.id
19+
resource_id = aws_api_gateway_resource.location_proxy.id
20+
http_method = "ANY"
21+
authorization = "NONE"
22+
}
23+
24+
resource "aws_api_gateway_integration" "location_proxy" {
25+
rest_api_id = aws_api_gateway_rest_api.api_gateway.id
26+
resource_id = aws_api_gateway_resource.location_proxy.id
27+
http_method = aws_api_gateway_method.location_proxy.http_method
28+
integration_http_method = "POST"
29+
type = "AWS_PROXY"
30+
uri = module.location_api_lambda.lambda_function_invoke_arn
31+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Organization Resource
2+
resource "aws_api_gateway_resource" "organization" {
3+
rest_api_id = aws_api_gateway_rest_api.api_gateway.id
4+
parent_id = aws_api_gateway_rest_api.api_gateway.root_resource_id
5+
path_part = "Organization"
6+
}
7+
8+
# GET /Organization
9+
resource "aws_api_gateway_method" "organization_get" {
10+
# checkov:skip=CKV_AWS_59: False positive; all the endpoints will be authenticated via mTLS
11+
rest_api_id = aws_api_gateway_rest_api.api_gateway.id
12+
resource_id = aws_api_gateway_resource.organization.id
13+
http_method = "GET"
14+
authorization = "NONE"
15+
16+
request_validator_id = aws_api_gateway_request_validator.validator.id
17+
}
18+
19+
resource "aws_api_gateway_integration" "organization_get" {
20+
rest_api_id = aws_api_gateway_rest_api.api_gateway.id
21+
resource_id = aws_api_gateway_resource.organization.id
22+
http_method = aws_api_gateway_method.organization_get.http_method
23+
integration_http_method = "POST"
24+
type = "AWS_PROXY"
25+
uri = module.organisation_api_lambda.lambda_function_invoke_arn
26+
}
27+
28+
# POST /Organization
29+
resource "aws_api_gateway_method" "organization_post" {
30+
# checkov:skip=CKV_AWS_59: False positive; all the endpoints will be authenticated via mTLS
31+
rest_api_id = aws_api_gateway_rest_api.api_gateway.id
32+
resource_id = aws_api_gateway_resource.organization.id
33+
http_method = "POST"
34+
authorization = "NONE"
35+
36+
request_validator_id = aws_api_gateway_request_validator.validator.id
37+
}
38+
39+
resource "aws_api_gateway_integration" "organization_post" {
40+
rest_api_id = aws_api_gateway_rest_api.api_gateway.id
41+
resource_id = aws_api_gateway_resource.organization.id
42+
http_method = aws_api_gateway_method.organization_post.http_method
43+
integration_http_method = "POST"
44+
type = "AWS_PROXY"
45+
uri = module.organisation_api_lambda.lambda_function_invoke_arn
46+
}
47+
48+
# Organization Proxy Resource (for any sub-paths)
49+
resource "aws_api_gateway_resource" "organization_proxy" {
50+
rest_api_id = aws_api_gateway_rest_api.api_gateway.id
51+
parent_id = aws_api_gateway_resource.organization.id
52+
path_part = "{proxy+}"
53+
}
54+
55+
# ANY /Organization/{proxy+}
56+
resource "aws_api_gateway_method" "organization_proxy" {
57+
# checkov:skip=CKV_AWS_59: False positive; all the endpoints will be authenticated via mTLS
58+
rest_api_id = aws_api_gateway_rest_api.api_gateway.id
59+
resource_id = aws_api_gateway_resource.organization_proxy.id
60+
http_method = "ANY"
61+
authorization = "NONE"
62+
63+
request_validator_id = aws_api_gateway_request_validator.validator.id
64+
}
65+
66+
resource "aws_api_gateway_integration" "organization_proxy" {
67+
rest_api_id = aws_api_gateway_rest_api.api_gateway.id
68+
resource_id = aws_api_gateway_resource.organization_proxy.id
69+
http_method = aws_api_gateway_method.organization_proxy.http_method
70+
integration_http_method = "POST"
71+
type = "AWS_PROXY"
72+
uri = module.organisation_api_lambda.lambda_function_invoke_arn
73+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Status Resource
2+
resource "aws_api_gateway_resource" "status" {
3+
rest_api_id = aws_api_gateway_rest_api.api_gateway.id
4+
parent_id = aws_api_gateway_rest_api.api_gateway.root_resource_id
5+
path_part = "_status"
6+
}
7+
8+
# GET /_status
9+
resource "aws_api_gateway_method" "status" {
10+
# checkov:skip=CKV_AWS_59: False positive; all the endpoints will be authenticated via mTLS
11+
rest_api_id = aws_api_gateway_rest_api.api_gateway.id
12+
resource_id = aws_api_gateway_resource.status.id
13+
http_method = "GET"
14+
authorization = "NONE"
15+
}
16+
17+
resource "aws_api_gateway_integration" "status" {
18+
rest_api_id = aws_api_gateway_rest_api.api_gateway.id
19+
resource_id = aws_api_gateway_resource.status.id
20+
http_method = aws_api_gateway_method.status.http_method
21+
integration_http_method = "POST"
22+
type = "AWS_PROXY"
23+
uri = module.organisation_api_lambda.lambda_function_invoke_arn
24+
}

0 commit comments

Comments
 (0)