Skip to content

Why is my lambda learner app able to write to dynamodb (POST request), but when retrieving via item_id (GET /todo/{item_id}), it returns 404. Stack: Python, lambda powertools, PynamoDB

0

I am new to the serverless web development world (after spending a few years in the aws sysops/devops world). This todo app is just a learner app to get me comfortable building rest apis with lambda functions. I appreciate any help. Thanks!

Below is 1. The code, 2. The requests send via POSTMAN, 3. The Cloudwatch logs

1. The relevant code snippets.

Ask for missing context in comments if I missed something.

# models.py
from pynamodb.models import Model
from pynamodb.attributes import UnicodeAttribute, BooleanAttribute

class TodoItem(Model):
    class Meta:
        table_name = 'todo_items'
        region = 'eu-central-1'

    item_id = UnicodeAttribute(hash_key=True)
    item_name = UnicodeAttribute()
    item_status = BooleanAttribute(default=False)
# app.py
from aws_lambda_powertools import Logger
from aws_lambda_powertools.event_handler import APIGatewayRestResolver
from models import TodoItem
import uuid

logger = Logger()
app = APIGatewayRestResolver()

@app.get('/todo/{item_id}')
def get_todo_item(item_id):
    logger.info(f'get_todo_item: {item_id}')
    item = TodoItem.get(item_id)
    return item.attribute_values

@app.post('/todo')
def create_todo_item():
    logger.info('create_todo_item')
    item_data = app.current_event.json_body
    logger.info(f"item_name: {item_data['item_name']}")
    item = TodoItem(item_id=str(uuid.uuid4()), item_name=item_data['item_name'])
    item.save()
    return item.attribute_values

def lambda_handler(event, context):
    logger.info(f'event: {event}')
    return app.resolve(event, context)

2. The following two requests were made with POSTMAN.

POST Request to https://lambdaprefix.execute-api.eu-central-1.amazonaws.com/Prod/todo/ 

POST Response: {"item_status":false,"item_id":"c36bfc42-e8fd-4bd0-b246-bb99be9c5487","item_name":"test-todo-item-name yolo"}

I have checked and confirmed that the data was saved to the dynamodb table.

GET Request to https://lambdaprefix.execute-api.eu-central-1.amazonaws.com/Prod/todo/c36bfc42-e8fd-4bd0-b246-bb99be9c5487

GET Response: {"statusCode":404,"message":"Not found"}

The request returns a 404 when requesting with the exact item_id returned by the POST response / saved in the DB

3. The logs

LOG1:


Code:
def lambda_handler(event, context):
    logger.info(f'event: {event}')
    return app.resolve(event, context)

