5

I have a graphql server on one of my EC2 instances running. I also have AWS appsync running, but at the moment it's integrated only with couple of lambdas.

I'd like to connect my Appsync with graphql server, so Appsync will behave as a proxy for specific queries/mutations.

So from client side, it will look like this:

  • Client sends a query to the appsync, lets say that it looks like that:
{
  user {
    id
  }
} 
  • Appsync has defined a user query, it's configured to proxy the query the graphql server, without any changes
  • Graphql server is able to handle following query:
{
  user {
    id
  }
} 

and returns a result:

"data": {
  "user": {
    "id": "123456789"
  }
}
  • finally Appsync proxies response back to the client

Am I able to configure Appsync in a way that given scenario is possible? Is it the right pattern to use Appsync for?

Update 1. After @mparis response

I was able to proxy my request through AppSync, and reach my graphql server, with following resolver configuration:

{
    "version": "2018-05-29",
    "method": "POST",
    "resourcePath": "/graphql",
    "params":{
        "body": {
          "query": "$util.escapeJavaScript($ctx.info.getSelectionSetGraphQL())"
        }
    }
}

But this still does not work as expected - it's different from description in docs, and I see at least two issues:

  1. If I have a query with arguments and nested paylod, $ctx.info.getSelectionSetGraphQL() cuts out the query name and arguments part, and gives me only nested payload, so this query:
{ 
  user(id: "1") {
    picture {
      url
    }
}

becomes following one, once I call $ctx.info.getSelectionSetGraphQL():

{
   picture {
     url
   }
}

But I'd like to use whole query, same as described in docs:

"selectionSetGraphQL": "{\n  getPost(id: $postId) {\n    postId\n    title\n    secondTitle: title\n    content\n    author(id: $authorId) {\n      authorId\n      name\n    }\n    secondAuthor(id: \"789\") {\n      authorId\n    }\n    ... on Post {\n      inlineFrag: comments {\n        id\n      }\n    }\n    ... postFrag\n  }\n}"
  1. Lets say I have a query, and I've defined resolver for user query in appsync, the query looks like this:
{ 
  user(id: "1") {
    picture {
      url
    }
}

and I call my graphql backend through appsync, in my graphql logs I see following response logged:

{
  "data: {
    "user": {
      "picture": {
        "url": "example.com/link/to/a/picture"
      }
    }
  }
}

but appsync returns me given response instead:

{
  "data: {
    "user": {
      "picture": null
    }
  }
}

I've figured out, that appsync expects from me that I will define resolvers for both user and picture query. Appsync wants to first call user and then picture query, but what I wanna do is simply proxy the response through appsync, without calling any additional queries except user. Everything is evaluated in my graphql backend and should be just put to the response body, but appsync wants to evaluate everything one more time.

Is there any solution for no 1. and 2.?

Pawel Kiszka
  • 812
  • 7
  • 11

2 Answers2

0

As of writing, you can use the $ctx.info object to get the selection set of queries from within the resolvers and send the relevant data via an HTTP resolver to your downstream service. Go here and look for the info field on the $ctx object. To make this work, you will need to mirror the schema of your downstream API within your AppSync API.

Thanks for bringing this up. The team is aware of these use cases and this helps prioritization.

mparis
  • 3,623
  • 1
  • 17
  • 16
  • Thanks for your response! I've tried to implement your solution, but another questions/issues came in between. Would you be able to take a look at my updates in the main topic, please? – Pawel Kiszka Feb 25 '20 at 09:29
0

You can use the following resolver function:

I used the openly available StarWarsAPI as data source: https://swapi-graphql.netlify.app

{
  "version": "2018-05-29",
  "method": "POST",
  "resourcePath": "/.netlify/functions/index",
  "params": {
    "headers": {
      "Content-Type": "application/json"
    },
    "body": {
      "query": "query { starship (id: \"$ctx.args.id\") $util.escapeJavaScript($ctx.info.getSelectionSetGraphQL()) }"
    }
  }
}

And then you have to get the data from the graphql response using this reponse mapping:

$util.toJson($util.parseJson($ctx.result.body).data.starship)

(You have to duplicate the schema in appsync)

NanoWar
  • 81
  • 1
  • 5