11import { APIGatewayProxyHandler } from "aws-lambda" ;
2- import { MetricsLogger , Unit , metricScope } from "aws-embedded-metrics" ;
2+ import { Unit } from "aws-embedded-metrics" ;
3+ import pino from "pino" ;
34import type { Deps } from "../config/deps" ;
45import { ApiErrorDetail } from "../contracts/errors" ;
56import {
@@ -13,7 +14,7 @@ import { mapToUpdateCommands } from "../mappers/letter-mapper";
1314import { enqueueLetterUpdateRequests } from "../services/letter-operations" ;
1415import { extractCommonIds } from "../utils/common-ids" ;
1516import { assertNotEmpty , requireEnvVar } from "../utils/validation" ;
16- import { MetricStatus } from "../utils/metrics" ;
17+ import { MetricEntry , MetricStatus , buildEMFObject } from "../utils/metrics" ;
1718
1819function duplicateIdsExist ( postLettersRequest : PostLettersRequest ) {
1920 const ids = postLettersRequest . data . map ( ( item ) => item . id ) ;
@@ -23,17 +24,23 @@ function duplicateIdsExist(postLettersRequest: PostLettersRequest) {
2324/**
2425 * emits metrics of successful letter updates, including the supplier and grouped by status
2526 */
26- function emitMetics (
27- metrics : MetricsLogger ,
27+ function emitSuccessMetrics (
2828 supplierId : string ,
2929 statusesMapping : Map < string , number > ,
30+ logger : pino . Logger ,
3031) {
3132 for ( const [ status , count ] of statusesMapping ) {
32- metrics . putDimensions ( {
33+ const dimensions : Record < string , string > = {
3334 supplier : supplierId ,
3435 eventType : status ,
35- } ) ;
36- metrics . putMetric ( MetricStatus . Success , count , Unit . Count ) ;
36+ } ;
37+ const metric : MetricEntry = {
38+ key : "Letters posted" ,
39+ value : count ,
40+ unit : Unit . Count ,
41+ } ;
42+ const emf = buildEMFObject ( "postLetters" , dimensions , metric ) ;
43+ logger . info ( emf ) ;
3744 }
3845}
3946
@@ -48,85 +55,90 @@ function populateStatusesMap(updateLetterCommands: UpdateLetterCommand[]) {
4855export default function createPostLettersHandler (
4956 deps : Deps ,
5057) : APIGatewayProxyHandler {
51- return metricScope ( ( metrics : MetricsLogger ) => {
52- return async ( event ) => {
53- const commonIds = extractCommonIds (
54- event . headers ,
55- event . requestContext ,
56- deps ,
57- ) ;
58+ return async ( event ) => {
59+ const commonIds = extractCommonIds (
60+ event . headers ,
61+ event . requestContext ,
62+ deps ,
63+ ) ;
5864
59- if ( ! commonIds . ok ) {
60- return processError (
61- commonIds . error ,
62- commonIds . correlationId ,
63- deps . logger ,
64- ) ;
65- }
65+ if ( ! commonIds . ok ) {
66+ return processError (
67+ commonIds . error ,
68+ commonIds . correlationId ,
69+ deps . logger ,
70+ ) ;
71+ }
6672
67- const maxUpdateItems = requireEnvVar ( deps . env , "MAX_LIMIT" ) ;
68- requireEnvVar ( deps . env , "QUEUE_URL" ) ;
73+ const maxUpdateItems = requireEnvVar ( deps . env , "MAX_LIMIT" ) ;
74+ requireEnvVar ( deps . env , "QUEUE_URL" ) ;
6975
70- const { supplierId } = commonIds . value ;
71- metrics . setNamespace (
72- process . env . AWS_LAMBDA_FUNCTION_NAME || "postLetters" ,
76+ const { supplierId } = commonIds . value ;
77+ try {
78+ const body = assertNotEmpty (
79+ event . body ,
80+ new ValidationError ( ApiErrorDetail . InvalidRequestMissingBody ) ,
7381 ) ;
82+
83+ let postLettersRequest : PostLettersRequest ;
84+
7485 try {
75- const body = assertNotEmpty (
76- event . body ,
77- new ValidationError ( ApiErrorDetail . InvalidRequestMissingBody ) ,
78- ) ;
86+ postLettersRequest = PostLettersRequestSchema . parse ( JSON . parse ( body ) ) ;
87+ } catch ( error ) {
88+ const typedError =
89+ error instanceof Error
90+ ? new ValidationError ( ApiErrorDetail . InvalidRequestBody , {
91+ cause : error ,
92+ } )
93+ : error ;
94+ throw typedError ;
95+ }
7996
80- let postLettersRequest : PostLettersRequest ;
97+ if ( postLettersRequest . data . length > maxUpdateItems ) {
98+ throw new ValidationError (
99+ ApiErrorDetail . InvalidRequestLettersToUpdate ,
100+ { args : [ maxUpdateItems ] } ,
101+ ) ;
102+ }
81103
82- try {
83- postLettersRequest = PostLettersRequestSchema . parse ( JSON . parse ( body ) ) ;
84- } catch ( error ) {
85- const typedError =
86- error instanceof Error
87- ? new ValidationError ( ApiErrorDetail . InvalidRequestBody , {
88- cause : error ,
89- } )
90- : error ;
91- throw typedError ;
92- }
104+ if ( duplicateIdsExist ( postLettersRequest ) ) {
105+ throw new ValidationError (
106+ ApiErrorDetail . InvalidRequestDuplicateLetterId ,
107+ ) ;
108+ }
93109
94- if ( postLettersRequest . data . length > maxUpdateItems ) {
95- throw new ValidationError (
96- ApiErrorDetail . InvalidRequestLettersToUpdate ,
97- { args : [ maxUpdateItems ] } ,
98- ) ;
99- }
110+ const updateLetterCommands : UpdateLetterCommand [ ] = mapToUpdateCommands (
111+ postLettersRequest ,
112+ supplierId ,
113+ ) ;
114+ const statusesMapping = populateStatusesMap ( updateLetterCommands ) ;
115+ await enqueueLetterUpdateRequests (
116+ updateLetterCommands ,
117+ commonIds . value . correlationId ,
118+ deps ,
119+ ) ;
100120
101- if ( duplicateIdsExist ( postLettersRequest ) ) {
102- throw new ValidationError (
103- ApiErrorDetail . InvalidRequestDuplicateLetterId ,
104- ) ;
105- }
121+ emitSuccessMetrics ( supplierId , statusesMapping , deps . logger ) ;
122+ return {
123+ statusCode : 202 ,
124+ body : "" ,
125+ } ;
126+ } catch ( error ) {
127+ // error metrics
128+ emitErrorMetrics ( supplierId , deps . logger ) ;
106129
107- const updateLetterCommands : UpdateLetterCommand [ ] = mapToUpdateCommands (
108- postLettersRequest ,
109- supplierId ,
110- ) ;
111- const statusesMapping = populateStatusesMap ( updateLetterCommands ) ;
112- await enqueueLetterUpdateRequests (
113- updateLetterCommands ,
114- commonIds . value . correlationId ,
115- deps ,
116- ) ;
130+ return processError ( error , commonIds . value . correlationId , deps . logger ) ;
131+ }
132+ } ;
133+ }
117134
118- emitMetics ( metrics , supplierId , statusesMapping ) ;
119- return {
120- statusCode : 202 ,
121- body : "" ,
122- } ;
123- } catch ( error ) {
124- metrics . putDimensions ( {
125- supplier : supplierId ,
126- } ) ;
127- metrics . putMetric ( MetricStatus . Failure , 1 , Unit . Count ) ;
128- return processError ( error , commonIds . value . correlationId , deps . logger ) ;
129- }
130- } ;
131- } ) ;
135+ function emitErrorMetrics ( supplierId : string , logger : pino . Logger ) {
136+ const dimensions : Record < string , string > = { supplier : supplierId } ;
137+ const metric : MetricEntry = {
138+ key : MetricStatus . Failure ,
139+ value : 1 ,
140+ unit : Unit . Count ,
141+ } ;
142+ const emf = buildEMFObject ( "postLetters" , dimensions , metric ) ;
143+ logger . info ( emf ) ;
132144}
0 commit comments