I have an existing table in dynamodb created with the following command
aws dynamodb create-table \
--region us-east-1 \
--table-name notifications \
--attribute-definitions AttributeName=CustomerId,AttributeType=S AttributeName=Timestamp,AttributeType=N AttributeName=MessageId,AttributeType=S \
--key-schema AttributeName=CustomerId,KeyType=HASH AttributeName=Timestamp,KeyType=RANGE \
--provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
--global-secondary-indexes '[
{
"IndexName": "MessageId",
"KeySchema": [
{
"AttributeName": "MessageId",
"KeyType": "HASH"
}
],
"Projection": {
"ProjectionType": "ALL"
},
"ProvisionedThroughput": {
"ReadCapacityUnits": 5,
"WriteCapacityUnits": 5
}
}
]'
}
And i want to put an API wrapper in front of it that allows me to get all records from the table provided a CustomerId
, so I am attempting to use query from the v2 GO SDK
// GET /notifications/
func (api NotificationsApi) getNotifications(w http.ResponseWriter, r *http.Request) {
var err error
customerId := r.URL.Query().Get("customerId")
if customerId == "" {
api.errorResponse(w, "customerId query parameter required", http.StatusBadRequest)
return
}
span, ctx := tracer.StartSpanFromContext(r.Context(), "notification.get")
defer span.Finish(tracer.WithError(err))
keyCond := expression.Key("CustomerId").Equal(expression.Value(":val"))
expr, err := expression.NewBuilder().WithKeyCondition(keyCond).Build()
input := &dynamodb.QueryInput{
TableName: aws.String("notifications"),
KeyConditionExpression: expr.KeyCondition(),
ExpressionAttributeValues: map[string]dynamodbTypes.AttributeValue{
":val": &dynamodbTypes.AttributeValueMemberS{Value: customerId},
},
}
fmt.Println(*expr.KeyCondition())
output, err := api.dynamoClient.Query(ctx, input)
fmt.Println(output)
fmt.Println(err)
}
However, I am getting a 400 from dynamodb
operation error DynamoDB: Query, https response error StatusCode: 400, RequestID: *****, api error ValidationException: Invalid KeyConditionExpression: An expression attribute name used in the document path is not defined; attribute name: #0
The output from fmt.PrintLn(*expr.KeyCondition())
is #0 = :0
Running this query locally returns my expected result
awslocal dynamodb query \
--table-name notifications \
--key-condition-expression "CustomerId = :val" \
--expression-attribute-values '{":val":{"S":"localTesting"}}'
I have tried including the timestamp as well, but dont think that would be required since my terminal command without it works. I dont think im dereferencing improperly. I know my dynamo session is valid because i can POST to my wrapper and see updates via the terminal command.
Here's an example of a Query which you can use as a template:
// TableBasics encapsulates the Amazon DynamoDB service actions used in the examples.
// It contains a DynamoDB service client that is used to act on the specified table.
type TableBasics struct {
DynamoDbClient *dynamodb.Client
TableName string
}
// Query gets all movies in the DynamoDB table that were released in the specified year.
// The function uses the `expression` package to build the key condition expression
// that is used in the query.
func (basics TableBasics) Query(releaseYear int) ([]Movie, error) {
var err error
var response *dynamodb.QueryOutput
var movies []Movie
keyEx := expression.Key("year").Equal(expression.Value(releaseYear))
expr, err := expression.NewBuilder().WithKeyCondition(keyEx).Build()
if err != nil {
log.Printf("Couldn't build expression for query. Here's why: %v\n", err)
} else {
response, err = basics.DynamoDbClient.Query(context.TODO(), &dynamodb.QueryInput{
TableName: aws.String(basics.TableName),
ExpressionAttributeNames: expr.Names(),
ExpressionAttributeValues: expr.Values(),
KeyConditionExpression: expr.KeyCondition(),
})
if err != nil {
log.Printf("Couldn't query for movies released in %v. Here's why: %v\n", releaseYear, err)
} else {
err = attributevalue.UnmarshalListOfMaps(response.Items, &movies)
if err != nil {
log.Printf("Couldn't unmarshal query response. Here's why: %v\n", err)
}
}
}
return movies, err
}
You can see more GoV2 examples here