11import { IdempotencyHandler } from '../IdempotencyHandler' ;
22import { IdempotencyConfig } from '../IdempotencyConfig' ;
3- import { cleanupMiddlewares } from '@aws-lambda-powertools/commons/lib/middleware' ;
3+ import {
4+ cleanupMiddlewares ,
5+ IDEMPOTENCY_KEY ,
6+ } from '@aws-lambda-powertools/commons/lib/middleware' ;
47import {
58 IdempotencyInconsistentStateError ,
69 IdempotencyItemAlreadyExistsError ,
@@ -9,51 +12,94 @@ import {
912import { IdempotencyRecord } from '../persistence' ;
1013import { MAX_RETRIES } from '../constants' ;
1114import type { IdempotencyLambdaHandlerOptions } from '../types' ;
15+ import type { BasePersistenceLayerInterface } from '../persistence' ;
1216import {
1317 MiddlewareLikeObj ,
1418 MiddyLikeRequest ,
1519 JSONValue ,
1620} from '@aws-lambda-powertools/commons' ;
1721
22+ /**
23+ * @internal
24+ * Utility function to get the persistence store from the request internal storage
25+ *
26+ * @param request The Middy request object
27+ * @returns The persistence store from the request internal
28+ */
29+ const getPersistenceStoreFromRequestInternal = (
30+ request : MiddyLikeRequest
31+ ) : BasePersistenceLayerInterface => {
32+ const persistenceStore = request . internal [
33+ `${ IDEMPOTENCY_KEY } .idempotencyPersistenceStore`
34+ ] as BasePersistenceLayerInterface ;
35+
36+ return persistenceStore ;
37+ } ;
38+
39+ /**
40+ * @internal
41+ * Utility function to set the persistence store in the request internal storage
42+ *
43+ * @param request The Middy request object
44+ * @param persistenceStore The persistence store to set in the request internal
45+ */
46+ const setPersistenceStoreInRequestInternal = (
47+ request : MiddyLikeRequest ,
48+ persistenceStore : BasePersistenceLayerInterface
49+ ) : void => {
50+ request . internal [ `${ IDEMPOTENCY_KEY } .idempotencyPersistenceStore` ] =
51+ persistenceStore ;
52+ } ;
53+
54+ /**
55+ * @internal
56+ * Utility function to set a flag in the request internal storage to skip the idempotency middleware
57+ * This is used to skip the idempotency middleware when the idempotency key is not present in the payload
58+ * or when idempotency is disabled
59+ *
60+ * @param request The Middy request object
61+ */
62+ const setIdempotencySkipFlag = ( request : MiddyLikeRequest ) : void => {
63+ request . internal [ `${ IDEMPOTENCY_KEY } .skip` ] = true ;
64+ } ;
65+
66+ /**
67+ * @internal
68+ * Utility function to get the idempotency key from the request internal storage
69+ * and determine if the request should skip the idempotency middleware
70+ *
71+ * @param request The Middy request object
72+ * @returns Whether the idempotency middleware should be skipped
73+ */
74+ const shouldSkipIdempotency = ( request : MiddyLikeRequest ) : boolean => {
75+ return request . internal [ `${ IDEMPOTENCY_KEY } .skip` ] === true ;
76+ } ;
77+
1878/**
1979 * A middy middleware to make your Lambda Handler idempotent.
2080 *
2181 * @example
2282 * ```typescript
23- * import {
24- * makeHandlerIdempotent,
25- * DynamoDBPersistenceLayer,
26- * } from '@aws-lambda-powertools/idempotency';
83+ * import { makeHandlerIdempotent } from '@aws-lambda-powertools/idempotency/middleware';
84+ * import { DynamoDBPersistenceLayer } from '@aws-lambda-powertools/idempotency/dynamodb';
2785 * import middy from '@middy/core';
2886 *
29- * const dynamoDBPersistenceLayer = new DynamoDBPersistenceLayer({
30- * tableName: 'idempotencyTable',
87+ * const persistenceStore = new DynamoDBPersistenceLayer({
88+ * tableName: 'idempotencyTable',
3189 * });
3290 *
33- * const lambdaHandler = async (_event: unknown, _context: unknown) => {
34- * //...
35- * };
36- *
37- * export const handler = middy(lambdaHandler)
38- * .use(makeHandlerIdempotent({ persistenceStore: dynamoDBPersistenceLayer }));
91+ * export const handler = middy(
92+ * async (_event: unknown, _context: unknown): Promise<void> => {
93+ * // your code goes here
94+ * }
95+ * ).use(makeHandlerIdempotent({ persistenceStore: dynamoDBPersistenceLayer }));
3996 * ```
4097 *
4198 * @param options - Options for the idempotency middleware
4299 */
43100const makeHandlerIdempotent = (
44101 options : IdempotencyLambdaHandlerOptions
45102) : MiddlewareLikeObj => {
46- const idempotencyConfig = options . config
47- ? options . config
48- : new IdempotencyConfig ( { } ) ;
49- const persistenceStore = options . persistenceStore ;
50- persistenceStore . configure ( {
51- config : idempotencyConfig ,
52- } ) ;
53-
54- // keep the flag for after and onError checks
55- let shouldSkipIdempotency = false ;
56-
57103 /**
58104 * Function called before the handler is executed.
59105 *
@@ -76,18 +122,34 @@ const makeHandlerIdempotent = (
76122 request : MiddyLikeRequest ,
77123 retryNo = 0
78124 ) : Promise < unknown | void > => {
125+ const idempotencyConfig = options . config
126+ ? options . config
127+ : new IdempotencyConfig ( { } ) ;
128+ const persistenceStore = options . persistenceStore ;
129+ persistenceStore . configure ( {
130+ config : idempotencyConfig ,
131+ } ) ;
132+
79133 if (
134+ ! idempotencyConfig . isEnabled ( ) ||
80135 IdempotencyHandler . shouldSkipIdempotency (
81136 idempotencyConfig . eventKeyJmesPath ,
82137 idempotencyConfig . throwOnNoIdempotencyKey ,
83138 request . event as JSONValue
84139 )
85140 ) {
86141 // set the flag to skip checks in after and onError
87- shouldSkipIdempotency = true ;
142+ setIdempotencySkipFlag ( request ) ;
88143
89144 return ;
90145 }
146+
147+ /**
148+ * Store the persistence store in the request internal so that it can be
149+ * used in after and onError
150+ */
151+ setPersistenceStoreInRequestInternal ( request , persistenceStore ) ;
152+
91153 try {
92154 await persistenceStore . saveInProgress (
93155 request . event as JSONValue ,
@@ -129,6 +191,7 @@ const makeHandlerIdempotent = (
129191 }
130192 }
131193 } ;
194+
132195 /**
133196 * Function called after the handler has executed successfully.
134197 *
@@ -139,9 +202,10 @@ const makeHandlerIdempotent = (
139202 * @param request - The Middy request object
140203 */
141204 const after = async ( request : MiddyLikeRequest ) : Promise < void > => {
142- if ( shouldSkipIdempotency ) {
205+ if ( shouldSkipIdempotency ( request ) ) {
143206 return ;
144207 }
208+ const persistenceStore = getPersistenceStoreFromRequestInternal ( request ) ;
145209 try {
146210 await persistenceStore . saveSuccess (
147211 request . event as JSONValue ,
@@ -164,9 +228,10 @@ const makeHandlerIdempotent = (
164228 * @param request - The Middy request object
165229 */
166230 const onError = async ( request : MiddyLikeRequest ) : Promise < void > => {
167- if ( shouldSkipIdempotency ) {
231+ if ( shouldSkipIdempotency ( request ) ) {
168232 return ;
169233 }
234+ const persistenceStore = getPersistenceStoreFromRequestInternal ( request ) ;
170235 try {
171236 await persistenceStore . deleteRecord ( request . event as JSONValue ) ;
172237 } catch ( error ) {
@@ -177,19 +242,11 @@ const makeHandlerIdempotent = (
177242 }
178243 } ;
179244
180- if ( idempotencyConfig . isEnabled ( ) ) {
181- return {
182- before,
183- after,
184- onError,
185- } ;
186- } else {
187- return {
188- before : ( ) => {
189- return undefined ;
190- } ,
191- } ;
192- }
245+ return {
246+ before,
247+ after,
248+ onError,
249+ } ;
193250} ;
194251
195252export { makeHandlerIdempotent } ;
0 commit comments