How do I generate ID automatically when I use AppSync and DynamoDB as the database source?
I have a type looking like below
type Post {
id: ID!
creator: String!
createdAt: String!
like: Int!
dislike: Int!
frozen: Boolean!
}
and input looking like below
input CreatePostInput {
id: ID!
creator: String!
createdAt: String!
like: Int!
dislike: Int!
frozen: Boolean!
}
and my mutation is obviously the combination of the two
createPost(input: CreatePostInput!): Post
However, when I make inserts I have to do something like below
mutation createPost{
createPost(input:{
id:2
creator:"some creator"
createdAt:"some date"
like:0
dislike:0
frozen:false
}){
id
creator
createdAt
like
dislike
frozen
}
}
There is no way I can insert a post without having to know what the id is up to right now. Is there a way I can provide null or any random id and DynamoDB or AppSync automatically create the next index before inserting into the table?
Error generated when I update the input CreatePostInput to not
accept any ID
{
"data": {
"createPost": null
},
"errors": [
{
"path": [
"createPost"
],
"data": null,
"errorType": "DynamoDB:AmazonDynamoDBException",
"errorInfo": null,
"locations": [
{
"line": 2,
"column": 3,
"sourceName": null
}
],
"message": "One or more parameter values were invalid: Type mismatch for key id expected: S actual: NULL (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ValidationException; Request ID: 629QEM7MH9BRAJ9MHU3FM1S0U3VV4KQNSO5AEMVJF66Q9ASUAAJG)"
}
]
}
My Resolver Template
{
"version" : "2017-02-28",
"operation" : "PutItem",
"key" : {
## If object "id" should come from GraphQL arguments, change to $util.dynamodb.toDynamoDBJson($ctx.args.id)
"id": $util.dynamodb.toDynamoDBJson($util.autoId()),
},
"attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args)
}
First, update the createPost resolver as:
{
"version": "2017-02-28",
"operation": "PutItem",
"key": {
"id": $util.dynamodb.toDynamoDBJson($util.autoId()),
},
"attributeValues": $util.dynamodb.toMapValuesJson($ctx.args.input),
"condition": {
"expression": "attribute_not_exists(#id)",
"expressionNames": {
"#id": "id",
},
},
}
Then, remove the id field from your CreatePostInput input type:
input CreatePostInput {
creator: String!
createdAt: String!
like: Int!
dislike: Int!
frozen: Boolean!
}
Save both the changes and you should be done.
If you're the one of seeing-is-believing guys like me, take a look at this egghead.io video.
You can auto generate a UUIDv4 using the $util.autoId() velocity helper function. For example, you can write a createPost resolver that uses a server-side generated id like this.
{
"version" : "2017-02-28",
"operation" : "PutItem",
"key" : {
"id": $util.dynamodb.toDynamoDBJson($util.autoId()),
},
"attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args)
}
Related
I get the exception ValidationException: One of the required keys was not given a value
when I click on the Play button as instructed in an AWS workshop page. Any advice would be really helpful!
AppSync Mock endpoint is running at http://192.168.20.3:20002
Error while executing Local DynamoDB
{
"version": "2018-05-29",
"operation": "PutItem",
"attributeValues": {
"type": {
"S": "post"
},
"content": {
"S": "test"
},
"timestamp": {
"N": "1668425585"
},
"owner": {
"S": "7d8ca528-4931-4254-9273-ea5ee853f271::user1"
},
"__typename": {
"S": "Post"
}
},
"condition": {
"expression": "attribute_not_exists(#id)",
"expressionNames": {
"#id": "id"
}
},
"key": {}
}
ValidationException: One of the required keys was not given a value
Schema file
input AMPLIFY {
globalAuthRule: AuthRule = { allow: public }
} # FOR TESTING ONLY!
type Post
#model(
mutations: { create: "createPost", delete: "deletePost", update: null }
timestamps: null
subscriptions: { level: public }
)
#auth(
rules: [
{
allow: owner
ownerField: "owner"
provider: userPools
operations: [read, create, delete]
}
{ allow: private, provider: userPools, operations: [read] }
]
) {
type: String! # always set to 'post'. used in the SortByTimestamp GSI
id: ID!
content: String!
owner: String
timestamp: Int!
}
(I tried adding and removing the exclamation to the ID here)
Screenshot
I am new to AppSync and DynamoDB, sorry if this question is basic. I have an AppSync Resolver for this schema:
type Profile {
name: String!
location: String!
}
input ProfileInput {
name: String!
location: String!
}
type Mutation {
createProfile(profileInput: ProfileInput!): Profile! #aws_cognito_user_pools #aws_api_key
}
The resolvers are:
Request
{
"version" : "2017-02-28",
"operation" : "UpdateItem",
"key" : {
"name" : $util.dynamodb.toDynamoDBJson($ctx.identity.username),
"attribute": $util.dynamodb.toDynamoDBJson("info")
},
"update" : {
"expression" : "SET #p :da",
"expressionNames" : {
"#p" : "data"
},
"expressionValues" : {
":da" : $util.dynamodb.toDynamoDBJson($ctx.args.profileInput)
}
}
}
Response
$util.toJson($ctx.result)
The Request I am sending to Appsync :
mutation CreateProfileMutation {
createProfile(profileInput: {location: "Updated Location", name: "Updated Username"}) {
location
name
}
}
But Dynamodb is throwing this error:
{
"data": null,
"errors": [
{
"path": [
"createProfile"
],
"data": null,
"errorType": "DynamoDB:DynamoDbException",
"errorInfo": null,
"locations": [
{
"line": 12,
"column": 3,
"sourceName": null
}
],
"message": "Invalid UpdateExpression: Syntax error; token: \":da\", near: \"#p :da\" (Service: DynamoDb, Status Code: 400, Request ID: some id, Extended Request ID: null)"
}
]
}
The transformed template is:
{
"version" : "2017-02-28",
"operation" : "UpdateItem",
"key" : {
"name" : {"S":"user#1"},
"attribute": {"S":"info"}
},
"update" : {
"expression" : "SET #p :da",
"expressionNames" : {
"#p" : "data"
},
"expressionValues" : {
":da" : {"M":{"name":{"S":"Updated Username"},"location":{"S":"Updated Location"}}}
}
}
}
It looks like a syntax error, but I couldn't figure out what the error is. Any help is appreciated.
The SET action in your update expression is missing the = operand.
It should be "expression" : "SET #p = :da" instead of "expression" : "SET #p :da".
I've got a simple AppSync API that has a type for City and Venue, the example is to map small retail shops. I'm trying to create a new City via the "Queries" pane within AppSync, I'm also wanting to provide a shortened ID - as opposed to the long autoId so that I can run queries for the shortened ID and the frontend app can use it from the params in the URL.
I'm trying to create a new item in DynamoDB with the following code:
Schema
type City {
id: String!
name: String!
}
type Mutation {
...
createCity(input: CreateCityInput!): City
...
}
input CreateCityInput {
id: String!
name: String!
}
Mutation.createCity
// Request mapping template
{
"version" : "2017-02-28",
"operation" : "PutItem",
"key" : {
## If object "id" should come from GraphQL arguments, change to $util.dynamodb.toDynamoDBJson($ctx.args.id)
"id": $util.dynamodb.toDynamoDBJson($ctx.args.id)
},
"attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args)
}
// Response mapping template
$util.toJson($context.result)
Here's the mutation that I ran within the Queries page
mutation CreateCity {
createCity(input: {
id: "11538062"
name: "Manchester"
}) {
id
name
}
}
And this is the error that is returned from AppSync and or Dynamo
{
"data": {
"createCity": null
},
"errors": [
{
"path": [
"createCity"
],
"data": null,
"errorType": "DynamoDB:AmazonDynamoDBException",
"errorInfo": null,
"locations": [
{
"line": 32,
"column": 3,
"sourceName": null
}
],
"message": "One or more parameter values were invalid: Type mismatch for key id expected: S actual: NULL (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ValidationException; Request ID: 7PU4D2...)"
}
]
}
Any help would be really appreciated, I can't see why I'm unable to perform a simple Create using a provided String as the ID and it identifies it as NULL...
## Request Mapping
{
"version" : "2017-02-28",
"operation" : "PutItem",
"key" : {
"id" : $util.dynamodb.toDynamoDBJson($ctx.args.input.id)
},
"attributeValues" : {
"name" : $util.dynamodb.toDynamoDBJson($ctx.args.input.name)
}
}
I am playing with AWS AppSync. I am trying to output some error details when the request fails using the $util.error() helper (Documented here) in my resolver's response mapping template. No matter what I do, I am not able to get AppSync to output the data and errorInfo fields in the error output.
Here is the Lambda I have.
exports.handler = (event, context, callback) => {
callback(null, {
data: {
name: "Test",
},
errorMessage: "Some error Message",
errorType: "SomeErrorType",
errors: {
"foo": "bar",
"bazz": "buzz",
}
})
};
As you can see, it is pretty much straight forward. I just return an object with the data, errors, errorMessage and errorType properties.
And here is my response mapping template
$utils.error($context.result.errorMessage, $context.result.errorType, $context.result.data, $context.result.errors)
Again, pretty much straight forward. I just throw an error directly using the fields coming from the Lambda.
But when I execute the query, I get this:
{
"data": {
"myField": null
},
"errors": [
{
"path": [
"myField"
],
"data": null,
"errorType": "SomeErrorType",
"errorInfo": null,
"locations": [
{
"line": 2,
"column": 3,
"sourceName": null
}
],
"message": "Some error Message"
}
]
}
As you can see, the errorType and message fields get populated correctly, but not the errorInfo and data ones.
Am I missing something? Why isn't this working ?
I also tried hardcoding the parameters of $util.error in the template. I got the same result...
As the documentation states, Note: data will be filtered based on the query selection set. So you need to return data that matches the selection set.
So, for a basic schema that looks like:
type Post {
id: ID!
title: String!
}
type Query {
simpleQuery: Post
}
schema {
query: Query
}
And a query:
query {
simpleQuery {
title // Note this selection set
}
}
And a response mapping template:
$utils.error($context.result.errorMessage, $context.result.errorType, $context.result.data, $context.result.errors)
With a Lambda code:
exports.handler = (event, context, callback) => {
callback(null, {
data: {
title: "Test", // The same selection set
},
errorMessage: "Some error Message",
errorType: "SomeErrorType",
errors: {
"foo": "bar",
"bazz": "buzz",
}
})
};
It will return:
{
"data": {
"badOne": null
},
"errors": [
{
"path": [
"badOne"
],
"data": {
"title": "Test"
},
"errorType": "SomeErrorType",
"errorInfo": null,
"locations": [
{
"line": 8,
"column": 3,
"sourceName": null
}
],
"message": "Some error Message"
}
]
}
For the errorInfo, you will need to update the template version to 2018-05-29.
See my answer here: https://stackoverflow.com/a/53495843/2724342
I am new to AWS and I am trying to update a value in the DynamoDB using query and it is returning me below error
The provided key element does not match the schema
The code done and the response is listed below
Error Response
{
"data": {
"updateIsRead": null
},
"errors": [
{
"path": [
"updateIsRead"
],
"data": null,
"errorType": "DynamoDB:AmazonDynamoDBException",
"errorInfo": null,
"locations": [
{
"line": 30,
"column": 3
}
],
"message": "The provided key element does not match the schema (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ValidationException; Request ID: 7ELPDK32SD0K9TGT31J03ANHVNVV4KQNSO5AEMVJF66Q9ASUAAJG)"
}
]
}
Query
//I want to update the isRead key value to true of below messageId
mutation UpdateISRead{
updateIsRead(input:{messageId:"3253b0b4-6645-4df2-952f-93694cc70af3"}){
messageId
}
}
Schema
type Mutation {
updateIsRead(input: MessageIDInput!): MessageRecipient
}
type MessageRecipient {
messageId: ID!
messageRecipientId: String!
receiverId: String!
isRead: Boolean!
}
Resolver for Mutation.updateIsRead
{
"version" : "2017-02-28",
"operation" : "UpdateItem",
"key" : {
"messageId" : $util.dynamodb.toDynamoDBJson($ctx.args.messageId)
},
"update" : {
"expression" : "SET #fieldName = :fieldValue",
"expressionNames" : {
"#fieldName" : "isRead"
},
"expressionValues" : {
":fieldValue" : { "BOOL" : true }
}
}
}
Any help in this is much appreciated.
Thanks in Advance.
If someone is looking for an answer for the above issue, I resolve it by changing below
"messageId" : $util.dynamodb.toDynamoDBJson($ctx.args.messageId)
to
"messageId" : $util.dynamodb.toDynamoDBJson($ctx.args.input.messageId)
We need to take the sent data as an input so after adding $ctx.args.input.messageId it resolved my issue.