amazon-web-servicesgraphqlaws-appsyncresolvervtl

Get parent object in child resolver AWS AppSync


I have a graphQL schema like this:

type Post {
    id: String!
    title: String!
    content: String!
    user: User!
}

type Query {
    allPosts: [Post!]
    singlePost(id: String!): Post!
}

type User {
    name: String!
    posts: [Post!]
}

The dynamo DataSource handles queries. In the query below, the user will be handled with a different resolver because it depends on different GSI.

query MyQuery {
  allPosts {
    content
    title
    user{
      name
    }
  }
}

allPosts resolver looks like this:

{
    "version" : "2017-02-28",
    "operation" : "Query",
    "query" : {
        "expression" : "#t = :sk",
        "expressionNames" : {
          "#t": "type"
        },
        "expressionValues" : {
            ":sk": $util.dynamodb.toDynamoDBJson("post")
        }
    },
    "index" : "GSI",
    "select" : "ALL_ATTRIBUTES"
}

The resolver for user in the Post type is:

{
    "version" : "2017-02-28",
    "operation" : "Query",
    "query" : {
        "expression" : "PK = :pk AND SK = :sk",
        
        "expressionValues" : {
            ":pk": "NEED TO ACCESS THE Partition KEY FROM ALL_POSTS",
            ":sk": $util.dynamodb.toDynamoDBJson("profile")
        }
    },
    "select" : "ALL_ATTRIBUTES"
}

I need to access the partition key from the post object in each iteration to fetch the user of a specific id, just like the author resolver in this code (https://github.com/benawad/graphql-n-plus-one-example/blob/master/src/index.js):

const resolvers = {
  Book: {
    author: async parent => {
      const author = await knex("users")
        .select()
        .where("id", parent.authorId)
        .first();

      return author;
    }
  },
  Query: {
    books: async () => {
      const books = await knex("books")
        .select()
        .limit(10);
      return books;
    }
  }
};

Solution

  • I've found the answer finally, the required object is stored in $ctx.source. All I had to do is to change the user resolver to this (Provided the result object have PK inside it):

    {
        "version" : "2017-02-28",
        "operation" : "Query",
        "query" : {
            "expression" : "PK = :pk AND SK = :sk",
            
            "expressionValues" : {
                ":pk": $util.dynamodb.toDynamoDBJson($ctx.source.PK),
                ":sk": $util.dynamodb.toDynamoDBJson("profile")
            }
        },
        "select" : "ALL_ATTRIBUTES"
    }
    

    The $context.source references the parent object of the current field that’s being resolved. In this example, $ctx.source.PK refers to the individual Post object, which is then used for the query expression. ($context and $ctx are same). It works exactly like the parent argument in the apollo-server framework.