Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple GraphQL Backends #387

Closed
rawkode opened this issue Sep 8, 2017 · 30 comments
Closed

Multiple GraphQL Backends #387

rawkode opened this issue Sep 8, 2017 · 30 comments

Comments

@rawkode
Copy link

rawkode commented Sep 8, 2017

Hi,

I have a micro-service architecture, because that's all we do now 😭, and I was hoping to run a master/minion configuration of Absinthe.

What do I mean by that?

Master - API Gateway that handles authentication and passes requests to one or more minions for a response

Minion - Exposes a small GraphQL subset

At the moment, I'm starting to write resolvers that go and speak to other Absinthe servers, but I'm hoping Absinthe will provide a more idiomatic way of providing this.

NB: Apollo are working on exactly this and referring to it as "Schema Stiching": ardatan/graphql-tools#382

@rawkode
Copy link
Author

rawkode commented Sep 22, 2017

So I've started to put together a GraphQL resolver, but I'm struggling to reconstruct the query in the resolver to forward it on. Is there a simple way to do this with the context?

@benwilson512
Copy link
Contributor

Hey! There isn't really any built in feature for this yet, nor are there any "client" type facilities in Absinthe to easily reconstruct queries.

@polmiro
Copy link

polmiro commented Oct 6, 2017

Apollo development just released a very interesting article on GraphQL stitching. It's mainly built on top of their graphql-tools library. Maybe it can serve as reference for a possible implementation here?

@rawkode
Copy link
Author

rawkode commented Oct 7, 2017

@polmiro I have a rudimentary version of this working, using Tesla as a GraphQL client.

At the moment, as @benwilson512 as said, there's no way to reconstruct the query - so I'm just hard-coding the query to request all values. As I said, rudimentary 😄

defmodule Absinthe.ProxyResolver do
  use Tesla
  adapter :hackney

  def user_from_identifier(identifier, _context) do
    user = request(method: :get, url: "https://user-service:5050/graphql", body: ~s/
      { user(identifier: identifier) {
          forename, surname, email, password_hash
        }
      }
    /)
    |> Map.get(:body)
    |> Poison.decode!([keys: :atoms])

    {:ok, user.data.user}
  end
end

@binaryseed
Copy link
Contributor

@benwilson512 do you think this "Schema Stiching" capability is something Absinthe will be able to do? We'd love to see this feature, an would like to help in any way possible to make it happen :)

@bruce
Copy link
Contributor

bruce commented Oct 18, 2017

This should be a lot easier after schema definition changes slated for 1.5. We’ll be switching gears to that after 1.4 hits stable.

@binaryseed
Copy link
Contributor

Awesome!

@bruce bruce added this to the Schema Definition Refactor milestone Oct 25, 2017
@zimt28
Copy link

zimt28 commented Dec 5, 2017

@bruce Is there a place to see the planned changes for schema definitions?

@benwilson512
Copy link
Contributor

@zimt28 the planned changes are first and foremost internal. We expect to avoid any breaking changes, all schemas that work today should continue to work. These changes ought to enable a variety of features however, and fix some bugs along the way. https://github.com/absinthe-graphql/absinthe/milestone/7 tracks the issues associated with the change.

@axelson
Copy link
Contributor

axelson commented Feb 5, 2018

@rawkode did you ever enhance your resolver? Or is it still simply requesting all values?

@rawkode
Copy link
Author

rawkode commented Feb 6, 2018

@axelson I'm still using that as is, there's no way to get the query at that stage. I started using Apollo Server, which supports schema stiching, as the API gateway and I am phasing our Absinthe at that layer

@Frogglet
Copy link

@benwilson512 Given that 1.5 seems to be mostly finished, I was wondering if you might have more information on how difficult schema stitching (or something like it) would be to implement in 1.5?

@Yamilquery
Copy link

@rawkode could you tell us how was your experience using Apollo Server directly?
Do you miss some Absinthe features or the Elixir power?

@binaryseed
Copy link
Contributor

Hi, my team at New Relic has schema stitching implemented on top of Absinthe, and I intend to open-source that in the coming months

It's not at all trivial, but we have most of the edge cases worked out

@acrogenesis
Copy link

That awesome @binaryseed, if you need some beta testing, at Valiot we use Absinthe for our microservices but an Apollo schema stitcher, we would love to help you and your team.

@Eptis
Copy link

Eptis commented May 15, 2019

@binaryseed any update on the open sourcing?

@sebsel
Copy link

sebsel commented Jun 4, 2019

Just wanted to note that Apollo deprecated their stitching solution, in favor of Apollo Federation.

While stitching was compatible with Absinthe backends, it seems like Federation is not, because they require the 'minion' services to expose a different kind of schema. Interested to see how that fits into this discussion and Absinthe.

@sebsel
Copy link

sebsel commented Jun 4, 2019

I was wrong: these fancy new @key things are actually in the GraphQL spec as 'directives', Absinthe has ways to define them, and here is a page describing which ones to support in your Schema to make use of the @apollo/gateway: Federation spec.

Sounds compatible, and also sounds like a thing that could live outside of the main Absinthe repo.

Edit +10 hours: I was wrong again... seems like the directive macro defines directives that can be used in the query, but after a day of hacking away at it I can't figure out how to get them into my Schema. I'll try to leave it alone now and wait for better informed people.

@JakeBeresford
Copy link

@sebsel did you get anywhere with the federation?

@sebsel
Copy link

sebsel commented Aug 10, 2019

@JakeBeresford No, I did give it up after writing that above reply. We just use stitching and wrote the stitching service in NodeJS.

