question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Discussion: subscriptions API design improvements

See original GitHub issue

I’ve been really happy with Apollo so far, and I’m delighted that it supports subscriptions, but the way subscriptions work in Apollo still seems half-baked to me, especially compared to what I was used to in Meteor. Here are some random thoughts that have been brewing in my mind. Everyone feel free to comment or suggest solutions!

Subscription updates can be missed while you’re waiting for query results

If your subscription variables depend on query results, you can’t initiate the subscription until the initial query is complete. This poses a problem: if any updates were published between the time the initial query was executed on the server and the client gets the result and initiates the subscription, the client will never get those updates.

This is why I think it would be better to use Meteor-style subscriptions that fetch and send initial values after the server starts listening to PubSub. This is definitely already possible, but it’s not recommended in the Apollo docs, and the danger of missed updates is not mentioned anywhere in the docs AFAIK. It would also take manual effort to send the initial update when the subscription starts; something systematic is desirable if possible.

For example, at the very least, PubSub could hang onto the last value published on each topic and (optionally) republish the last value when pubsub.asyncIterator is called.

Or, pubsub.asyncIterator could accept an initialValue option, so that in our subscription resolvers, we could fetch the initial value and then pass it to pubsub.asyncIterator. This would be less involved than setting up our own async iterator to yield the initial value and then yield the rest from pubsub.asyncIterator. (I assume at least that any time we create an async iterator of our own, we should take care to implement the return and throws methods to ensure that it gets shut down properly?)

What about standalone subscriptions?

The current design seems to assume we’ll always use a subscription with a corresponding query. But coming from Meteor, where you use subscribe by itself, and the subscription sends the initial data on startup, using a query and subscription together seems a little overcomplicated for some use cases.

If subscription updates contain objects with __typename and id, couldn’t Apollo update the cache automatically?

Right now developers have to write their own updateQuery logic for each subscription, which is a bit cantankerous. But if the objects in a subscription update contain __typename and id, I’d think Apollo could apply the same normalization and cache update logic as it does for queries automatically, and not require developers to write any update logic of their own. Is there something I’m not thinking about that makes this difficult?

Updating deeply nested objects is awkward

This kind of goes along with the above. Let’s say my query is

query {
  User {
    id
    name
    Posts {
      id
      text
    }
  }
}

And let’s say I subscribe to updates on posts for the given post ids in the query result. When I get a post update, I have to merge it into the query shape, which is fairly tedious, something like the following code. It would be a lot simpler if I could just tell the Apollo cache to replace its cached post with the given id with the updated version. (Which maybe is possible, but I don’t know if it can really be done via subscribeToMore.)

updateQuery(prev, update) {
  const {User: {Posts}} = prev
  const {subscriptionData: {data: {Post}}} = update
  const postIndex = newPosts.findIndex(p => p.id === Post.id)
  if (postIndex < 0) return prev
  return {
    ...prev,
    User: {
      ...prev.User,
      Posts: [
        ...Posts.slice(0, postIndex),
        Post,
        ...Posts.slice(postIndex + 1),
      ],
    }
  }
}

Unsubscribing and resubscribing when variables could be automated

Currently all the work of unsubscribing and resubscribing if variables change is pushed onto the developer. It wouldn’t be too hard to make my own component to do this automatically in a similar way to how Apollo query HOCs automatically refetch when variables change. But it definitely seems to me like something that should live in Apollo itself.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:11
  • Comments:10 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
hwillsoncommented, May 16, 2019

Thanks for the great discussion @jedwards1211 @TheMickeyMike. A new design for the subscription API is being worked on, as part of our Apollo Client 3.0 work. I’ll close this for now (since we’re trying to make sure issues here are for bugs only), but your input is greatly appreciated. Thanks!

0reactions
TheMickeyMikecommented, Aug 7, 2018

Well for now I’m using name for better understanding how Apollo cache works. Moreover, I need to check case when my client subscribe many subscriptions (ex. likeSub, dislikeSub, newPostSub…) and if there will be one open WebSocket pipe to my Apollo server, or each subscription opens new one, if so i will stick with one connection and probably doing some magic on server side with dynamic __typename or add enum field to recognize action type and parse subscription data based on this actionType field, idk for know, just overthinking some basic stuff 🤔 Btw. this Blog is still in development, because I started my React/Node.js/Typescript journey couple days ago, even JS is new for me 😄 Now I know, that learning GraphQL in totally new technologies is really challenging 🤦‍♂️

Read more comments on GitHub >

github_iconTop Results From Across the Web

Best practices for REST API design - Stack Overflow Blog
In this article, we'll look at how to design REST APIs to be easy to understand for anyone consuming them, future-proof, and secure...
Read more >
Potential hooks API design · Issue #1179 · reduxjs/react-redux
Let's use this thread to discuss actual design considerations for an ... state mapping hook that does not subscribe to store changes at...
Read more >
A Framework For Our All Day API Discussion - API Evangelist
What Is API? - Discuss your overall web strategy, and discuss how your API operations will augment, complement, and extend your web presence....
Read more >
Design-First Approach to API Development: How to Implement ...
Let's start with the most valuable API development asset: developers. Improved Developer Experience: There are numerous benefits to the Design- ...
Read more >
Official API Design Guide - Stoplight
Learn all there is to know about our API designs through our comprehensive guides, including the basics, API tooling, and OpenAPI Specification.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found