AWS Appsync schema query resolver response mapping - graphql

After performing a create mutation, i expect to get the entire response object as shown in
https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference.html
But all i manage to get is the auto generated id (part of the schema) which is of uuid type.
Below is my schema and response mapping :-
Schema:-
type Apple{
id: ID!
type: String
price: Float
}
Mutation used :-
mutation MyMutation {
updateApple(input: {id: "0a9aa23f-3017-4b67-8dcd-354ef8f609d8", type: "green", price: 10.5}) {
id
}
}
======================================================================
type Mutation {
updateApple(input: UpdateAppleInput!): Apple
}
======================================================================
input UpdateAppleInput {
id: ID!
type: String
price: Float!
}
======================================================================
Response mapping template which returns only id
## Raise a GraphQL field error in case of a datasource invocation error
#if($ctx.error)
$utils.error($ctx.error.message, $ctx.error.type)
#end
$utils.toJson($utils.rds.toJsonObject($ctx.result)[1][0])
Sample response below (I am expecting the updated "Apple" object):-
{
"data": {
"updateApple": {
"id": "0b8bb23f-5613-4b67-8dcd-354ef8f617r5"
}
}
}
I am referring the example given in :
https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-rds-resolvers.html#run-queries
And i specifically need the entire Apple object as response when i perform create or update mutations..
EDIT 1: Below response template works fine with a query. Why is it not working with a mutation? :
$utils.toJson($utils.rds.toJsonObject($ctx.result)

Related

Error Cannot return null for non-nullable type: 'String' within parent MyModelType' (/createMyModelType/id)

I am trying to trigger a mutation in the aws console. I have linked my resolver function to a None type data source.
However, when I define my mutation with an input type as a parameter, the error " Error Cannot return null for non-nullable type: 'String' within parent MyModelType' (/createMyModelType/id)." occurs. Everything is fine though if I replace the input type with key word arguments.
I am certain it has to do with my resolver mapping template.
Just if you're wondering why I am using a None type, I want to be able to trigger a subscription without making real database changes or mutations.
I am not sure how to make it work with input types. Here is my code for the template:
{
"version": "2017-02-28",
"payload": $util.toJson($context.args)
}
My Schema:
input CreateMyModelType5Input {
title: String
}
type Mutation {
createMyModelType5(input: CreateMyModelType5Input!): MyModelType5
}
type MyModelType5 {
id: ID!
title: String
}
type Subscription {
onCreateMyModelType5(id: ID, title: String): MyModelType5
#aws_subscribe(mutations: ["createMyModelType5"])
}
Query I am trying to run:
mutation createMyModelType($createmymodeltypeinput: CreateMyModelTypeInput!) {
createMyModelType(input: $createmymodeltypeinput) {
id
title
}
}
Query Variables for the mutation query
{
"createmymodeltype5input": {
"title": "Hello, world!"
}
}
So I have been working on passing my arguments in the graphql mutation and using the input type seemed the only straight forward way around.
However, I have been able to do it with this way:
mutation = """mutation CreateMyModelType($id: String!, $title: String!){
createMyModelType(id: $id, title: $title){
id
title
}
}
"""
input_params = {
"id": "34",
"title": "2009-04-12"
}
response = app_sync.createMyModelType(mutation, input_params)
this can be a good guide

Can't extending a remote graphql nested input type

graphql service 1 type defs:
import { gql } from 'apollo-server';
const typeDefs = gql`
type Post {
postId: ID!
postTitle: String!
postContent: String!
postAuthorId: ID
}
input PostTag {
name: String!
}
input PostInput {
postTitle: String!
postContent: String!
postAuthorId: ID!
postTags: [PostTag!]!
}
type CommonResponse {
code: Int!
message: String!
}
type Query {
posts: [Post]!
}
type Mutation {
addPost(post: PostInput): CommonResponse!
}
`;
export { typeDefs };
Now, graphql service 2 wants to extend PostTag input type from graphql service 1 like this:
import { gql } from 'apollo-server';
const typeDefs = gql`
extend input PostTag {
color: String
}
`;
export { typeDefs };
I print stitching schema, it's correct.
enum CacheControlScope {
PUBLIC
PRIVATE
}
type CommonResponse {
code: Int!
message: String!
}
type Mutation {
addPost(post: PostInput): CommonResponse!
}
type Post {
postId: ID!
postTitle: String!
postContent: String!
postAuthorId: ID
}
input PostInput {
postTitle: String!
postContent: String!
postAuthorId: ID!
postTags: [PostTag!]!
}
input PostTag {
name: String!
color: String
}
type Query {
posts: [Post]!
}
"""The `Upload` scalar type represents a file upload."""
scalar Upload
But when client sends a mutation like this:
mutation{
addPost(post: {
postTitle: "ez2on",
postContent: "golang",
postAuthorId: "1",
postTags: [{
name: "222",
color: "red"
}]
}){
code
message
}
}
Got this error:
{
"errors": [
{
"message": "Variable \"$_v0_post\" got invalid value { postTitle: \"ez2on\", postContent: \"golang\", postAuthorId: \"1\", postTags: [[Object]] }; Field \"color\" is not defined by type PostTag at value.postTags[0].",
"locations": [
{
"line": 7,
"column": 3
}
],
"path": [
"addPost"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"errors": [
{
"message": "Variable \"$_v0_post\" got invalid value { postTitle: \"ez2on\", postContent: \"golang\", postAuthorId: \"1\", postTags: [[Object]] }; Field \"color\" is not defined by type PostTag at value.postTags[0].",
"locations": []
}
],
"stacktrace": [
"Error: Variable \"$_v0_post\" got invalid value { postTitle: \"ez2on\", postContent: \"golang\", postAuthorId: \"1\", postTags: [[Object]] }; Field \"color\" is not defined by type PostTag at value.postTags[0].",
" at new CombinedError (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/src/stitching/errors.ts:90:5)",
" at Object.checkResultAndHandleErrors (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/src/stitching/errors.ts:111:11)",
" at CheckResultAndHandleErrors.transformResult (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/src/transforms/CheckResultAndHandleErrors.ts:15:12)",
" at /Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/src/transforms/transforms.ts:37:45",
" at Array.reduce (<anonymous>)",
" at applyResultTransforms (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/src/transforms/transforms.ts:35:21)",
" at /Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/src/stitching/delegateToSchema.ts:104:12",
" at step (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/dist/stitching/delegateToSchema.js:31:23)",
" at Object.next (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/dist/stitching/delegateToSchema.js:12:53)",
" at fulfilled (/Users/ldu020/workspace/github.com/mrdulin/apollo-graphql-tutorial/node_modules/graphql-tools/dist/stitching/delegateToSchema.js:3:58)"
]
}
}
}
],
"data": null
}
It's important to keep in mind that makeRemoteExecutableSchema just "uses the [provided] link to delegate requests to the underlying service". When you query fields from the remote schema, it's delegating the request for those particular fields to the remote server, effectively rerouting the request. This is true whether you stitch the schema with some other one, or use it by itself.
Schema stitching allows you to combine any number of local and remote schemas. However, any remote schemas will still have their fields resolved by their respective servers.
Because stitching merges the provided schemas' type definitions, you can use the extend keyword inside one schema to modify types from another, even if it's a remote schema. If we extend an object type, we can also add some resolvers to help resolve the fields we've added.
Extending a remote schema's input object is a bit different. There's no "resolving" input objects. Instead, all we do by extending it is saying "these fields are also valid". However, when we request some remote schema field that takes this modified input object as an argument, the resolution of this field is, again, delegated to the underlying remote schema. It gets the modified input object and when it validates it, it finds extra fields and throws an error.
In other words, it's not possible to extend input types like this. And consider, even if the request didn't fail validation -- even if you extend the input type, the original resolver has not been changed and so it necessarily won't know how to handle the additional input type fields anyway.
NOTE: If you do the above but with two local schemas, the extension should work as expected because there is no delegation in this case. You're still left with a resolver that doesn't necessarily know how to handle the new input object field though.