Federation requires a property on your schema that returns the SDL (query { _service { sdl } }), but since SDL is a feature of Absinthe 1.5, it might be best to wait for that. Unfortunately, it has been in development for quite a while now, as I understand mostly because of reworkings to support the now-deprecated stitching. But having your schema in SDL is beneficial for both.

@sebsel
Copy link

sebsel commented Aug 10, 2019

Also, this is needed, as I mentioned in the earlier post: #766

Maybe Federation should have it's own issue, as it is quite distinct from what the OP asks for.

@tonyrud
Copy link

tonyrud commented Nov 8, 2019

@sebsel Great article on Stitching vs Federation! Any updates on getting the Federation setup to work in Absinthe? Would love to be able to use this for a large microservices project my team is getting ready to start on.

@binaryseed binaryseed removed this from the Schema Definition Refactor milestone Dec 7, 2019
@collegeimprovements
Copy link

Should we create a new issue for Federation Support ?

@jessedrelick
Copy link

jessedrelick commented Mar 31, 2020

Official Apollo Federation Spec

Any updates on this? I'm currently working on Apollo Federation support in Absinthe and the main blockers I have at the moment are:

  1. Defining __resolveReference does not work because Absinthe correctly throws an error when using 2 underscores on a field. I'm looking into configuring that error as a warning instead in order to support the federation spec.
  2. extend support is not 100% required but without it Absinthe APIs will not be able to extend types defined in other schemas, only define source types:
    PR to Support extend in Absinthe
  3. I cannot figure out how to APPLY directives to SCHEMA (rather than QUERIES). I'm still navigating directives myself but from my learnings I've found 2 distinct ways to APPLY directives:

QUERY DIRECTIVES
These are defined by the client when querying a GraphQL API. Using the directive notation macros in Absinthe will make these directives valid for clients to use in their queries, and then GraphQL clients can use them when querying:

{
    getUser(id: 1) {
       id
       name @skip(if: true)
    }
}

This will add skip to the list of directives on the name field Blueprint, which can then be used in middleware/plugins/phases etc to customize behavior. In this case, the skip behavior is built into Absinthe.

SCHEMA DIRECTIVES
Unlike Query Directives that are applied when querying the api, Schema Directives are APPLIED directly to the schema. This is the case needed for Apollo Federation because the gateway uses these directives to understand how to resolve queries across federated services. The best example is the @key(fields: [_FieldSet]) directive:

directive :key do
  arg :fields, list_of(:_FieldSet)
  on [:object, :interface]

  expand fn
    _, node ->
      Blueprint.put_flag(node, :fields, __MODULE__)
  end
end

object :directive_tester, directives: ["I WANT TO APPLY KEY DIRECTIVE WITH ARGS HERE"] do
  field :id, :string
  field :_resolve_reference, :directive_tester do # should be __resolve_reference with double underscore
    resolve(fn _, _, _ ->
      {:ok, %{ id: 1 }}
    end)
  end
end

It seems that directives is a valid attribute when defining an object, I just cannot figure out what I'm supposed to put there or if it's actually supported. I found this question on the Elixir forum which also seems to express the same confusion:

How to apply directives?

A built-in example of this is the @deprecated(reason: String) directive. Obviously a client would not be specifying this when querying, it is up to the server to APPLY this to the schema.

IMPORTANCE
I know there are some federation/stitching alternatives in the Elixir/Absinthe world, but due to the popularity of Apollo I believe supporting the federation spec may help remove the barriers preventing wider adoption of Elixir/Absinthe, especially if Apollo Federation ends up becoming part of the standard GraphQL spec.

Any guidance on this would be highly appreciated. I have PLENTY of free time right now and would love to learn more about Absinthe and contribute any way I can, including documenting this process.

@binaryseed
Copy link
Contributor

binaryseed commented Mar 31, 2020

From what I can tell, Apollo Federation relies on some behavior that "works around" the GraphQL spec itself... That's why it requires the API to expose the SDL of the schema as a field instead of using the normal Introspection query. GraphQL schema directives are intentionally not exposed as part of the normal introspection queries, they are "private" to the server...

I think it'd be interesting to see Federation support as a library separate from Absinthe itself... A library could make modifications the various pipelines inside Absinthe to change the behavior as desired, like the __ field name restriction for example:

https://github.com/absinthe-graphql/absinthe/blob/master/lib/absinthe/phase/schema/validation/type_names_are_reserved.ex

@jessedrelick
Copy link

@binaryseed thanks for the prompt reply. I'll look deeper into the exposed SDL, I appreciate the feedback there.

My plan is for this to be a separate library without any need to change Absinthe. I'm hopeful that will be possible due to the various extension points available (plugins, middleware, phases etc).

@ryanwinchester
Copy link

What kind of work needs to be done to support federation?

Either with Apollo in front, or providing a similar functionality without it.

Is there currently any way to get this working at all?

@michaljanocko
Copy link

Any updates on this problem? I feel like this is the main deal-breaker for adopting Elixir and Absinthe for most people.

@binaryseed
Copy link
Contributor

I've posted this in the various Issues but perhaps not this one... We did open source an example schema stitching application:

https://github.com/newrelic/absinthe-schema-stitching-example

Building this kind of support into absinthe core is unlikely, but with the flexibility of absinthe as-is, it's possible to accomplish.

@binaryseed
Copy link
Contributor

Closing since this kind of feature won't be built into absinthe core. We'd be excited to see what folks in the community are doing in this space!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests