Closed mattkrick closed 8 years ago
I like this. The trick is going to be how to allow a developer to follow the thread all the way round (subscription creation->mutation->publish->subscriber), but I trust you'll be able to do that.
I love that this minimizes payloads.
I also prefer the forceFetch
pattern, it is more expression and – importantly – more obvious.
in my head, it goes like this:
presence
subscription, Terry is already subscribedmutate(changeAvatar)
, the resolve
for that mutation tries to publish to the presence/:teamId
presence
subscriber listens for that & requeries accordinglyThe thing I don't like about it is that we're essentially using the presence
subscription because it's there. There is no really good reason we don't use the subscriber
for meeting, only that we are doing a lot of non-GraphQL stuff in the presence
one.
Maybe it makes sense, since every developer will have at least 1 sub that listens for changes, otherwise they'd have to just put everyone on the same channel & blast changes all around, leaving it up to the socket PUBLISH_OUT middleware to block.
closed by writing recipes for subscriptions
Per https://github.com/ParabolInc/action/issues/121:
TeamMember, CachedUser, UserProfile
.Terry
. The server queries Terry's data from 3 separate tables (TeamMember, CachedUser, UserProfile
) & returns the result.changeAvatar
mutation publishes a message{user: 'terry', type: 'changeAvatar'}
to thepresence/:teamId
channel, which may or may not be empty.presence
has logic that triggers a requery of the data:cashay.query(foo, {forceFetch: true})
.This presents the problem of performing a full requery instead of a query of just the parts we need. We could solve this in 2 ways:
avatar
field from the state & delete the cached response. This will cause cashay to create a minimized query included only the avatar field. It can be easily done by performing alocalOnly
mutation that removesavatar
from the state.forceFetch
a new query that only wants one field: avatar. With either case, cashay is sending off the same query. The question is, which one is more maintainable? To write logic that deletes something from our current state, or to write logic that wants to add something to our current state?Ideally, the pattern I want to achieve is a multi-user mutation. Currently, when I call a mutation, it mutates the data & gives me a mutation payload. I want to give this same payload to everyone in the same channel. The challenge is that they currently aren't expecting this & don't know what to do with it when they get it.
I see 2 ways to handle this:
localOnly
mutation that deletes theavatar
field from the state. Then, we the query gets triggered, it'll see that it's missing, minimize the server query to only fetch the avatar field, and patch it in.forceFetch
only theavatar
field.I think I like the latter because it's a little more expressive. When I get a tip that the
avatar
field has changed for someone, I should ask (read "query") for a new version, not mutate my local copy so the requery happens behind the scenes.This pattern could open up the door to having the client write custom queries (eg pass in fields that you want to fetch & dynamically create an AST which turns into a query string). In Relay, these queries are regarded as static strings that are babelfied before being sent to the client in order to avoid having to send GraphQL + the client schema down. Cashay doesn't have the same constraint, so it might make for a really powerful pattern that hugely differentiates cashay from Relay, or it could be an abuse of power.