GraphQL error FieldsConflict: fields have different list shapes

I'm using AWS AppSync's GraphQL server with the following (simplified) schema:
type Query {
getIssue(id: String!): Issue
}
type Issue {
id: String!
data: IssueData!
}
type Event {
id: String!
time: AWSDateTime!
status: [String]
}
type Payment {
id: String!
amount: Int!
status: String
}
union IssueData = Event | Payment
When I make a query that includes inline fragments to select the status as a child of either an Event or Payment type in the Issue/data field, I get a FieldsConflict error:
query getIssue($id: String!) {
getIssue(id: $id) {
id
data {
... on Event {
time
status
}
... on Payment {
amount
status
}
}
}
}
Validation error of type FieldsConflict: status: fields have different list shapes # 'getIssue/data'
This is presumably caused by the Event/status field returning an array of strings, while the Payment/status field returns a single string.
Why does GraphQL consider this to be a conflict? How should I construct my query to allow access to the status field on both data types?
Note that I'm using a union rather than an extended interface because the Issue and Payment types have no common data structure.
From the spec:
If multiple field selections with the same response names are encountered during execution, the field and arguments to execute and the resulting value should be unambiguous. Therefore any two field selections which might both be encountered for the same object are only valid if they are equivalent.
You can resolve the issue by providing a field alias for one or both fields:
query getIssue($id: String!) {
getIssue(id: $id) {
id
data {
... on Event {
time
eventStatus: status
}
... on Payment {
amount
status
}
}
}
}
Renaming one or both fields in your schema would obviously also resolve the issue.

