Question:
I have an optional String field, notes, that is sometimes empty. If it’s empty I want to insert null, otherwise I want to insert the string.
Here is my resolver –
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
{ "version" : "2017-02-28", "operation": "Invoke", #set($id = $util.autoId()) #set($notes = $util.defaultIfNullOrEmpty($context.arguments.notes, 'null')) "payload": { "sql":"INSERT INTO things VALUES ('$id', :NOTES)", "variableMapping": { ":NOTES" : $notes }, "responseSQL": "SELECT * FROM things WHERE id = '$id'" } |
}
With this graphql
1 2 3 4 5 6 7 |
mutation CreateThing{ createThing() { id notes } } |
I get –
1 2 3 4 5 6 7 8 |
{ "data": { "createRoll": { "id": "6af68989-0bdc-44e2-8558-aeb4c8418e93", "notes": "null" } } |
}
when I really want null without the quotes.
And with this graphql –
1 2 3 4 5 6 7 |
mutation CreateThing{ createThing(notes: "Here are some notes") { id notes } } |
I get –
1 2 3 4 5 6 7 8 9 |
{ "data": { "createThing": { "id": "6af68989-0bdc-44e2-8558-aeb4c8418e93", "notes": "Here are some notes" } } } |
which is what I want.
How do I get a quoteless null and a quoted string into the same field?
Answer:
TL;DR you should use $util.toJson()
to print the $context.arguments.notes
correctly. Replace your $notes
assignment with
1 2 |
#set($notes = $util.toJson($util.defaultIfNullOrEmpty($context.arguments.notes, null))) |
Explanation:
The reason is VTL prints whatever the toString()
method returns and your call to
$util.defaultIfNullOrEmpty($context.arguments.notes, 'null')
will return the string "null"
, which will be printed as "null"
.
If you replace with $util.defaultIfNullOrEmpty($context.arguments.notes, null)
then it will return a null
string. However, VTL will print $notes
because that is the way it handles null
references. In order to print null
, which is the valid JSON representation of null
, we have to serialize it to JSON. So the correct statement is:
1 2 |
#set($notes = $util.toJson($util.defaultIfNullOrEmpty($context.arguments.notes, null))) |
Full test:
I’m assuming you started with the RDS sample provided in the AWS AppSync console and modified it. To reproduce, I updated the content
field in the Schema to be nullable:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
type Mutation { ... createPost(author: String!, content: String): Post ... } type Post { id: ID! author: String! content: String views: Int comments: [Comment] } |
and I modified the
posts
table schema so content
can also be null there: (inside the Lambda function)
1 2 3 4 5 6 7 8 9 10 |
function conditionallyCreatePostsTable(connection) { const createTableSQL = `CREATE TABLE IF NOT EXISTS posts ( id VARCHAR(64) NOT NULL, author VARCHAR(64) NOT NULL, content VARCHAR(2048), views INT NOT NULL, PRIMARY KEY(id))`; return executeSQL(connection, createTableSQL); } |
This is the request template for the
createPost
mutation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
{ "version" : "2017-02-28", "operation": "Invoke", #set($id = $util.autoId()) "payload": { "sql":"INSERT INTO posts VALUES ('$id', :AUTHOR, :CONTENT, 1)", "variableMapping": { ":AUTHOR" : "$context.arguments.author", ":CONTENT" : $util.toJson($util.defaultIfNullOrEmpty($context.arguments.content, null)) }, "responseSQL": "SELECT id, author, content, views FROM posts WHERE id = '$id'" } } |
and response template:
1 2 |
$util.toJson($context.result[0]) |
The following query:
1 2 3 4 5 6 7 8 9 |
mutation CreatePost { createPost(author: "Me") { id author content views } } |
returns:
1 2 3 4 5 6 7 8 9 10 11 |
{ "data": { "createPost": { "id": "b42ee08c-956d-4b89-afda-60fe231e86d7", "author": "Me", "content": null, "views": 1 } } } |
and
1 2 3 4 5 6 7 8 9 |
mutation CreatePost { createPost(author: "Me", content: "content") { id author content views } } |
returns
1 2 3 4 5 6 7 8 9 10 11 |
{ "data": { "createPost": { "id": "c6af0cbf-cf05-4110-8bc2-833bf9fca9f5", "author": "Me", "content": "content", "views": 1 } } } |