-
Notifications
You must be signed in to change notification settings - Fork 344
[apollo-link-offline] What's your idea? #125
Comments
What would you consider as the typical use case ? |
As an offline app:
I imagine that it is used like this:
|
I think this would be an amazing piece of functionality. The way I see it potentially happening, would be to have Apollo-link-offline define a set of Queries and Mutations that need to be used offline. Once those are defined, in the background of the application, we could fetch all the data from the Queries and store those in local storage. For the Mutations, we'd need all the fields created in the local storage so that we can store any data that is created offline. This way we can still perform functionality while offline while storing the data in a local cache. Obviously there'd need to be some form of Concurrency protection in place. My worry is User A (offline) updates Table X while User B (online) has updated Table X while User A was offline. We'd need some form of Concurrency rules here. I guess it could be date driven, but it doesn't solve the issue if User A overrides User B's data without User B being aware. Or we could just fail the Mutation and let the User manually update when back online. Apollo Client 2 is amazing, but this piece of functionality would be the absolute dogs bollocks |
I'd be a huge fan of this as well. I know there's been varying attempts at tackling this with 1.0's Redux store, but making it a full citizen of the Apollo 2.0 ecosystem with a consistent approach would be pretty marvelous. Most of what was covered here already makes a lot of sense to me- basically I want to persist my data to local storage, and then yank it from there into Apollo after the fact. Secondarily, queuing up mutations. As kind of a tertiary goal, being able to suck in even more data in the background would also be great, and something I'll be looking to do regardless. I'd actually like to store almost all of the user's data locally as well, just to make common query operations much faster, and then rehydrate for full accuracy, network allowing. So some sort of solution for that eagerly-load-for-later angle would be great, particularly as Service Workers are starting to become viable with Safari finally having them in tech preview. |
I too am excited about this. @danieljvdm Got a bit of a head start on persistence over in an issue in the apollo-client repo. I think the RetryLink will be useful for managing network errors and retries, though I'd like to see some sort of falloff like redux-offline had. |
This is pretty cool. The issue that @2WheelCoder referenced is an early and perhaps naive approach geared more towards persisting the cache rather than full offline support (queuing queries/mutations and such). It still could be a decent place to start and build on top of. What I pointed out in that issue is that I currently don't have a good way of monitoring the cache for changes. I actually tried to implement @2WheelCoder 's initial suggestion earlier today but ran into similar problems. The issue with creating an ApolloLink for "monitoring store changes" is that it only lives in the context between a client action and then the subsequent cache write. So I can intercept the request before it goes out (middleware) and intercept it before it gets written to the cache (afterware) but I don't know when it has been written - I can only guess (my current hack is a 1000ms timeout). Another fatal flaw with using a link for offline persistence is that it doesn't account for subscriptions. A subscription link will only fire when the subscription is opened, not on subsequent events (maybe there's a way to do this that I missed?). This is basically where I am right now, and I'm pretty stuck - I think to get any further I may have to open a PR to apollo-cache-inmemory. |
@danieljvdm I’m in the same place and I think it does make sense to handle persistence directly on the cache after just running into the same issue you did. The HttpLink just isn’t suited for it since the observable completes after the request but (usually) before the cache updates. While it may be worth opening up a PR on apollo-cache-inmemory I also wonder if it would be better to fork it into a new project. Apollo 2’s modularity around the cache and link seem to suggest that if you need a different kind of cache you can just build it. Maybe an issue on apollo-client is the next step (I don’t think apollo-cache-inmemory has its own repo)? Apologies for getting a little off-topic from links here. |
@holman would you have a reference about service worker in safari tech preview? |
@sedubois it dropped (kinda suddenly) a month or two ago. It's in tech preview, but there's still quite a bit to go. |
@2WheelCoder I like the idea of a PR to apollo client for a new cache. Perhaps |
@2WheelCoder @danieljvdm what about using LocalForage for the persistence https://github.com/localForage/localForage If you guys open a PR I'd be willing to lend a hand |
@danieljvdm Yeah, I'll open an issue if you want to get a PR going. I don't have much time over the next week and a half, but am happy to jump in after that. @Eishpirate Definitely agree LocalForage is great. I think the way redux-persist managed saving the store was pretty solid and can probably act as a decent pattern to follow in |
Folks, i am using redux persist package to save store data in react native AsyncStorage. Hows i do this now? Any idea? |
@Eishpirate: does localforage work for react native? Looking at the compatibility chart of the library, I can not find anything about react native. https://github.com/localForage/localForage/wiki/Supported-Browsers-Platforms It would be very sad if the offline feature of apollo would not work for apps.. |
@timLoewel it's a very good point. Hadn't really thought as far ahead as React Native. Don't believe it explicitly does. This may cause unexpected issues further down the line. Not sure though if there's a viable alternative without having to reinvent the wheel |
Interesting article that could be relevant to this discussion https://blog.logrocket.com/building-an-offline-first-app-with-react-and-rxdb-e97a1fa64356?t=now It looks really promising using rxdb as the offline database. This is compatible with React, React-Native, Vue, Angular, pretty much most popular options. The issue I find though is that it needs to sync with a noSQL database like PouchDB (derivative of CouchDB). In my use case I'm using a relational SQL database (Postgres) and all my data validation occurs at the database level. If I had to use this system, then I'd need to maintain validation via the jsonschema. It doesn't follow DRY principles, and would definitely introduce issues. Another option I've found is Kinto http://docs.kinto-storage.org/en/stable/index.html which works with Postgres so should avoid some of the extra layers of complexity that rxdb would introduce. Kinto uses HTTP, so we could theoretically just plug it into Apollo-link-http https://github.com/apollographql/apollo-link/tree/master/packages/apollo-link-http |
Sounds like a lot of the work will be related to caching. How about redux? (I'm serious) An apollo-link-offline package, based on the apollo-offline work and... Apollo created the inmemory-cache as the default, generic solution - I can understand why they didn't want to be tied so closely with another library. But the redux/redux-offline/redux-persis solution is so battle-tested... it's still a great choice. Development is very active for all three. EDIT: apollo-cache-redux exists now, thanks to @rportugal |
@giautm I've implemented pretty much exactly what you describe for a small project of mine a little while ago, and decided to publish it as a really simple package: apollo-link-queue. If any of you have ideas for improvement, I'd love to get your suggestions or contributions. |
Please what is the state of this issue? Is there something we can use for offline stuffs that is from Apollo and not related to Redux Offline? |
@smithaitufe, |
@Gregor1971 How does this differ from apollo-link-queue |
Hey folks, I've tried to piece together a basic implementation for react-native that has similar behavior to apollo-offline. You can check it out in this gist: https://gist.github.com/lachenmayer/2e364a5ca9ae0918eb032867d0c6720d It's a combination of:
When the device goes offline, requests will be queued, and will be unqueued when it goes back online. ( Any request that fails with a network error will be retried (currently infinitely). ( However, if we can resolve the query from the cache, it will not be retried, and instead the data in the cache will be used as the response. This is implemented in the In my opinion, this "optimistic fetch" behavior is one of the most important parts of apollo-offline, and any future If you save the gist as import { InMemoryCache } from 'apollo-cache-inmemory'
import { ApolloClient } from 'apollo-client'
import { createHttpLink } from 'apollo-link-http'
// get this from https://gist.github.com/lachenmayer/2e364a5ca9ae0918eb032867d0c6720d
import { createOfflineLink } from './offlineLink'
const cache = new InMemoryCache()
const networkLink = createHttpLink()
const offlineLink = createOfflineLink({ cache })
const link = ApolloLink.from([
// ... + other links ...
offlineLink,
networkLink,
])
const client = new ApolloClient({
cache,
link,
} Known issues / missing bits
I'd appreciate for anyone who's looking for a solution on this to try this out, and we can then possibly turn this into a proper npm module with typings, tests, docs & the whole lot. This behavior is super important in my opinion, and it's a real shame that apollo-client 2 has no proper solution for this yet. Nice one ✌️ |
It looks like apollo-link-queue does intelligent things based on connection status. apollo-cache-persist saves the cache; allowing, for example, users to start and run your app while disconnected. Without persisting the cache, you app would need connectivity to start up, We'll likely want both, or better yet, @lachenmayer's solution above (which uses apollo-link-queue) and a cache that's persistent. (we're chatting in the link repos, so the most of the focus here is on that) |
@lachenmayer From first looks, your approach looks very appealing. I absolutely agree with you on the necessity of something like I myself am not quite satisfied with how I had to implement selectively enabling/disabling the optimistic fetch feature in The next couple of weeks are going to be quite stressful for me. After that though, I'd be more than happy to contribute to the implementation of an up-to-date offline first solution for Apollo - may that be a new version of the |
Thanks @MLPXBrachmann! |
@lachenmayer @MLPXBrachmann I am more than ready and willing to contribute. |
I too am looking for options to implement offline behavior in an Apollo app. The approach from @lachenmayer looks super promising, but as it relies on apollo-link-retry the mutations that have not been applied successfully will not be persisted, so if the page is refreshed any data that has not been committed to the server will be discarded (I assume that is the same thing on react-native if the app is suspended). Is there any work or at least discussion on that aspect? |
@nicocrm I see... At the moment the discussion around offline support ist mostly in this issue. I think apollo themselves have other priorities right now, so we should create a community project |
@benseitz I am definitely in favor of that. There is a lot of interest in the feature so I am sure there is room for a community project - as long as I am not duplicating or fragmenting existing effort I can create a new team and repo for apollo-link-offline and invite all interested. I have some personal interest as well as a client really pushing for that feature so I'll have some hours to burn on it. I'll ask on the apollo-offline repo to see if they want to take the lead on it since they have a lot more experience. |
I definitely have personal interest in this too - would be happy to chat further with you on this @nicocrm. I haven't noticed any lost requests so far on react-native but tbh I haven't really tested all this stuff properly (only with queries so far & it seems to run everything just fine). I feel like it would make sense to start a repo for this. @MLPXBrachmann who built I don't think there's any code that's going to be reusable from |
@nicocrm I very much agree with you. Persisting queued queries/mutations should definitely be something a potential @benseitz I too think it'd be a great idea to start @lachenmayer You are absolutely right, the amount of code shared by In any case I'd be happy to discuss ideas for |
@MLPXBrachmann @lachenmayer @nicocrm This sounds like the right way to do so! Are you okay with me opening both the repo and slack channel or does one of you want to do that? |
For sure, thank you! |
I added you three as collaborators to the Repo. And you can join the Of course everyone is invited to collaborate on the GitHub Repo and discuss on Slack :) |
For those of you arriving here from a Google Search, I've written up a summary of all of the existing offline technologies available today for Apollo Client 2.0. |
Is Apollo working on an AWS AppSync equivalent? We already have a GraphQL server and need offline client caching for queries and mutations using our server, not AWS solutions (i.e. Lamda, DynamoDB, Elastic Search). |
hope it working. |
@masull That would be absolutely amazing. I tried and didn't think firebase or parse platform work for me, so having this feature would be glorious. |
Hi, I would be very happy to participate in this feature build. Because I really need it for the present project. But I need some hints to get started. Does anyone have any ideas?
The text was updated successfully, but these errors were encountered: