1
- import os
2
1
import logging
2
+ import os
3
+
3
4
import boto3
4
5
from fastapi import FastAPI , HTTPException
5
6
from fastapi .middleware .cors import CORSMiddleware
6
7
from mangum import Mangum
7
-
8
8
from pydantic import BaseModel
9
9
from typing import List , Dict
10
10
11
+ # Configure logging
11
12
logging .basicConfig (level = logging .DEBUG )
12
13
14
+ # Initialize FastAPI application
13
15
app = FastAPI ()
14
16
15
- # Enable CORS
17
+ # Configure CORS middleware
16
18
app .add_middleware (
17
19
CORSMiddleware ,
18
- allow_origins = ["*" ], # Adjust this as needed for your use case
20
+ allow_origins = ["*" ], # Adjust the allowed origins for your use case
19
21
allow_credentials = True ,
20
22
allow_methods = ["*" ],
21
23
allow_headers = ["*" ],
22
24
)
23
25
24
26
# Connect to DynamoDB
25
- dynamodb = boto3 .resource (' dynamodb' , region_name = ' us-east-1' )
27
+ dynamodb = boto3 .resource (" dynamodb" , region_name = " us-east-1" )
26
28
table = dynamodb .Table ("todo-dev" )
27
29
28
- @app .get ("/todos" , response_model = List [dict ])
30
+
31
+ # Define a Pydantic model for a todo item
32
+ class TodoItem (BaseModel ):
33
+ id : str
34
+ text : str
35
+ timestamp : int
36
+
37
+
38
+ @app .get ("/todos" , response_model = List [TodoItem ])
29
39
async def get_todos ():
30
40
try :
31
41
# Perform a scan operation on the DynamoDB table
32
42
response = table .scan ()
33
- # Return the 'Items' from the scan result, which contains the table data
34
- return response .get ('Items' , [])
43
+ # Return the 'Items' from the scan result
44
+ items = response .get ("Items" , [])
45
+ logging .debug (f"Fetched { len (items )} items from DynamoDB" )
46
+ return items
35
47
except Exception as e :
36
48
logging .error (f"Error getting todos: { e } " )
37
- raise HTTPException (status_code = 500 , detail = str (e ))
38
-
39
- # POST request to create a new todo
40
- @app .post ("/todos" , status_code = 201 )
41
- async def create_todo (todo : Dict ):
42
- if not todo :
43
- raise HTTPException (status_code = 400 , detail = "Invalid input" )
49
+ raise HTTPException (status_code = 500 , detail = "Error fetching todos" )
44
50
45
- # Ensure 'id' is present in the todo item, or else raise an error
46
- if 'id' not in todo :
47
- raise HTTPException (status_code = 400 , detail = "Missing 'id' in request body" )
48
51
52
+ @app .post ("/todos" , status_code = 201 , response_model = TodoItem )
53
+ async def create_todo (todo : TodoItem ):
49
54
try :
50
55
# Add the todo item to DynamoDB
51
- table .put_item (Item = todo )
52
- return todo # Return the created todo item
53
-
56
+ response = table .put_item (Item = todo .dict ())
57
+ logging .debug (f"DynamoDB put_item response: { response } " )
58
+ return todo
59
+ except boto3 .exceptions .Boto3Error as boto_error :
60
+ logging .error (f"Boto3Error: { boto_error } " )
61
+ raise HTTPException (status_code = 500 , detail = f"DynamoDB Error: { str (boto_error )} " )
54
62
except Exception as e :
55
- logging .error (f"Error creating todo: { e } " )
56
- raise HTTPException (status_code = 500 , detail = "Internal server error" )
57
-
58
- # PUT request to update an existing todo
59
- @app .put ("/todos/{id}" )
60
- async def update_todo (id : str , todo : Dict ):
61
- # Validate that 'text' is in the request body
62
- if 'text' not in todo :
63
+ logging .error (f"Unexpected error creating todo: { e } " )
64
+ raise HTTPException (status_code = 500 , detail = "Error creating todo" )
65
+
66
+
67
+ @app .put ("/todos/{id}" , response_model = TodoItem )
68
+ async def update_todo (id : str , todo : Dict [str , str ]):
69
+ if "text" not in todo :
63
70
raise HTTPException (status_code = 400 , detail = "Missing 'text' in request body" )
64
71
65
72
try :
66
- # Update the todo item in DynamoDB based on the 'id'
73
+ # Update the todo item in DynamoDB
67
74
response = table .update_item (
68
- Key = {'id' : id },
69
- UpdateExpression = ' SET #t = :t' ,
70
- ExpressionAttributeNames = {'#t' : ' text' },
71
- ExpressionAttributeValues = {':t' : todo [' text' ]},
72
- ReturnValues = "ALL_NEW" # Return the updated item
75
+ Key = {"id" : id },
76
+ UpdateExpression = " SET #t = :t" ,
77
+ ExpressionAttributeNames = {"#t" : " text" },
78
+ ExpressionAttributeValues = {":t" : todo [" text" ]},
79
+ ReturnValues = "ALL_NEW"
73
80
)
74
-
75
- # Check if the item was updated and return the updated todo
76
- updated_todo = response .get ('Attributes' )
81
+ updated_todo = response .get ("Attributes" )
77
82
if not updated_todo :
78
83
raise HTTPException (status_code = 404 , detail = "Todo not found" )
79
-
80
84
return updated_todo
81
-
82
85
except Exception as e :
83
86
logging .error (f"Error updating todo: { e } " )
84
- raise HTTPException (status_code = 500 , detail = "Internal server error" )
87
+ raise HTTPException (status_code = 500 , detail = "Error updating todo" )
88
+
85
89
86
- # DELETE request to delete a todo
87
90
@app .delete ("/todos/{id}" , status_code = 204 )
88
91
async def delete_todo (id : str ):
89
92
try :
90
- # Attempt to delete the todo item from DynamoDB
91
- response = table .delete_item (Key = {'id' : id })
92
-
93
- # Check if the item exists based on the HTTP status code
94
- if response .get ('ResponseMetadata' , {}).get ('HTTPStatusCode' ) != 200 :
93
+ # Delete the todo item from DynamoDB
94
+ response = table .delete_item (Key = {"id" : id })
95
+ if response .get ("ResponseMetadata" , {}).get ("HTTPStatusCode" ) != 200 :
95
96
raise HTTPException (status_code = 404 , detail = "Todo not found" )
96
-
97
- return {"detail" : "Todo deleted successfully" } # Confirm deletion
98
-
97
+ return {"detail" : "Todo deleted successfully" }
99
98
except Exception as e :
100
99
logging .error (f"Error deleting todo: { e } " )
101
- raise HTTPException (status_code = 500 , detail = "Internal server error" )
100
+ raise HTTPException (status_code = 500 , detail = "Error deleting todo" )
101
+
102
+
102
103
@app .get ("/health" )
103
104
async def health ():
104
105
try :
105
106
return {"message" : "Everything looks good!" }
106
107
except Exception as e :
107
108
logging .error (f"Health check error: { e } " )
108
- raise HTTPException (status_code = 500 , detail = str (e ))
109
+ raise HTTPException (status_code = 500 , detail = "Error performing health check" )
110
+
109
111
110
112
# Define the Lambda handler function
111
113
def handler (event , context ):
112
- """ Entry point for AWS Lambda """
113
114
logging .info (f"Received event: { event } " )
114
115
mangum_handler = Mangum (app )
115
116
return mangum_handler (event , context )
0 commit comments