aerogear / offix

GraphQL Offline Client and Server
https://offix.dev
Apache License 2.0
758 stars 45 forks source link

Support for local typeDefs and resolvers #259

Closed wilmervanheerde closed 4 years ago

wilmervanheerde commented 4 years ago

I'm using a local GraphQL schema with client-only queries to achieve local state management using Apollo.

Since ApolloClient gets initialized by Offix itself, and there is no way to provide additional typeDefs and resolver options in the config I'm wondering if this is even possible using Offix?

Here is an example of the options I need that can't be offered to Offix' OfflineClient:

const apolloClient = new ApolloClient({
  typeDefs,
  resolvers,
});

Ideally, it should be possible to pass a client initializer function which allows you to create an ApolloClient from outside OfflineClient.

darahayes commented 4 years ago

@wilmervanheerde thanks for raising this issue, this is a really valid point.

Ideally, it should be possible to pass a client initializer function which allows you to create an ApolloClient from outside OfflineClient.

I totally agree. I'm going to investigate how we can support that while also keeping in mind that we initialise the client ourselves with a couple of things that we absolutely need in order for things to work properly. (Mainly the cache and some links). I will report back soon.

It's not ideal but as a workaround, you might be able to do something like this.

const offlineClient = new OfflineClient(options)
const apolloClient = new ApolloClient({typedefs, resolvers})
offlineClient.decorateApolloClient(apolloClient)

This is an internal function that OfflineClient uses to decorate the Apollo Client with things like the queue and the offlineMutate function (if you're using typescript you'll need a @ts-ignore comment). We might be able to rework things to make that method (or something similar) a supported API.

I'd love to get your opinion on how you'd like things done. Thanks.

wilmervanheerde commented 4 years ago

Thanks for the quick and detailed response! The workaround you suggested is what I considered, but it might give some side effects. I can't say so much about this but I think the execution and caching of local queries will have to be kept in mind

It would be awesome to see this implemented at some time :smile:

wtrocki commented 4 years ago

Simplest way to do that will be to extract create client to separate abstract function: https://github.com/aerogear/offix/blob/master/packages/offix-client/src/OfflineClient.ts#L139-L142

When this is done developers can simply extend client and provide their own createClient implementation. This is very small change with a lots of benefits.

darahayes commented 4 years ago

+1 on this idea @wtrocki it's a quick and maintainable way to get there. There will be a small requirement on the user's part that they include the appropriate cache and link. I'm happy enough that we can document it and it gives users what is needed.

wtrocki commented 4 years ago

See #263

darahayes commented 4 years ago

Hey @wilmervanheerde so sorry for taking this long to get back to you. Your issue actually motivated us to go ahead and do some work that we've been planning on doing for a long time.

Previously, the OfflineClient class was a wrapper that would internally create an ApolloClient and then you could get access to it afterwards. The flow looked something like this.

const offlineClient = new OfflineClient(options)
const apolloClient = await offlineClient.init()

And of course, your issue was that you wanted to pass some additional options into the resulting ApolloClient but our API didn't provide a way to do that.

Well, we've refactored things so now we export a class called ApolloOfflineClient which directly extends ApolloClient. Now you can pass in all of the Apollo Client options you'd like.

The way you initialise things is slightly different, mainly, you need to pass an ApolloLink that can talk to your GraphQL server. Check out the example code below.

import { ApolloOfflineClient } from 'offix-client'

const link = new HttpLink({ uri: 'http://localhost/graphql' })

const config = {
  link,
  typeDefs,
  resolvers,
  ...otherOptions
}

const client = new ApolloOfflineClient(config)
await client.init()
...

// `client` is an ApolloClient so you can call all of the methods you'd expect
client.query(...)
client.mutate(...)
client.offlineMutate(...)

We haven't officially released it yet and we're still working on some docs updates but you should be able to try out our dev release with npm install offix-client@0.11.0-dev3. We'd love to get your feedback to see if it resolves your problem (and hopefully doesn't create any new ones) before we cut an official release. Thanks!

wilmervanheerde commented 4 years ago

Thanks for picking this up so early, the new changes look awesome!

wtrocki commented 4 years ago

Changes landed in 0.11.0 release. @darahayes lets update docs to the new api.