You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository has been archived by the owner on May 21, 2024. It is now read-only.
It would be great to come up with common contracts for adapters and their clients.
Here's common logic, that relates to all transports:
Client make calls to the server via RPC.
Server handle client's RPCs by declareProcedure handlers and replies with the result.
This is nice workflow, because it provides clear and easy way for client and server to communicate in request-response manner. But in this case only client initiate a communication, which is not suitable for "real-time" applications. So, there's definitely a necessity for a server to be able to send some events to a client.
declareProcedure({handle: ({ client })=>{client.send('some server event')return'RPC reply'},})
with something like client interface it would be possible to isolate underlying transport implementation, so application code does not rely on actual transport. The only thing it should know, is that there's a client, and it possible to send some event.
But that comes with the problem, that some transports could be used for bi-directional communication, but some couldn't. HTTP does not support bi-directional communication, so server won't be able to send anything, except a response to that particular call.
id - client's unique identifier. E.g, for HTTP it would be id of a particular request; for websockets, it will be id of a particular websocket connection; etc..
send - method to send event to the client by server. Responds with boolean to indicate whether that event was successfully sent
data - application-related data to assign/attach to a client. It could be anything, like some auth info, application user's data, etc
Example for HTTP client provider:
// this is the only provider that application will have to adjust if the transport has changed// so the rest of the application just end up working flawlesslyconstclientDataProvider=declareClientDataProvider((ctx,transportData: any)=>{const{ cookie, authorization }=transportData.headersconstuserToken=getUserTokenFromCookie(cookie);// something like machine-to-machine communication, if you app is also supports not just only real users, but also other type of clients, e.g other servicesconstm2mToken=getM2MTokenFromHeader(authorization)return{ userToke, m2mToken }})
transportData - some data from underlying transport, so application could handle transport specific things if needed, e.g cookie for HTTP transport. This is the only thing, that could not be isolated, and application will have to handle it properly by itself.
Then it could be implemented like the following:
// for procedures that work with actual real usersconstuserProvider=declareProvider(async({ client, injections })=>{const{ db }=injectionsconst{ userToken }=client.dataif(!userToken)returnnullreturnawaitdb.getUserByToken(token)},{// like some db connection injection...})
// for procedures that communicate with other servicesconstclientProvider=declareProvider(({ client })=>{const{ m2mToken }=client.datareturngetM2MClient(m2mToken)})
In the end this will allow to create application with both monolith and microservices architectures, that are able communicate with each other, as well as with real users. And at the same time be completely transport-agnostic, so it can be swapped without any impact on the application code and businness logic.
The text was updated successfully, but these errors were encountered:
It would be great to come up with common contracts for adapters and their clients.
Here's common logic, that relates to all transports:
declareProcedure
handlers and replies with the result.This is nice workflow, because it provides clear and easy way for client and server to communicate in request-response manner. But in this case only client initiate a communication, which is not suitable for "real-time" applications. So, there's definitely a necessity for a server to be able to send some events to a client.
with something like
client
interface it would be possible to isolate underlying transport implementation, so application code does not rely on actual transport. The only thing it should know, is that there's aclient
, and it possible to send some event.But that comes with the problem, that some transports could be used for bi-directional communication, but some couldn't. HTTP does not support bi-directional communication, so server won't be able to send anything, except a response to that particular call.
Proposed interface for server-side
Client
:id
- client's unique identifier. E.g, for HTTP it would be id of a particular request; for websockets, it will be id of a particular websocket connection; etc..send
- method to send event to the client by server. Responds withboolean
to indicate whether that event was successfully sentdata
- application-related data to assign/attach to a client. It could be anything, like some auth info, application user's data, etcExample for HTTP client provider:
transportData
- some data from underlying transport, so application could handle transport specific things if needed, e.g cookie for HTTP transport. This is the only thing, that could not be isolated, and application will have to handle it properly by itself.Then it could be implemented like the following:
In the end this will allow to create application with both monolith and microservices architectures, that are able communicate with each other, as well as with real users. And at the same time be completely transport-agnostic, so it can be swapped without any impact on the application code and businness logic.
The text was updated successfully, but these errors were encountered: