Skip to content

Commit 7d9a3f2

Browse files
Refactor header validation
1 parent d37e735 commit 7d9a3f2

File tree

4 files changed

+61
-33
lines changed

4 files changed

+61
-33
lines changed
Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { APIGatewayProxyHandler } from "aws-lambda";
2-
import { assertNotEmpty, lowerCaseKeys } from "../utils/validation";
2+
import { assertNotEmpty, validateCommonHeaders } from "../utils/validation";
33
import { ApiErrorDetail } from '../contracts/errors';
44
import { mapErrorToResponse } from "../mappers/error-mapper";
55
import { ValidationError } from "../errors";
@@ -11,28 +11,26 @@ export function createGetLetterDataHandler(deps: Deps): APIGatewayProxyHandler {
1111

1212
return async (event) => {
1313

14-
let correlationId: string | undefined;
14+
const commonHeadersResult = validateCommonHeaders(event.headers, deps);
15+
16+
if (!commonHeadersResult.ok) {
17+
return mapErrorToResponse(commonHeadersResult.error, commonHeadersResult.correlationId, deps.logger);
18+
}
1519

1620
try {
17-
assertNotEmpty(event.headers, new Error("The request headers are empty"));
18-
const lowerCasedHeaders = lowerCaseKeys(event.headers);
19-
correlationId = assertNotEmpty(lowerCasedHeaders[deps.env.APIM_CORRELATION_HEADER],
20-
new Error("The request headers don't contain the APIM correlation id"));
21-
const supplierId = assertNotEmpty(lowerCasedHeaders[deps.env.SUPPLIER_ID_HEADER],
22-
new ValidationError(ApiErrorDetail.InvalidRequestMissingSupplierId));
2321
const letterId = assertNotEmpty( event.pathParameters?.id,
2422
new ValidationError(ApiErrorDetail.InvalidRequestMissingLetterIdPathParameter));
2523

2624
return {
2725
statusCode: 303,
2826
headers: {
29-
'Location': await getLetterDataUrl(supplierId, letterId, deps)
27+
'Location': await getLetterDataUrl(commonHeadersResult.value.supplierId, letterId, deps)
3028
},
3129
body: ''
3230
};
3331
}
3432
catch (error) {
35-
return mapErrorToResponse(error, correlationId, deps.logger);
33+
return mapErrorToResponse(error, commonHeadersResult.value.correlationId, deps.logger);
3634
}
3735
}
3836
};

lambdas/api-handler/src/handlers/get-letters.ts

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { APIGatewayProxyEventQueryStringParameters, APIGatewayProxyHandler } from "aws-lambda";
22
import { getLettersForSupplier } from "../services/letter-operations";
3-
import { assertNotEmpty, lowerCaseKeys } from "../utils/validation";
3+
import { validateCommonHeaders } from "../utils/validation";
44
import { ApiErrorDetail } from '../contracts/errors';
55
import { mapErrorToResponse } from "../mappers/error-mapper";
66
import { ValidationError } from "../errors";
@@ -19,21 +19,19 @@ export function createGetLettersHandler(deps: Deps): APIGatewayProxyHandler {
1919

2020
return async (event) => {
2121

22-
const { maxLimit } = getMaxLimit();
22+
const commonHeadersResult = validateCommonHeaders(event.headers, deps);
23+
24+
if (!commonHeadersResult.ok) {
25+
return mapErrorToResponse(commonHeadersResult.error, commonHeadersResult.correlationId, deps.logger);
26+
}
2327

24-
let correlationId: string | undefined;
28+
const { maxLimit } = getMaxLimit();
2529

2630
try {
27-
assertNotEmpty(event.headers, new Error("The request headers are empty"));
28-
const lowerCasedHeaders = lowerCaseKeys(event.headers);
29-
correlationId = assertNotEmpty(lowerCasedHeaders[deps.env.APIM_CORRELATION_HEADER],
30-
new Error("The request headers don't contain the APIM correlation id"));
31-
const supplierId = assertNotEmpty(lowerCasedHeaders[deps.env.SUPPLIER_ID_HEADER],
32-
new ValidationError(ApiErrorDetail.InvalidRequestMissingSupplierId));
3331
const limitNumber = getLimitOrDefault(event.queryStringParameters, maxLimit, deps.logger);
3432

3533
const letters = await getLettersForSupplier(
36-
supplierId,
34+
commonHeadersResult.value.supplierId,
3735
status,
3836
limitNumber,
3937
deps.letterRepo,
@@ -43,7 +41,7 @@ export function createGetLettersHandler(deps: Deps): APIGatewayProxyHandler {
4341

4442
deps.logger.info({
4543
description: 'Pending letters successfully fetched',
46-
supplierId,
44+
supplierId: commonHeadersResult.value.supplierId,
4745
limitNumber,
4846
status,
4947
lettersCount: letters.length
@@ -55,7 +53,7 @@ export function createGetLettersHandler(deps: Deps): APIGatewayProxyHandler {
5553
};
5654
}
5755
catch (error) {
58-
return mapErrorToResponse(error, correlationId, deps.logger);
56+
return mapErrorToResponse(error, commonHeadersResult.value.correlationId, deps.logger);
5957
}
6058
}
6159
};

lambdas/api-handler/src/handlers/patch-letter.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { PatchLetterRequest, PatchLetterRequestSchema } from '../contracts/lette
44
import { ApiErrorDetail } from '../contracts/errors';
55
import { ValidationError } from '../errors';
66
import { mapErrorToResponse } from '../mappers/error-mapper';
7-
import { assertNotEmpty, lowerCaseKeys } from '../utils/validation';
7+
import { assertNotEmpty, validateCommonHeaders } from '../utils/validation';
88
import { mapToLetterDto } from '../mappers/letter-mapper';
99
import type { Deps } from "../config/deps";
1010

@@ -13,15 +13,13 @@ export function createPatchLetterHandler(deps: Deps): APIGatewayProxyHandler {
1313

1414
return async (event) => {
1515

16-
let correlationId: string | undefined;
16+
const commonHeadersResult = validateCommonHeaders(event.headers, deps);
17+
18+
if (!commonHeadersResult.ok) {
19+
return mapErrorToResponse(commonHeadersResult.error, commonHeadersResult.correlationId, deps.logger);
20+
}
1721

1822
try {
19-
assertNotEmpty(event.headers, new Error('The request headers are empty'));
20-
const lowerCasedHeaders = lowerCaseKeys(event.headers);
21-
correlationId = assertNotEmpty(lowerCasedHeaders[deps.env.APIM_CORRELATION_HEADER],
22-
new Error("The request headers don't contain the APIM correlation id"));
23-
const supplierId = assertNotEmpty(lowerCasedHeaders[deps.env.SUPPLIER_ID_HEADER],
24-
new ValidationError(ApiErrorDetail.InvalidRequestMissingSupplierId));
2523
const letterId = assertNotEmpty( event.pathParameters?.id,
2624
new ValidationError(ApiErrorDetail.InvalidRequestMissingLetterIdPathParameter));
2725
const body = assertNotEmpty(event.body, new ValidationError(ApiErrorDetail.InvalidRequestMissingBody));
@@ -37,15 +35,15 @@ export function createPatchLetterHandler(deps: Deps): APIGatewayProxyHandler {
3735
else throw error;
3836
}
3937

40-
const result = await patchLetterStatus(mapToLetterDto(patchLetterRequest, supplierId), letterId, deps.letterRepo);
38+
const updatedLetter = await patchLetterStatus(mapToLetterDto(patchLetterRequest, commonHeadersResult.value.supplierId), letterId, deps.letterRepo);
4139

4240
return {
4341
statusCode: 200,
44-
body: JSON.stringify(result, null, 2)
42+
body: JSON.stringify(updatedLetter, null, 2)
4543
};
4644

4745
} catch (error) {
48-
return mapErrorToResponse(error, correlationId, deps.logger);
46+
return mapErrorToResponse(error, commonHeadersResult.value.correlationId, deps.logger);
4947
}
5048
};
5149
};

lambdas/api-handler/src/utils/validation.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
import { APIGatewayProxyEventHeaders } from "aws-lambda";
2+
import { EnvVars } from "../config/env";
3+
import { ValidationError } from "../errors";
4+
import { ApiErrorDetail } from "../contracts/errors";
5+
import { mapErrorToResponse } from "../mappers/error-mapper";
6+
import { getLetterDataUrl } from "../services/letter-operations";
7+
import { Deps } from "../config/deps";
8+
19
export function assertNotEmpty<T>(
210
value: T | null | undefined,
311
error: Error
@@ -20,3 +28,29 @@ export function assertNotEmpty<T>(
2028
export function lowerCaseKeys(obj: Record<string, any>): Record<string, any> {
2129
return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k.toLowerCase(), v]));
2230
}
31+
32+
export function validateCommonHeaders(headers: APIGatewayProxyEventHeaders, deps: Deps
33+
): { ok: true; value: {correlationId: string, supplierId: string } } | { ok: false; error: Error; correlationId?: string } {
34+
35+
if (!headers || Object.keys(headers).length === 0) {
36+
return { ok: false, error: new Error("The request headers are empty") };
37+
}
38+
39+
const lowerCasedHeaders = lowerCaseKeys(headers);
40+
41+
const correlationId = lowerCasedHeaders[deps.env.APIM_CORRELATION_HEADER];
42+
if (!correlationId) {
43+
return { ok: false, error: new Error("The request headers don't contain the APIM correlation id") };
44+
}
45+
46+
const supplierId = lowerCasedHeaders[deps.env.SUPPLIER_ID_HEADER];
47+
if (!supplierId) {
48+
return {
49+
ok: false,
50+
error: new ValidationError(ApiErrorDetail.InvalidRequestMissingSupplierId),
51+
correlationId,
52+
};
53+
}
54+
55+
return { ok: true, value: { correlationId, supplierId } };
56+
}

0 commit comments

Comments
 (0)