Cannot perform update query because update values are not defined

I am trying to execute a mutation like so
mutation creating {
createTeam(
payload: {
name: "Team von abc"
tacts:["94b4cbc2-b996-482f-b712-967bdb646e73"]
}
) {
id
name
}
}
This results in :
"message": "Cannot perform update query because update values are not
defined. Call \"qb.set(...)\" method to specify updated values.",
My graphql is defined like this:
input CreateTeamPayload {
name: String
tacts:[ID!]
}
type Team {
id: ID!
name: String
tacts: [Tact]!
}
type Query {
fetchTeams: [Team]!
fetchTeamById(id: ID!): Team
}
type Mutation {
createTeam(payload: CreateTeamPayload): Team!
}
My Team requires an ID from a "tact" so I provide him with an ID from a "tact" I created before. Is this approach wrong? How can I mutate types that reference other types? is there some documentation that actually does this?

AppSync subscription authorization problem

Hi i am new in aws AppSync and GraphQl. I have a problem with subscription. I want to get notifiend in real time when new post is posted
Here is my graphql schema ``
type Mutation {
addPost(
id: ID!,
author: String!,
title: String,
contennt: String,
url: String
): Post!
updatePost(
id: ID!,
author: String!,
title: String,
content: String,
ups: Int!
): Post!
deletePost(id: ID): Post!
}
type Post {
id: ID!
author: String!
title: String!
url: String
content: String
ups: Int!
}
type Query {
allPost: [Post]
getPost(id: ID!): Post
}
type Subscription {
newPost: Post
#aws_subscribe(mutations: ["addPost"])
}
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
``
Here is my Query for subs:
subscription NewPostSub{
newPost{
__typename
title
content
author
url
}
}
Im getting error that provided key element doesnt match a schema, in dynamodb table pk is id and i generated mapping template.
Thank you
Thanks for the info.
First, you do not need a resolver on your subscription field at all. The only reason you need to add a resolver to a subscription field is to do authorization checks based on the calling identity at connect time. You do not need to add a resolver to make subscriptions work. To fix it, remove the resolver off the subscription (Subscription.newPost) field.
To solve your use case and make it so you only subscribe to posts with a certain id, change your newPost subscription field to newPost(id: ID!). When you make the subscription query, provide an id and that subscription will only get pushed posts returned by the subscribed to mutation with that id. This is a feature baked into AppSync and the argument equality check happens automatically when you add the arguments to the subscription field.
Secondly as you pasted it in the comment, you currently have this request mapping template for Mutation.addPost:
{
"version" : "2017-02-28",
"operation" : "PutItem",
"key" : {
$util.dynamodb.toDynamoDBJson($ctx.args.id)
"id": $util.dynamodb.toDynamoDBJson($util.autoId()),
},
"attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args)
}
There is a typo and it should be this:
{
"version" : "2017-02-28",
"operation" : "PutItem",
"key" : {
"id": $util.dynamodb.toDynamoDBJson($util.autoId()),
},
"attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args)
}

Resources