Introducing Hapi Web Service

I spent a certain amount of time during the last 14 months working on web services, whether it is RPC-like web services or RESTful WSes. I’ve recently started to work, for the purpose of a services computing class (CS459) here at KAIST, on another web service architecture - written in JavaScript, as part of my experimentations with Node. Hapi had nice features and extensions for building lightweight servers, so I went with this tech to start building it.

However, I realised that although Hapi was built in the objective of serving APIs (even though it can also render templates), several features were lacking to accelerate web services development. Notably, there is no web services description automation, generic error handling, common communication language, access protection…

That’s why I started building Hapi Web Service, that aims at providing an efficient framework for completing those issues. The package is still at its early stages, but here is how you can build an easy JSON RPC web service with HWS:

'use strict'

const Hapi = require('hapi')
const hws = require('hapi-web-service')
const Joi = require('joi')

const server = new Hapi.Server()
server.connection({ port: 3000 })

// Our web service's objective is responding with the list of users:
const users = [{
  name: 'Johnny Appleseed'
}, {
  name: 'Kim Minjun'
}, {
  name: 'John Smith'
}]

// We define the keys and their level of access:
const accesses = {
  iamasecretkey: 'none',
  iamamoresecretkey: 'all'
}

// Creating a service
let userService = new hws.Service('users')

// Creating an authRequirement for a route allowing to get all the users
let getAuthRequirement = new hws.basicAuthRequirement()
getAuthRequirement.check = function (args, session, callback) {
  if (args.key) {
    // If there's a key, we'll check if this key has access
    if (accesses[args.key] === 'all') {
      callback(null, new hws.Grant(hws.grantTypes.granted))
    } else {
      callback(null, new hws.Grant(hws.grantTypes.refused))
    }
  } else {
    callback(null, new hws.Grant(hws.grantTypes.notConnected))
  }
}

// Creating a method for this service
let getUsersNamesMethod = new hws.Method('getUsersNames',
  // input validation object
  Joi.object().keys({
    name: Joi.string().alphanum()
  }),
  // output format
  Joi.array().items(Joi.string().alphanum()),
  // method handler
  function (args, session, callback) {
    if (args.name) {
      // If the request has a name parameter, we'll filter based on this string
      callback(null, users.filter((user) => { return user.name.indexOf(args.name) !== -1 }).map((user) => { return user.name }))
    } else {
      // Otherwise, we won't filter
      callback(null, users.map((user) => { return user.name }))
    }
  },
  // HTTP method
  'GET',
  // auth requirement
  getAuthRequirement
)

// Registering the method to the service
userService.registerMethod(getUsersNamesMethod)

// Adding the service to the server
userService.registerToServer(server)

server.start((err) => {
  if (err) {
    throw err
  }
  console.log('Server running.')
})
// The service is now available at /users/getUsersNamesMethod and the route is controlled.

We’ve just built a web service called users, with a method getUsersNames only accessible giving a certain key as a parameter, with HTTP error handling (thanks to the great Boom package) and JSON input and output.

This is still an early release, without extensive testing and WSDL features. Please feel free to contribute via pull requests or issues on the GitHub repo!

 
0
Kudos
 
0
Kudos

Now read this

Quick AES encryption and decryption

For situations when Keybase is not an option. Should work on Ubuntu. Generate a AES key Choose a unique passphrase, <passphrase>. openssl enc -aes-128-cbc -k <passphrase> -P -md sha1 Keep the iv and key values in the $IV and... Continue →