Like you were calling a function locally
// Server function sum(a, b) { return a + b } // Client const result = await sum(5, 5) console.log(result) // 10 Old style using Promises
// Client sum(5, 5).then(result => { console.log(result) // 10 }) You can pass or recive any valid JSON value
// Server function sum({ a, b }) { return { result: a + b } } // Client const { result } = await sum({ a: 5, b: 5 }) console.log(result) // 10 Remote Procedure Calls are the funniest part of this protocol because functions are created dynamically. Which means we can call a remote function and pass a local one as an argument.
// Server function square(n, callback) { callback(n * n) } // Client square(5, result => { console.log(result) // 25 }) This will work as expected, but is a bad pattern. Because we are creating a new function every time we call square. Instead we should do something like this to create only one function on server.
// Server function square(n, callback) { callback(n * n) } // Client function callback(result) { console.log(result) // 25 } square(5, callback) We can throw an error. And catch it on the client.
// Server function login(email, password) { if (email === 'johndoe@mail.com' && password === '1234') { return true } else { throw 'Invalid login' } } // Client try { const isLogged = await login('wrong', 'wrong') } catch (message_error) { console.error(message_error) // > 'Invalid login' } If the error throwed is instance of
Errorwill be a normal error on server instead of throwing it to the client.
When calling a remote function, the last argument is always a deferred promise.
// Server function login(email, password, ...args) { const request = args[args.length - 1] setTimeout(() => { if (email === 'johndoe@mail.com' && password === '1234') { request.resolve(true) } else { request.reject('Invalid login') } }, 1000) // We must return request to make this function asynchronous return request } Or you can use your own Promise
function login(email, password) { return new Promise((resolve, reject) => { setTimeout(() => { if (email === 'johndoe@mail.com' && password === '1234') { resolve(true) } else { reject('Invalid login') } }, 1000) }) } Dop does not handle authentication because not all situations needs it. But when we have the typical Server-Client architecture most of the time we need to know what client is calling our functions on server.
When a function is being called remotely the last argument is a Promise instance with an extra property named node. Which is the node that is calling the function. Is the same instance/object that we got using createNode.
// Server function login(email, password, ...args) { const { node } = args[args.length - 1] }