You can use graphql subscriptions (see apollo docs for details).
At start query for current state. Both sides (server and client) will have equal data. Both can use the same lib, f.e. immutable.js
Client invokes subscription, starts to listen to 'onListChange' messages.
On server insertElement
, removeElement
, updateElement
resolvers are doing the same:
- processes mutation on backend state;
- encodes
insert
(or remove
or update
) as actionType
and required data (mutation arguments, newly created id, version number) as payload
;
- sends this ('onListChange') message to subscribers using publish.
Client:
- receives a message;
- decodes message and updates/mutates own state (processes the same mutation as on server);
- updates local version number.
As the result client should have the same state.
Client can detect missing messages (version numbers passed within payload compared with local version indicator) and force [re-]query for current(entire) state.
Update
If server side changes:
- are not driven by mutations (f.e. other app operates on the same db);
- are not a stream of changes but simply new states (new state just arrives/is read from external source);
... - you don't have a chance to inject your logic into process applying change - you should have a running monitoring process to:
- detect state changes;
- convert state differences into set of 'patches' (f.e. using jiff);
- publish patches as message to subscribers.
Client decodes (messages are a stream of) patches into mutations of local state (to be in sync with server state) as earlier. As above - apply changes if versions matches or requery entire state.
Graphql is only a communication channel (queries, messages) - it has nothing to processes (and data, on both sides) needed for this task.