ashiaka
ashiaka

Reputation: 4064

AppSync perform multiple HTTP requests for one query

I've got the following use case I want to solve with AWS AppSync:

  1. Client sends GraphQL query saved(username: String)
  2. AppSync sends query to an HTTP endpoint which returns a list of items: {"items": ["a", "b"] }
  3. For each of these items (a,b) AppSync sends a query to an HTTP endpoint which returns details for the items. I.e. {"images": ["1.jpg", "2.jpg"], "panoramas": ["1a.jpg"]}
  4. This should be combined to an response: {"saved": [{"images": ["1.jpg", "2.jpg"], "panoramas": ["1a.jpg"]}, {"images": ["11.jpg", "22.jpg"], "panoramas": ["1b.jpg"]}]}

schema:

type Query {
    saved(username: String!): [Detail]
}

type Detail {
    images: [String]
    panoramas: [String]
}

The HTTP enpoints are fairly simple:

GET /users/$username/saved/
GET /details/$itemid/

I've looked into Pipeline resolvers but couldn't get anything working. Also I tried to attach a resolver directly to "Detail" which is not possible. It seems that I lack some basic understanding of AppSync here. Can you point me to the right direction?

Upvotes: 2

Views: 1928

Answers (1)

Myz
Myz

Reputation: 828

So, I did some further experimentation and testing, this is the closest I came.

Modify your schema like this;

type Query {
  saved(username: String!): [Item]
   
type Item {
  items: String
  details: Details
}

type Details {
  images: [String]
  panorama: [String]
}

For your saved query;

Request Template

{
  "version": "2018-05-29",
  "method": "GET",
  "resourcePath": "/users/$ctx.args.username/saved",
  "params":{
      "headers": {
          "Content-Type": "application/json"
      }
  }
}

Since your API response is not exactly what AppSync would recognize so we have to do some sanitation. Therefore in response template

#if($ctx.error)
  $util.error($ctx.error.message, $ctx.error.type)
#end
#if($ctx.result.statusCode == 200)
    #set($itemList = [])
    #set($items = $util.parseJson($ctx.result.body).items)
    #foreach($item in $items)
      #set($itemJson = {})
      $util.qr($itemJson.put("items", $item))
      $util.qr($itemList.add($itemJson))
    #end
    #return($itemList)
#else
    $utils.appendError($ctx.result.body, "$ctx.result.statusCode")
#end

Now, you can attach another HTTP resolver with your details like this;

Request Template

{
  "version": "2018-05-29",
  "method": "GET",
  "resourcePath": "/details/$ctx.source.items",
  "params":{
      "headers": {
          "Content-Type": "application/json"
      }
  }
}

Response template

#if($ctx.error)
  $util.error($ctx.error.message, $ctx.error.type)
#end
#if($ctx.result.statusCode == 200)
    $ctx.result.body
#else
    $utils.appendError($ctx.result.body, "$ctx.result.statusCode")
#end

I tested the above code and it give me this response;

{
  "data": {
    "saved": [
      {
        "items": "a",
        "details": {
          "images": [
            "1.jpg",
            "2.jpg"
          ],
          "panoramas": [
            "1a.jpg"
          ]
        }
      },
      {
        "items": "b",
        "details": {
          "images": [
            "11.jpg",
            "22.jpg"
          ],
          "panoramas": [
            "1b.jpg"
          ]
        }
      }
    ]
  }
}

I hope this will help you and might not give you exactly what you asked in your question (specially your requirement # 4) but I hope it will at least give you some direction.

Upvotes: 1

Related Questions