xaviergonz / mobx-keystone

A MobX powered state management solution based on data trees with first class support for Typescript, support for snapshots, patches and much more
https://mobx-keystone.js.org
MIT License
551 stars 25 forks source link

Suggested Patterns for Middlewares #500

Open graphographer opened 1 year ago

graphographer commented 1 year ago

I've been refactoring a rather large part of our codebase to use Mobx Keystone, and (hopefully) some modified form of Domain Driven Design on the client side and server. Although the Client/Server example given in the documentation is very helpful, I'm having difficulty understanding exactly how it might be applied to some of our use-cases, or whether it was never intended to be used in these particular ways.

Specifically, I want to use our websocket connection to both provide hydrated models to the client side, while possibly formalizing that initial fetch in terms of Mobx Keystone models. The documentation makes it clear that the intended use of onActionMiddleware is mainly to replicate actions remotely: that is, to create/modify models elsewhere and then subsequently synchronize those changes locally.

Is there a possible or recommended pattern for using any of the middleware functions (like actionTrackingMIddleware) to essentially call back-end services in order to return model data to the client? Models wouldn't be created or modified on the server, but rather, the server would simply return model snapshots to the client.

So, for example, instead of doing something like myNetworkTransportInterface.fetch('myModels') it's more like 'myDomainModel.fetchAction('myModels')` and that's intercepted by an action middleware at the application layer which passes it to the server via a websocket or http request. The serialized form of that action is then run on a Mobx Keystone model on the server which is designed really only to return data (like a controller for a GET request).

Sorry if this is unclear, I may really be asking for a new feature or design paradigm that Mobx Keystone doesn't provide.

xaviergonz commented 1 year ago

Basically you'd want to do something like this (assuming you want a "pessimistic" model, this is, whenever you do an action you cancel it locally and only replicate it whenever it is sent by the server):

Id you want an "optimistic" model, where you apply local actions directly, without cancelling them, and then possible conflicts are auto-fixed then probably you might have more luck with a Conflict-Free Replicated Data Type (CRDT), such as https://github.com/yjs/yjs or https://automerge.org/

graphographer commented 1 year ago

Thank you for your response. I understand that what you are suggesting is essentially what is given in the "Client/Server" example on the documentation website.

However, my question is whether action middlewares can be used to describe step ii of your points above. That is, I want to avoid having many individual websocket messages for fetching specific data if the Mobx Keystone model actions themselves can do that.

xaviergonz commented 1 year ago

there's no Middleware for it, but you can just use getSnapshot and fromSnapshot

graphographer commented 1 year ago

Now that I've been working for a few weeks with remotely replicating action calls, I have a bit of a better conceptual grasp of how Keystone works more generally.

So my new question is this: Is there a straightforward way to "extract" the return value of a serialized action call result? That is, can I have a client send a sort of serialized standalone action to the server and parse the serialized response action (that is, as an alternative to getSnapshot for example)?

I do sense that I'm simply asking for non-existent features, so do not worry about disappointing me :) Thank you so much for all the great work you have put into Keystone.

xaviergonz commented 1 year ago

applyAction should return any value that might be returned from the action call being called

xaviergonz commented 1 year ago

or returnValue inside the object returned by applySerializedActionAndTrackNewModelIds / applySerializedActionAndSyncNewModelIds