Magic Bridge lets you call functions on a Node.JS server from a client, abstracting away HTTP.
Register a function on the server:
constnewBridge=require('@magic-bridge/bridge')// import bridge from '@magic-bridge/bridge'constbridge=newBridge()// register functions (or classes)bridge.register(functiongetServerThing(){return'i am a string from server'}// use with express constapp=express()app.use('/jsonrpc/default',bridge.middleware())Now you can call it from the client:
constbridge=require('@magic-bridge/client')// import bridge from '@magic-bridge/client'constbridge=newBridge()// call a function on the server!constthingFromServer=awaitbridge.getServerThing()// thingFromServer === 'i am a string from server'At your server:
npm install @magic-bridge/bridge
At your client:
npm install @magic-bridge/client
- Create a bridge instance
- Registering functions
- Using middleware with Express
- Multple bridges
- Local arg resolvers
The Magic Bridge module exports a factory function for making new bridges both on the client and the server. The server optionally accepts some advanced options:
constnewBridge=require('@magic-bridge/bridge')constbridge=newBridge()// orconstbridge=newBridge(opts)| Option | Description | Type | Default |
|---|---|---|---|
ignoreMethodNameRegex | Functions registered that match this regex will be ignored. Such as methods on a class starting with an underscore to denote that they are private | regex | /^_/ |
throwOnDup | Will throw an error if more than one function is added with the same name | boolean | true |
The client accepts one optional arguemnt; the url/path of the Magic Bridge middleware
constnewBridge=require('@magic-bridge/client')constbridge=newBridge()// uses /jsonrpc/default// or constbridge=newBridge('/my-magic-bridge-url')the client bridge is now ready to call functions on the server:
// bridge calls must always be asyncconstthingFromServer=awaitbridge.doServerThing()Magic Bridge provides a few ways of registering functions via register():
bridge.register(functionfunc(){ ... })// client: await bridge.func()constobj={x: 99,func: function(){returnthis.x}}bridge.register(obj.func,obj)// client: await bridge.func() --> 99bridge.register('myFunc',()=>{ ... })// client: await bridge.myFunc()constobj={x: 99,func: function(){returnthis.x}}bridge.register('myFunc',obj.func,obj)// client: await bridge.myFunc() --> 99This is quite handy, espcially in combination with multiple bridges
classClazz{myMethod(){return99}anotherMethod(){return88}}constclazz=newClazz()bridge.register(clazz)// client: await bridge.myMethod() --> 99// client: await bridge.anotherMethod() --> 88This is quite handy, espcially in combination with multiple bridges
constobj{myFunction(){return99}anotherFunction(){return88}}bridge.register(obj)// client: await bridge.myFunction() --> 99// client: await bridge.anotherFunction() --> 88Magic Bridge is designed to be used as Express middleware. The default path used by
the client is /jsonrpc/default, so the default set up is to do this:
constapp=express()app.use('/jsonrpc/default',bridge.middleware())If you do use a different path, you must also configure the bridge side on the client to use it:
// client side:constbridge=newBridge('/my-magic-bridge-path')You can create multiple bridge instances in a single application, this useful for two main reasons:
- It acts as a namespace for classes or collections of related functions
- Registered functions/methods requiring different credentials can be used as separate middleware
constnewBridge=require('@magic-bridge/bridge')constauth=newAuth();constaccount=newAccount()constauthBridge=newBridge()constaccountBridge=newBridge()app.use('/jsonrpc/auth',authBridge.middleware())app.use('/jsonrpc/account',ensureLoggedIn(),accountBridge.middleware())and on the client:
constnewBridge=require('@magic-bridge/client')constauthBridge=newBridge('/jsonrpc/auth')constaccountBridge=newBridge('/jsonrpc/account')awaitauthBridge.login()awaitaccountBridge.changeUsername()Functions on the server can be injected with request, response, request.session and request.cookie arguments that
are invisible to the client.
Use arguments with these method names in any postion to have them injected:
| Argument | Resolves to |
|---|---|
_request_ | The (express) request object |
_response_ | The (express) response object |
_session_ | The (express) request session object (if using express-session middleware |
_cookies_ | Parsed request cookies |
Examples:
functionchangeUsername(_session_,newUsername){constuser=db.getUser(_session_.userId)user.setUsername(newUsername)...}functionchangeUsername(newUsername,_cookies_){constuser=db.getUser(_cookies_.token)user.setUsername(newUsername)...}Magic Bridge is inspired by JSON-RPC-Java (later renamed Jabsorb) a library I used circa 2006-8 to do Ajaxy stuff.
Magic bridge partially implements the JSON-RPC 2.0 specification (it doesn't do batches)