1212import java .util .regex .Pattern ;
1313
1414import com .amazonaws .services .lambda .runtime .Context ;
15- import com .amazonaws .services .lambda .runtime .events .APIGatewayProxyRequestEvent ;
16- import com .amazonaws .services .lambda .runtime .events .APIGatewayProxyResponseEvent ;
15+ import com .amazonaws .services .lambda .runtime .events .SQSEvent ;
1716import com .fasterxml .jackson .annotation .JsonProperty ;
1817import com .fasterxml .jackson .core .JsonProcessingException ;
1918import com .fasterxml .jackson .databind .JsonNode ;
3635import software .amazon .awssdk .services .eventbridge .EventBridgeAsyncClient ;
3736import software .amazon .awssdk .services .eventbridge .model .PutEventsRequest ;
3837import software .amazon .awssdk .services .eventbridge .model .PutEventsRequestEntry ;
39- import software .amazon .lambda .powertools .logging .CorrelationIdPathConstants ;
4038import software .amazon .lambda .powertools .logging .Logging ;
4139import software .amazon .lambda .powertools .metrics .Metrics ;
4240import software .amazon .lambda .powertools .tracing .Tracing ;
@@ -49,7 +47,6 @@ public class RequestApprovalFunction {
4947 private static final Logger logger = LogManager .getLogger (RequestApprovalFunction .class );
5048 private static final Set <String > NO_ACTION_STATUSES = new HashSet <>(Arrays .asList ("APPROVED" ));
5149 private static final String PROPERTY_ID_PATTERN = "[a-z-]+\\ /[a-z-]+\\ /[a-z][a-z0-9-]*\\ /[0-9-]+" ;
52- private static final String CONTENT_TYPE = "application/json" ;
5350
5451 private final Pattern propertyIdPattern = Pattern .compile (PROPERTY_ID_PATTERN );
5552 private final String tableName = System .getenv ("DYNAMODB_TABLE" );
@@ -60,6 +57,7 @@ public class RequestApprovalFunction {
6057 private final ObjectMapper objectMapper = new ObjectMapper ();
6158
6259 public RequestApprovalFunction () {
60+
6361 DynamoDbAsyncClient dynamodbClient = DynamoDbAsyncClient .builder ()
6462 .httpClientBuilder (NettyNioAsyncHttpClient .builder ())
6563 .build ();
@@ -76,72 +74,74 @@ public RequestApprovalFunction() {
7674
7775 @ Tracing
7876 @ Metrics (captureColdStart = true )
79- @ Logging (logEvent = true , correlationIdPath = CorrelationIdPathConstants .API_GATEWAY_REST )
80- public APIGatewayProxyResponseEvent handleRequest (final APIGatewayProxyRequestEvent input ,
81- final Context context ) {
82- try {
83- if (input .getBody () == null || input .getBody ().trim ().isEmpty ()) {
84- return createErrorResponse (400 , "Request body is required" );
85- }
86-
87- JsonNode rootNode = objectMapper .readTree (input .getBody ());
88- JsonNode propertyIdNode = rootNode .get ("property_id" );
89-
90- if (propertyIdNode == null ) {
91- return createErrorResponse (400 , "property_id field is required" );
92- }
77+ @ Logging (logEvent = true )
78+ public void handleRequest (final SQSEvent input , final Context context ) {
79+ logger .info ("Environment variables - DYNAMODB_TABLE: {}, EVENT_BUS: {}" , tableName , eventBus );
80+ logger .info ("Starting approval request processing for {} messages" , input .getRecords ().size ());
9381
94- String propertyId = propertyIdNode .asText ();
95- if (!propertyIdPattern .matcher (propertyId ).matches ()) {
96- return createErrorResponse (400 , "Invalid property_id format. Must match: " + PROPERTY_ID_PATTERN );
97- }
98-
99- PropertyComponents components = parsePropertyId (propertyId );
100- List <Property > properties = queryTable (components .partitionKey , components .sortKey );
101-
102- if (properties .isEmpty ()) {
103- return createErrorResponse (404 , "Property not found" );
104- }
105-
106- Property property = properties .get (0 );
107- if (NO_ACTION_STATUSES .contains (property .getStatus ())) {
108- return createSuccessResponse ("Property is already " + property .getStatus () + "; no action taken" );
82+
83+ for (SQSEvent .SQSMessage message : input .getRecords ()) {
84+ try {
85+ String body = message .getBody ();
86+ logger .info ("Processing SQS message: {}" , body );
87+
88+ if (body == null || body .trim ().isEmpty ()) {
89+ logger .warn ("Message body is null or empty" );
90+ continue ;
91+ }
92+
93+ JsonNode rootNode = objectMapper .readTree (body );
94+ JsonNode propertyIdNode = rootNode .get ("property_id" );
95+
96+ if (propertyIdNode == null ) {
97+ logger .warn ("property_id field missing from message" );
98+ continue ;
99+ }
100+
101+ String propertyId = propertyIdNode .asText ();
102+ logger .info ("Processing approval request for property: {}" , propertyId );
103+
104+ if (!propertyIdPattern .matcher (propertyId ).matches ()) {
105+ logger .warn ("Invalid property_id format: {}" , propertyId );
106+ continue ;
107+ }
108+
109+ PropertyComponents components = parsePropertyId (propertyId );
110+ logger .info ("Parsed property ID components: {}" , components );
111+ List <Property > properties = queryTable (components .partitionKey , components .sortKey );
112+
113+ if (properties .isEmpty ()) {
114+ logger .warn ("Property not found in database: {}" , propertyId );
115+ continue ;
116+ }
117+
118+ Property property = properties .get (0 );
119+ logger .info ("Found property with status: {}" , property .getStatus ());
120+
121+ if (NO_ACTION_STATUSES .contains (property .getStatus ())) {
122+ logger .info ("Property already approved, no action needed: {}" , propertyId );
123+ continue ;
124+ }
125+
126+ sendEvent (property );
127+ logger .info ("Approval request completed successfully for property: {}" , propertyId );
128+
129+ } catch (JsonProcessingException e ) {
130+ logger .error ("Invalid JSON in message body: {}" , message .getBody (), e );
131+ } catch (Exception e ) {
132+ logger .error ("Error processing approval request for message: {}" , message .getBody (), e );
109133 }
110-
111- sendEvent (property );
112- return createSuccessResponse ("Approval requested successfully" );
113-
114- } catch (JsonProcessingException e ) {
115- logger .error ("Invalid JSON in request body" , e );
116- return createErrorResponse (400 , "Invalid JSON format" );
117- } catch (Exception e ) {
118- logger .error ("Error processing approval request" , e );
119- return createErrorResponse (500 , "Internal server error" );
120134 }
121135 }
122136
123137 private PropertyComponents parsePropertyId (String propertyId ) {
124138 String [] parts = propertyId .split ("/" );
125- String partitionKey = ("search #" + parts [0 ] + "#" + parts [1 ]).replace (' ' , '-' ). toLowerCase ( );
139+ String partitionKey = ("PROPERTY #" + parts [0 ] + "#" + parts [1 ]).replace (' ' , '-' );
126140 String sortKey = (parts [2 ] + "#" + parts [3 ]).replace (' ' , '-' ).toLowerCase ();
127141 return new PropertyComponents (partitionKey , sortKey );
128142 }
129143
130- private APIGatewayProxyResponseEvent createSuccessResponse (String message ) {
131- String body = String .format ("{\" result\" :\" %s\" }" , message );
132- return new APIGatewayProxyResponseEvent ()
133- .withStatusCode (200 )
134- .withHeaders (Map .of ("Content-Type" , CONTENT_TYPE ))
135- .withBody (body );
136- }
137144
138- private APIGatewayProxyResponseEvent createErrorResponse (int statusCode , String message ) {
139- String body = String .format ("{\" error\" :\" %s\" }" , message );
140- return new APIGatewayProxyResponseEvent ()
141- .withStatusCode (statusCode )
142- .withHeaders (Map .of ("Content-Type" , CONTENT_TYPE ))
143- .withBody (body );
144- }
145145
146146 private static class PropertyComponents {
147147 final String partitionKey ;
@@ -154,7 +154,10 @@ private static class PropertyComponents {
154154 }
155155
156156 private List <Property > queryTable (String partitionKey , String sortKey ) throws Exception {
157+ logger .info ("Starting DynamoDB query with partitionKey: {}, sortKey: {}" , partitionKey , sortKey );
158+
157159 if (partitionKey == null || sortKey == null ) {
160+ logger .error ("Null keys provided - partitionKey: {}, sortKey: {}" , partitionKey , sortKey );
158161 throw new IllegalArgumentException ("Partition key and sort key cannot be null" );
159162 }
160163
@@ -166,19 +169,24 @@ private List<Property> queryTable(String partitionKey, String sortKey) throws Ex
166169 .build ();
167170
168171 try {
172+ logger .debug ("Executing DynamoDB query on table: {}" , tableName );
169173 SdkPublisher <Property > properties = propertyTable .query (request ).items ();
170174 CompletableFuture <Void > future = properties .subscribe (result ::add );
171175 future .get ();
176+ logger .info ("DynamoDB query completed successfully, found {} properties" , result .size ());
172177 return result ;
173178 } catch (DynamoDbException | InterruptedException | ExecutionException e ) {
174- logger .error ("Error querying DynamoDB" , e );
179+ logger .error ("Error querying DynamoDB with partitionKey: {}, sortKey: {}, table: {}" ,
180+ partitionKey , sortKey , tableName , e );
175181 throw new Exception ("Database query failed: " + e .getMessage ());
176182 }
177183 }
178184
179185 @ Tracing
180186 @ Metrics
181187 private void sendEvent (Property property ) throws JsonProcessingException {
188+ logger .info ("Creating approval event for property: {}" , property .getId ());
189+
182190 RequestApproval event = new RequestApproval ();
183191 event .setPropertyId (property .getId ());
184192
@@ -189,6 +197,7 @@ private void sendEvent(Property property) throws JsonProcessingException {
189197 event .setAddress (address );
190198
191199 String eventString = objectMapper .writeValueAsString (event );
200+ logger .info ("Event payload created: {}" , eventString );
192201
193202 PutEventsRequestEntry requestEntry = PutEventsRequestEntry .builder ()
194203 .eventBusName (eventBus )
@@ -202,8 +211,15 @@ private void sendEvent(Property property) throws JsonProcessingException {
202211 .entries (requestEntry )
203212 .build ();
204213
205- eventBridgeClient .putEvents (eventsRequest ).join ();
206- logger .info ("Event sent successfully for property: {}" , property .getId ());
214+ logger .debug ("Sending event to EventBridge bus: {}" , eventBus );
215+ try {
216+ eventBridgeClient .putEvents (eventsRequest ).join ();
217+ logger .info ("Event sent successfully for property: {}" , property .getId ());
218+ } catch (Exception e ) {
219+ logger .error ("Failed to send event to EventBridge for property: {}, bus: {}" ,
220+ property .getId (), eventBus , e );
221+ throw e ;
222+ }
207223 }
208224}
209225
0 commit comments