Log:
{
    "level": "INFO",
    "location": "lambda_handler:53",
    "message": "event: {'resource': '/todo/{id}', 'path': '/todo/c36bfc42-e8fd-4bd0-b246-bb99be9c5487', 'httpMethod': 'GET', 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate, br', 'CloudFront-Forwarded-Proto': 'https', 'CloudFront-Is-Desktop-Viewer': 'true', 'CloudFront-Is-Mobile-Viewer': 'false', 'CloudFront-Is-SmartTV-Viewer': 'false', 'CloudFront-Is-Tablet-Viewer': 'false', 'CloudFront-Viewer-ASN': '9009', 'CloudFront-Viewer-Country': 'AT', 'Host': 'lambdaprefix.execute-api.eu-central-1.amazonaws.com', 'Postman-Token': 'ef43b28b-eb20-4feb-9503-9c3ca4ae3b5c', 'User-Agent': 'PostmanRuntime/7.32.2', 'Via': '1.1 e77ae8cfd42b65dd9027fa08596c6f2a.cloudfront.net (CloudFront)', 'X-Amz-Cf-Id': 'DRtAi5i4sBEkeK4xZDPy_S_5bbBfi9J7dACytDCIRK9oi00IDchRbQ==', 'X-Amzn-Trace-Id': 'Root=1-6495c1af-505c7a9f36e4b0d6011af833', 'X-Forwarded-For': '146.70.116.141, 130.176.38.185', 'X-Forwarded-Port': '443', 'X-Forwarded-Proto': 'https'}, 'multiValueHeaders': {'Accept': ['*/*'], 'Accept-Encoding': ['gzip, deflate, br'], 'CloudFront-Forwarded-Proto': ['https'], 'CloudFront-Is-Desktop-Viewer': ['true'], 'CloudFront-Is-Mobile-Viewer': ['false'], 'CloudFront-Is-SmartTV-Viewer': ['false'], 'CloudFront-Is-Tablet-Viewer': ['false'], 'CloudFront-Viewer-ASN': ['9009'], 'CloudFront-Viewer-Country': ['AT'], 'Host': ['lambdaprefix.execute-api.eu-central-1.amazonaws.com'], 'Postman-Token': ['ef43b28b-eb20-4feb-9503-9c3ca4ae3b5c'], 'User-Agent': ['PostmanRuntime/7.32.2'], 'Via': ['1.1 e77ae8cfd42b65dd9027fa08596c6f2a.cloudfront.net (CloudFront)'], 'X-Amz-Cf-Id': ['DRtAi5i4sBEkeK4xZDPy_S_5bbBfi9J7dACytDCIRK9oi00IDchRbQ=='], 'X-Amzn-Trace-Id': ['Root=1-6495c1af-505c7a9f36e4b0d6011af833'], 'X-Forwarded-For': ['146.70.116.141, 130.176.38.185'], 'X-Forwarded-Port': ['443'], 'X-Forwarded-Proto': ['https']}, 'queryStringParameters': None, 'multiValueQueryStringParameters': None, 'pathParameters': {'id': 'c36bfc42-e8fd-4bd0-b246-bb99be9c5487'}, 'stageVariables': None, 'requestContext': {'resourceId': 'p8pwqo', 'resourcePath': '/todo/{id}', 'httpMethod': 'GET', 'extendedRequestId': 'G-szfGo6FiAFsAw=', 'requestTime': '23/Jun/2023:16:00:47 +0000', 'path': '/Prod/todo/c36bfc42-e8fd-4bd0-b246-bb99be9c5487', 'accountId': '216411484155', 'protocol': 'HTTP/1.1', 'stage': 'Prod', 'domainPrefix': 'lambdaprefix', 'requestTimeEpoch': 1687536047656, 'requestId': '33bafab2-0823-405c-819b-16bdb84bd773', 'identity': {'cognitoIdentityPoolId': None, 'accountId': None, 'cognitoIdentityId': None, 'caller': None, 'sourceIp': '146.70.116.141', 'principalOrgId': None, 'accessKey': None, 'cognitoAuthenticationType': None, 'cognitoAuthenticationProvider': None, 'userArn': None, 'userAgent': 'PostmanRuntime/7.32.2', 'user': None}, 'domainName': 'lambdaprefix.execute-api.eu-central-1.amazonaws.com', 'apiId': 'lambdaprefix'}, 'body': None, 'isBase64Encoded': False}",
    "timestamp": "2023-06-23 16:00:48,540+0000",
    "service": "service_undefined",
    "xray_trace_id": "1-6495c1af-505c7a9f36e4b0d6011af833"
}

LOG2:


Code:
@app.get('/todo/{item_id}')
def get_todo_item(item_id):
    logger.info(f'get_todo_item: {item_id}')
    item = TodoItem.get(item_id)
    return item.attribute_values

Logs:
NOTHING! The function doesn't ever get called even though the event data logged previously shows this:

event: {'resource': '/todo/{id}', 'path': '/todo/c36bfc42-e8fd-4bd0-b246-bb99be9c5487', 'httpMethod': 'GET',

1 Answer
0
Accepted Answer

Hi,

according to the documentation (https://docs.powertools.aws.dev/lambda/python/latest/core/event_handler/api_gateway/#dynamic-routes), the correct syntax for the dynamic route should be @app.get("/todos/<item_id>") instead of @app.get("/todos/{item_id}").

Please upvote/accept this answer if it was helpful. Thanks

AWS
EXPERT
answered 3 years ago
AWS
EXPERT
reviewed 3 years ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.