Skip to content

Instantly share code, notes, and snippets.

@andywer
Last active August 26, 2016 22:27
Show Gist options
  • Save andywer/cc47bf3cc8a230784ed0629251771682 to your computer and use it in GitHub Desktop.
Save andywer/cc47bf3cc8a230784ed0629251771682 to your computer and use it in GitHub Desktop.
Idea: Make REST communication as easy as a function call

Passway - Make REST communication as easy as a function call

What is this about?

  • Make message passing using REST as easy and convenient as possible
  • Convention over configuration for the basics, middleware concept for more powerful stuff
  • Make it easy for people to design software in microservices and provide open APIs

Sample shows code of a small demo page for doing a simple mathematical addition of two numbers (method calculation). Calculation is done on the server.

Client

const api = passway
  .connectTo('http://localhost:3000/api/')
  .use(passwayMiddlewares.HttpOptions({
    Authentication: {
      user: 'demo',
      password: 'demo'
    }
  }))

const calculate = api.action((num1, operator, num2) =>
  api.request('GET /calculate?num1={num1}&num2={num2}&operator={operator}', { num1, num2, operator })
)
// - or -
const calculate = api.action((num1, operator, num2) =>
  // `api.request`knows that the object describes the request body, not the query params,
  // since there are no query params
  api.request('POST /calculate', { num1, num2, operator })
))

async function onClick () {
  try {
    const calculated = await calculate(input1.value, '+', input2.value)
    result.textContent = calculated
  } catch (error) {
    result.textContent = error.message
  }
}

const input1 = document.querySelector('form .number1')
const input2 = document.querySelector('form .number2')
const submit = document.querySelector('form *[type=submit]')
const result = document.querySelector('form .result')

submit.addEventListener('click', onClick)

Server

const app = express()
const api = passway.serve(app)

api.on('GET /calculate?num1&num2&operator', ({ num1, num2, operator }) => {
  // function may return a Response object or something else that will be JSON-encoded
  // function may be async (return promise)
  if (operator === '+') {
    return num1 + num2
  } else {
    throw new Error('Unhandled operation.')
  }
})
// - or -
api.on('POST /calculate', ({ num1, num2, operator }) => {
  // First param passed is the parsed body, since there are no query params
  // (otherwise query params object as 1st param, parsed body as 2nd param)
  ...
})

Or just use zeit/micro.

Why?

We are right in the middle of a paradigm shift. We don't write big monolithic enterprise software anymore, we want to create bunches of small, loosely coupled microservices instead.

Not only do they scale better, but thinking in small self-contained services usually leads to cleaner interfaces to the outside world, reduces the necessary scope of the engineer during development and can strongly simplify handling legacy code or migrating to alternative software gradually.

So if it brings so many benefits why don't we all just write microservices? I think in many (maybe most) cases there is a straight-forward reason:

Because network communication means more implementation work, so we tend to limit it to a minimum. And especially if you have many tiny services you have to care for communication many tiny times.

Still figuring out

  • Pagination out of the box (?)
    • Maybe: Provide for Observables
  • Server-side: How to specify status code (when throwing an Error or if successful)
    • Maybe provide different REST Errors or use restify-errors
    • If successful: Possible solution: Need to return Response for setting status !== 200
  • Websocket adapter (request-response is fine for many use cases, but e.g. querying large collections of items will be less efficient than with a pub-sub approach)
  • Make it easy to deploy multiple microservices to cloud (zeit.co's now for instance)
    • Easily deploy multiple microservices at once
    • Let these services find each other easily
    • Must be super easy to run them locally as well as deploying them to the cloud
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment