Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions internal/datastore/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"dependencies": {
"@aws-sdk/client-dynamodb": "^3.858.0",
"@aws-sdk/lib-dynamodb": "^3.858.0",
"@aws-sdk/client-dynamodb": "^3.981.0",
"@aws-sdk/lib-dynamodb": "^3.981.0",
"@internal/helpers": "*",
"pino": "^9.7.0",
"zod": "^4.1.11",
Expand Down
7 changes: 4 additions & 3 deletions lambdas/api-handler/package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
{
"dependencies": {
"@aws-sdk/client-dynamodb": "^3.925.0",
"@aws-sdk/client-dynamodb": "^3.981.0",
"@aws-sdk/client-s3": "^3.925.0",
"@aws-sdk/client-sqs": "^3.925.0",
"@aws-sdk/lib-dynamodb": "^3.925.0",
"@aws-sdk/s3-request-presigner": "^3.925.0",
"@internal/datastore": "*",
"@internal/helpers": "*",
"aws-lambda": "^1.0.7",
"esbuild": "^0.25.11",
"aws-embedded-metrics": "^4.2.1",
"aws-lambda": "^1.0.6",
"esbuild": "0.27.2",
"pino": "^9.7.0",
"zod": "^4.1.11"
},
Expand Down
83 changes: 49 additions & 34 deletions lambdas/api-handler/src/handlers/get-letter-data.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,66 @@
import { APIGatewayProxyHandler } from "aws-lambda";
import { MetricsLogger, metricScope } from "aws-embedded-metrics";
import { assertNotEmpty } from "../utils/validation";
import { extractCommonIds } from "../utils/common-ids";
import { ApiErrorDetail } from "../contracts/errors";
import { processError } from "../mappers/error-mapper";
import ValidationError from "../errors/validation-error";
import { getLetterDataUrl } from "../services/letter-operations";
import type { Deps } from "../config/deps";
import { MetricStatus, emitForSingleSupplier } from "../utils/metrics";

export default function createGetLetterDataHandler(
deps: Deps,
): APIGatewayProxyHandler {
return async (event) => {
const commonIds = extractCommonIds(
event.headers,
event.requestContext,
deps,
);

if (!commonIds.ok) {
return processError(
commonIds.error,
commonIds.correlationId,
deps.logger,
return metricScope((metrics: MetricsLogger) => {
return async (event) => {
const commonIds = extractCommonIds(
event.headers,
event.requestContext,
deps,
);
}

try {
const letterId = assertNotEmpty(
event.pathParameters?.id,
new ValidationError(
ApiErrorDetail.InvalidRequestMissingLetterIdPathParameter,
),
);
if (!commonIds.ok) {
return processError(
commonIds.error,
commonIds.correlationId,
deps.logger,
);
}

return {
statusCode: 303,
headers: {
Location: await getLetterDataUrl(
commonIds.value.supplierId,
letterId,
deps,
const { supplierId } = commonIds.value;
try {
const letterId = assertNotEmpty(
event.pathParameters?.id,
new ValidationError(
ApiErrorDetail.InvalidRequestMissingLetterIdPathParameter,
),
},
body: "",
};
} catch (error) {
return processError(error, commonIds.value.correlationId, deps.logger);
}
};
);

emitForSingleSupplier(
metrics,
"getLetterData",
supplierId,
1,
MetricStatus.Success,
);
return {
statusCode: 303,
headers: {
Location: await getLetterDataUrl(supplierId, letterId, deps),
},
body: "",
};
} catch (error) {
emitForSingleSupplier(
metrics,
"getLetterData",
supplierId,
1,
MetricStatus.Failure,
);
return processError(error, commonIds.value.correlationId, deps.logger);
}
};
});
}
98 changes: 59 additions & 39 deletions lambdas/api-handler/src/handlers/get-letter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { APIGatewayProxyHandler } from "aws-lambda";
import { MetricsLogger, metricScope } from "aws-embedded-metrics";
import { assertNotEmpty } from "../utils/validation";
import { extractCommonIds } from "../utils/common-ids";
import ValidationError from "../errors/validation-error";
Expand All @@ -7,53 +8,72 @@ import { getLetterById } from "../services/letter-operations";
import { processError } from "../mappers/error-mapper";
import { mapToGetLetterResponse } from "../mappers/letter-mapper";
import { Deps } from "../config/deps";
import { MetricStatus, emitForSingleSupplier } from "../utils/metrics";

// Get letter data
export default function createGetLetterHandler(
deps: Deps,
): APIGatewayProxyHandler {
return async (event) => {
const commonIds = extractCommonIds(
event.headers,
event.requestContext,
deps,
);

if (!commonIds.ok) {
return processError(
commonIds.error,
commonIds.correlationId,
deps.logger,
return metricScope((metrics: MetricsLogger) => {
return async (event) => {
const commonIds = extractCommonIds(
event.headers,
event.requestContext,
deps,
);
}

try {
const letterId = assertNotEmpty(
event.pathParameters?.id,
new ValidationError(
ApiErrorDetail.InvalidRequestMissingLetterIdPathParameter,
),
);
if (!commonIds.ok) {
return processError(
commonIds.error,
commonIds.correlationId,
deps.logger,
);
}

const letter = await getLetterById(
commonIds.value.supplierId,
letterId,
deps.letterRepo,
);
const { supplierId } = commonIds.value;
try {
const letterId = assertNotEmpty(
event.pathParameters?.id,
new ValidationError(
ApiErrorDetail.InvalidRequestMissingLetterIdPathParameter,
),
);

const letter = await getLetterById(
supplierId,
letterId,
deps.letterRepo,
);

const response = mapToGetLetterResponse(letter);
const response = mapToGetLetterResponse(letter);

deps.logger.info({
description: "Letter successfully fetched by id",
supplierId: commonIds.value.supplierId,
letterId,
});
deps.logger.info({
description: "Letter successfully fetched by id",
supplierId,
letterId,
});

return {
statusCode: 200,
body: JSON.stringify(response, null, 2),
};
} catch (error) {
return processError(error, commonIds.value.correlationId, deps.logger);
}
};
emitForSingleSupplier(
metrics,
"getLetter",
supplierId,
1,
MetricStatus.Success,
);
return {
statusCode: 200,
body: JSON.stringify(response, null, 2),
};
} catch (error) {
emitForSingleSupplier(
metrics,
"getLetter",
supplierId,
1,
MetricStatus.Failure,
);
return processError(error, commonIds.value.correlationId, deps.logger);
}
};
});
}
104 changes: 62 additions & 42 deletions lambdas/api-handler/src/handlers/get-letters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
APIGatewayProxyHandler,
} from "aws-lambda";
import { Logger } from "pino";
import { MetricsLogger, metricScope } from "aws-embedded-metrics";
import { getLettersForSupplier } from "../services/letter-operations";
import { extractCommonIds } from "../utils/common-ids";
import { requireEnvVar } from "../utils/validation";
Expand All @@ -11,7 +12,9 @@ import { processError } from "../mappers/error-mapper";
import ValidationError from "../errors/validation-error";
import { mapToGetLettersResponse } from "../mappers/letter-mapper";
import type { Deps } from "../config/deps";
import { MetricStatus, emitForSingleSupplier } from "../utils/metrics";

// List letters Handlers
// The endpoint should only return pending letters for now
const status = "PENDING";

Expand Down Expand Up @@ -82,53 +85,70 @@ function getLimitOrDefault(
export default function createGetLettersHandler(
deps: Deps,
): APIGatewayProxyHandler {
return async (event) => {
const commonIds = extractCommonIds(
event.headers,
event.requestContext,
deps,
);

if (!commonIds.ok) {
return processError(
commonIds.error,
commonIds.correlationId,
deps.logger,
return metricScope((metrics: MetricsLogger) => {
return async (event) => {
const commonIds = extractCommonIds(
event.headers,
event.requestContext,
deps,
);
}

try {
const maxLimit = requireEnvVar(deps.env, "MAX_LIMIT");
if (!commonIds.ok) {
return processError(
commonIds.error,
commonIds.correlationId,
deps.logger,
);
}

const limitNumber = getLimitOrDefault(
event.queryStringParameters,
maxLimit,
deps.logger,
);
const { supplierId } = commonIds.value;
try {
const maxLimit = requireEnvVar(deps.env, "MAX_LIMIT");

const letters = await getLettersForSupplier(
commonIds.value.supplierId,
status,
limitNumber,
deps.letterRepo,
);
const limitNumber = getLimitOrDefault(
event.queryStringParameters,
maxLimit,
deps.logger,
);

const letters = await getLettersForSupplier(
supplierId,
status,
limitNumber,
deps.letterRepo,
);

const response = mapToGetLettersResponse(letters);
const response = mapToGetLettersResponse(letters);

deps.logger.info({
description: "Pending letters successfully fetched",
supplierId: commonIds.value.supplierId,
limitNumber,
status,
lettersCount: letters.length,
});
deps.logger.info({
description: "Pending letters successfully fetched",
supplierId,
limitNumber,
status,
lettersCount: letters.length,
});

return {
statusCode: 200,
body: JSON.stringify(response, null, 2),
};
} catch (error) {
return processError(error, commonIds.value.correlationId, deps.logger);
}
};
emitForSingleSupplier(
metrics,
"getLetters",
supplierId,
letters.length,
MetricStatus.Success,
);
return {
statusCode: 200,
body: JSON.stringify(response, null, 2),
};
} catch (error) {
emitForSingleSupplier(
metrics,
"getLetters",
supplierId,
1,
MetricStatus.Failure,
);
return processError(error, commonIds.value.correlationId, deps.logger);
}
};
});
}
Loading
Loading