
If you send a GET request using this URL: https://{{apiId}}.execute-api.us-east-1.amazonaws.com/dev/groups?limit=2 you should get a reply like this:
{
"items": [
...
],
"nextKey": "%7B%22id%22%3A%221%22%7D"
}
Notice that you need to replace {{apiId}} with an id of the API that you've deployed.
If you pass the nextKey and use it with another GET request using this URL: https://{{apiId}}.execute-api.us-east-1.amazonaws.com/dev/groups?limit=2&nextKey=%7B%22id%22%3A%221%22%7D
{
"items": [
...
],
"nextKey": null
}
If nextKey is null it means that there are no more items to return.

Notice that the value of the LastEvaluatedKey in a DynamoDB result is a JSON object. To pass it in another GET request we convert it to a string and then use URI encoding to allow to pass it in a URL:
encodeURIComponent(JSON.stringify(lastEvaluatedKey))
To pass a value coming in a GET request you would need to first decode a string and then parse a JSON string:
// Value read from a query parameter
const nextKeyStr = ...
// "exclusiveStartKey" can be passed a parameter to a "scan()" call
const exclusiveStartKey = JSON.parse(decodeURIComponent(nextKeyStr))
'use strict'
const AWS = require('aws-sdk')
const docClient = new AWS.DynamoDB.DocumentClient()
const groupsTable = process.env.GROUPS_TABLE
exports.handler = async (event) => {
console.log('Processing event: ', event)
let nextKey // Next key to continue scan operation if necessary
let limit // Maximum number of elements to return
try {
// Parse query parameters
nextKey = parseNextKeyParameter(event)
limit = parseLimitParameter(event) || 20
} catch (e) {
console.log('Failed to parse query parameters: ', e.message)
return {
statusCode: 400,
headers: {
'Access-Control-Allow-Origin': '*'
},
body: JSON.stringify({
error: 'Invalid parameters'
})
}
}
// Scan operation parameters
const scanParams = {
TableName: groupsTable,
Limit: limit,
ExclusiveStartKey: nextKey
}
console.log('Scan params: ', scanParams)
const result = await docClient.scan(scanParams).promise()
const items = result.Items
console.log('Result: ', result)
// Return result
return {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*'
},
body: JSON.stringify({
items,
// Encode the JSON object so a client can return it in a URL as is
nextKey: encodeNextKey(result.LastEvaluatedKey)
})
}
}
/**
* Get value of the limit parameter.
*
* @param {Object} event HTTP event passed to a Lambda function
*
* @returns {number} parsed "limit" parameter
*/
function parseLimitParameter(event) {
const limitStr = getQueryParameter(event, 'limit')
if (!limitStr) {
return undefined
}
const limit = parseInt(limitStr, 10)
if (limit <= 0) {
throw new Error('Limit should be positive')
}
return limit
}
/**
* Get value of the limit parameter.
*
* @param {Object} event HTTP event passed to a Lambda function
*
* @returns {Object} parsed "nextKey" parameter
*/
function parseNextKeyParameter(event) {
const nextKeyStr = getQueryParameter(event, 'nextKey')
if (!nextKeyStr) {
return undefined
}
const uriDecoded = decodeURIComponent(nextKeyStr)
return JSON.parse(uriDecoded)
}
/**
* Get a query parameter or return "undefined"
*
* @param {Object} event HTTP event passed to a Lambda function
* @param {string} name a name of a query parameter to return
*
* @returns {string} a value of a query parameter value or "undefined" if a parameter is not defined
*/
function getQueryParameter(event, name) {
const queryParams = event.queryStringParameters
if (!queryParams) {
return undefined
}
return queryParams[name]
}
/**
* Encode last evaluated key using
*
* @param {Object} lastEvaluatedKey a JS object that represents last evaluated key
*
* @return {string} URI encoded last evaluated key
*/
function encodeNextKey(lastEvaluatedKey) {
if (!lastEvaluatedKey) {
return null
}
return encodeURIComponent(JSON.stringify(lastEvaluatedKey))
}