skip to Main Content

thank you in advance for stopping by 🙂

Something weird is going on with my API Gateway – Lambda – DynamoDB combo: I am inserting items using a PutCommand

try {
        return await documentClient.send(new PutCommand({
            TableName: process.env.TABLE_NAME,
            Item: {
                'PK': '#LEADERBOARDS',
                'SK': `LEADERBOARD#${requestBody.leaderboard_id}`,
                'leaderboard_display_name': requestBody.leaderboard_display_name,
                'participant_type': requestBody.participant_type,
                'active_leaderboard': requestBody.active_leaderboard,
                'tournaments': requestBody.tournaments,
                'associated_tournaments': new Set(requestBody.associated_tournaments)
            },
            ConditionExpression: 'attribute_not_exists(PK) AND attribute_not_exists(SK)',
            ReturnConsumedCapacity: 'TOTAL'
        }))
    } catch (error) {
        return error
    }

Everything works as expected, except for the number set ‘associated_tournaments’, which when I try to retrieve via a GetCommand:

try {
        return await documentClient.send(new GetCommand({
            TableName: process.env.TABLE_NAME,
            Key: {
                'PK': '#LEADERBOARDS',
                'SK': `LEADERBOARD#${leaderboardName}`
            },
            ReturnConsumedCapacity: 'TOTAL'
        }))
    } catch (error) {
        return error
    }

it returns an empty object ‘{}’ to the caller (using curl, or postman), however from the Dynamo UI and by querying via the CLI I can see the data is actually present in the attribute and item.

This is the CLI command I’m using:

aws dynamodb get-item   --table-name STGLeaderboards   --key '{"PK": {"S": "#LEADERBOARDS"}, "SK": {"S": "LEADERBOARD#LeaderboardPM"}}'  --return-consumed-capacity TOTAL --profile qlash --region eu-central-1

which returns the numbers in the set.

The curl command hitting the API Gateway endpoint:

curl 'https://api.stg.tournaments.qlash.gg/admin/leaderboard/LeaderboardPM'

which triggers the GetCommand I shared above via this handler:

export const handler = async (event) => {

    switch (event.routeKey) {
        case 'POST /admin/leaderboard':
            return await createLeaderboard(JSON.parse(event.body))
        case 'GET /admin/leaderboards':
            return await getLeaderboards()
        case 'GET /admin/leaderboard/{leaderboard_name}':
            return await getLeaderboard(event.pathParameters.leaderboard_name)
        case 'PATCH /admin/leaderboard/{leaderboard_name}':
            return await updateLeaderboard(event.pathParameters.leaderboard_name, JSON.parse(event.body))
        case 'DELETE /admin/leaderboard/{leaderboard_name}':
            return await deleteLeaderboard(event.pathParameters.leaderboard_name)
        default:
            return {
                statusCode: 404,
                body: JSON.stringify({'message': 'No matching path'}),
            }
    }
}

Here is the output of the curl command:

{
    "$metadata": {
        "httpStatusCode": 200,
        "requestId": "CDDA7KIQSDR7JE4PA06S6AB3HNVV4KQNSO5AEMVJF66Q9ASUAAJG",
        "attempts": 1,
        "totalRetryDelay": 0
    },
    "ConsumedCapacity": {
        "CapacityUnits": 0.5,
        "TableName": "STGLeaderboards"
    },
    "Item": {
        "SK": "LEADERBOARD#LeaderboardPM",
        "associated_tournaments": {},
        "active_leaderboard": true,
        "leaderboard_display_name": "This Leaderboards is AWESOME",
        "participant_type": "SOLO"
    }
}

as you can see it returns an empty set, but from the dynamodb dashboard I can see two associated tournaments in the form {7121, 7224}

What is going on here? :/ Am I missing something about converting back the Set in some way?

Thank you in advance, and have a nice day!

Ettore

2

Answers


  1. From the information you provided, it seems as though you are using a response mapping template in API Gateway. I suggest either you don’t map the response and let the client retrieve all of the item, or you return the entire item payload, and drop the metadata.

    Login or Signup to reply.
  2. I bumped into the same issue recently. I solved it manipulating the response, converting the set back into an array in the response, and now it is working as expected.

    Here is how you’d do it:
    (for a single item)

    const response = await getItem();
    
                return JSON.stringify({
                    ...response,
                    Item: {
                        ...response.Item,
                        associated_items: [...response.Item.associated_items]
                    }
                });
    

    (and for a scan/query)

    const response = await getLeaderboards();
    
                return JSON.stringify({
                    ...response,
                    Items: response.Items.map(item => ({
                        ...item,
                        associated_tournaments: [...item.associated_tournaments]
                    }))
                })
    

    I know it cloud be a hit in terms of performance for a response with many items, but I don’t know what to say… I think there’s something funky going on with the API Gateway… AWS FIX YOUR **** LMAO

    Jokes aside, hope this helps 🙂

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search