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

Support multiple GraphQL endpoints #315

Closed
benmonro opened this issue Jul 31, 2020 · 12 comments · Fixed by #319
Closed

Support multiple GraphQL endpoints #315

benmonro opened this issue Jul 31, 2020 · 12 comments · Fixed by #319

Comments

@benmonro
Copy link
Contributor

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
our app has to hit multiple graphql endpoints. So this is either a question, or if it's not possible a feature request.

The problem is that our app is using graphql endpoints from more than 1 url.

Describe the solution you'd like

The ability to specify the base url for a graphql.query.

Currently you define a route like this: graphql.query("MyQuery", () => {})

Not sure exactly what the best api is for this, but here are a couple of options.

  1. something simple like
graphql.query("MyQuery", () => {}, {baseUrl:"http://example")
graphql.query("MyFooQuery", () => {}, {baseUrl:"http://foo")
  1. something at a higher level that let's us map multiple queries:
graphql.urls({
  "http://example": [
     graphql.query("MyQuery", () => {}), graphql.query("MyOtherQuery", () => {})
  ],
  "http://foo": [
     graphql.query("MyFooQuery", () => {}), graphql.query("MyOtherFooQuery", () => {})
  ]
  1. open to other options? just need a way to handle multiple GQL endpoints. again, maybe there's already a way and we can close this issue.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

@kettanaito
Copy link
Member

kettanaito commented Aug 1, 2020

Hey, @benmonro.

What do you think if we adopt an approach similar to Apollo's "Link" component and allow to define a separate graphql request handler instances based on the server URL?

import { setupWorker, graphql } from 'msw'

const gitHub = graphql.link('https://api.github.com/graphql')
const stripe = graphql.link('https://api.stripe/v3/gql')

setupWorker(
  gitHub.query('GetUser', resolver),
  stripe.mutation('WithdrawFunds', resolver),
)

I'd appreciate your expertise in GraphQL to suggest us what the API for graphql.link (or graphql.client) may look like. Is there anything else to cover than the endpoint URL?

Such API should definitely exist, and we need to define its spec first.

  1. How should it align with the existing GraphQL clients? Should it resemble something like schema federation?
  2. Should the endpoint URL support parameters, wildcards, RegExp? Is there a practical use in such support?
  3. Should graphql.link allow some per-endpoint logic? For example, a custom "middleware".

@benmonro
Copy link
Contributor Author

benmonro commented Aug 1, 2020

This would be perfect! Nice clean API, I love it.

My expertise on gql is limited I'm afraid but everything you said all seems good to me. I think the way you describe it also lends itself to iteration.

@kettanaito kettanaito self-assigned this Aug 1, 2020
@kettanaito kettanaito changed the title multiple graphql endpoints Support multiple GraphQL endpoints Aug 2, 2020
@marcosvega91
Copy link
Member

to avoid breaking changes we should support both forms? 🤔

@kettanaito
Copy link
Member

Hey, @marcosvega91. There's no breaking changes, as graphql.link just encapsulates both .query and .mutation, adding an extra URL (mask) predicate check.

I've started working on this, will ship pull request soon!

@kettanaito
Copy link
Member

The graphql.link API has been added to the 0.20.2 release 🎉

Refer to the Documentation for explanations and use examples.

@benmonro
Copy link
Contributor Author

benmonro commented Aug 5, 2020

🎉 that was fast! Thank you @kettanaito !

@benmonro
Copy link
Contributor Author

benmonro commented Aug 5, 2020

@kettanaito just curious, do you think it would make sense to apply this same pattern to rest?

i.e. rest.link?

@kettanaito
Copy link
Member

kettanaito commented Aug 6, 2020

While it may sound compelling, graphql.link and rest.link would have significant design difference:

  • graphql.link adds an extra layer of endpoint matching as a part of its predicate.
  • rest already matches a request URL against a given endpoint, so the functionality of linking routes to a specific endpoint becomes a matter of a plain abstraction:
const github = (path: string) => {
  return `https://api.github.com/v3${path}`
}

rest.get(github(/repo/:owner/:name’), resolver)

I wish this was a way we solve a per-endpoint mocking for GraphQL as well, and it may become similar to this in the future.

@benmonro
Copy link
Contributor Author

benmonro commented Aug 6, 2020

Yeah for sure. Makes sense just thought it would be more consistent to have a unified approach...

@kettanaito
Copy link
Member

kettanaito commented Aug 6, 2020

We actively encourage functional composition, so introducing a function that prepends a fixed portion of a URL is the way to go. Think of it as of custom React hooks: if you need a hook you don't request it to be added to the React API, you reuse existing hooks to create your own. Request handlers in this matter are very similar: you are given an API and you are in charge of adapting it so it suits your specific needs.

@vitorcamachoo
Copy link

Hii , I've a question.

If I have the same query for different endpoints, how it will know if goes to one or another, example:

import { setupWorker, graphql } from 'msw'

const gitHub = graphql.link('https://api.github.com/graphql')
const stripe = graphql.link('https://api.stripe/v3/gql')

setupWorker(
  gitHub.query('GetUser', resolver),
  stripe.query('GetUser', resolver),
)

@kettanaito
Copy link
Member

Hi, @vitorcamachoo.

Because you've defined endpoints, whenever a GetUser query happens, MSW will also take its request URL into account. When you make a query, you specify the endpoint URL. Roughly, it can be represented as follows:

const client = graphQLClient({ endpoint: 'https://api.github.com/graphql' })

client.query(`
  query GetUser { ... }
`

If you inspect your GraphQL query in the Network tab, you will see it being a GET/POST request to the server endpoint you've specified. That's how MSW distinguishes between them: their request URLs are different.

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

Successfully merging a pull request may close this issue.

4 participants