Using Hapi to develop RESTful APIS is very rare. Some community introduction parts are no longer applicable in the new version. There are many changes in the new version

What is theRESTful API

REpresentational State Transfer REpresentational State Transfer

Can refer to the following understanding:

  • Understand itself REST architectural style: www.infoq.com/cn/articles…

  • Understanding a RESTful architecture: www.ruanyifeng.com/blog/2011/0…

  • Restful API design guidelines: www.ruanyifeng.com/blog/2014/0…

Hapi

Hapi is a Web framework for Node.js, which is a framework for building rich applications and services. Currently, Hapi V17 supports only Node V8.9.0 or later

  • Understand: Node.js performance comparison of Hapi – Express-Restify-KOA

Hapi features

  • Authentication and authorization: Built-in authentication and authorization scheme
  • Caching: Provides client and server caching, catbox
  • Route: built-in route
  • Validation: Use Joi
  • Cookies: Provides configuration options for handling Cookies
  • Log: Built-in logging
  • Error handling: BOOM
  • Process monitoring: hapi plugin good

Requirements for using Hapi

  • Install Node.js v8.9.0 or later
  • Install the mongo
  • Familiar with database concepts and JavaScript application knowledge

New changes to Hapi V17

  • The server.connection method has been removed and is now in use

    const server = new Hapi.Server({
        host: 'localhost',
        port: 3000
    })
    Copy the code
  • Enable or disable the service method is completely asynchronous without callback

    try {
        await server.start()
    }
    catch (err) {
        console.log(err)
    }
      
    try {
        await server.stop()
    }
    catch (err) {
        console.log(err)
    }
    Copy the code
  • The reply() callback method is removed, and the response.hold() and Response.resume () methods are no longer available

    // Previous const handler =function (request, reply) {
      return reply('ok'); }; // Now const handler =function (request, h) {
      return 'ok';
    };
    Copy the code

    More examples of using h are as follows:

    const handler = (request, h) => {
      // return a string
      return 'ok'
    
      // return an object and hapi creates JSON out of it
      return { name: 'Authentication Library', library: true }
    
      // redirect to 404
      return h.redirect('/ 404') / /return a view
      return h.view('index', { name: 'Authentication Library' })
    
      // use the "h" response toolkit to create a response
      return h
       .response(thisHTML)
        .type('text/html')
        .header('X-Custom'.'my-value')
        .code(201)
    }
    Copy the code
  • Three request event types: REQUEST, request-interval, and request-error are combined into a single request event

  • Triggered methods like server.on, request.on, and Response.on are replaced with server.events.on(), request.events.on(), and response.events.on()

  • New request extensions:

    server.ext('onPreAuth', (request, h) => {... }) server.ext('onCredentials', (request, h) => {... }) server.ext('onPostAuth', (request, h) => { … }) ]
    Copy the code
  • Replace config with options when defining routes

    server.route({
      method: 'POST',
      path: '/'Options: {... }})Copy the code
  • Plugins currently in use

    exports.plugin = { register, name, version, multiple, dependencies, once, pkg }
    Copy the code

See GitHub’s full update log for more details

Topic: Build a simple API using Hapi

The CURD operation is provided in this example

  • Get all demos – GET /demos
  • Get one demo – GET /demo/11
  • Create a demo – POST /demos
  • Edit a demo – PUT /demos/11
  • Delete a demo – DELETE /demos/11

A demo has the following properties:

  • name
  • age

1 Create project directory demo. The final structure is as follows:

Demo ├ ─ ─ package. Json ├ ─ ─ for server js ├ ─ ─ the gitignore (optional) └ ─ ─ the SRC ├ ├ ─ ─ controller | └ ─ ─ test. The js └ ─ ─ ─ models └ ─ ─ test. JsCopy the code

2 write the model

src/models/test.js
'use strict';

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const demoModel = new Schema({
  name: { type: String, required: true, index: { unique: true } },
  age: { type: Number, required: true}}); module.exports = mongoose.model('Demo', demoModel, 'demos'); 
Copy the code

Write the controllers

src/controllers/test.js

var Demo =  require('.. /models/test');

/**
 * List Demos
 */
exports.list = (req, h) => {
  return Demo.find({}).exec().then((demo) => {

    return { demos: demo };

  }).catch((err) => {

    return { err: err };

  });
}

/**
 * Get Demo by ID
 */
exports.get = (req, h) => {

  return Demo.findById(req.params.id).exec().then((demo) => {

    if(! demo)return { message: 'Demo not Found' };

    return { demos: demo };

  }).catch((err) => {

    return { err: err };

  });
}


/**
 * POST a Demo
 */
exports.create = (req, h) => {

  const demoData = {
    name: req.payload.name,
    age: req.payload.age
  };

  return Demo.create(demoData).then((demo) => {

     return { message: "Demo created successfully", demo: demo };

  }).catch((err) => {

    return { err: err };

  });
}

/**
 * PUT | Update Demo by ID
 */
exports.update = (req, h) => {

  return Demo.findById(req.params.id).exec().then((demo) => {

    if(! demo)return { err: 'Demo not found' };

    demo.name = req.payload.name;
    demo.breed = req.payload.breed;
    demo.age = req.payload.age;
    demo.image = req.payload.image;

    demo.save(dogData);

  }).then((data) => {

      return { message: "Demo data updated successfully" };

  }).catch((err) => {

      return { err: err };

  });
}

/**
 * Delete Demo by ID
 */
exports.remove = (req, h) => {

  return Demo.findById(req.params.id).exec(function (err, demo) {

    if (err) return { dberror: err };
    if(! demo)return { message: 'Demo not found' };

    demo.remove(function (err) {
      if (err) return { dberror: err };

      return { success: true };
    });
  });
}
Copy the code

Write server. Js

'use strict';

const Hapi = require('hapi');
const mongoose = require('mongoose');
const DemoController =  require('./src/controllers/test');
const MongoDBUrl = 'mongodb://localhost:27017/demoapi';

const server = new Hapi.Server({
  port: 3000,
  host: 'localhost'
});

server.route({
  method: 'GET',
  path: '/demos',
  handler: DemoController.list
});

server.route({
  method: 'GET',
  path: '/demos/{id}',
  handler: DemoController.get
});
server.route({
  method: 'POST',
  path: '/demos',
  handler: DemoController.create
});

server.route({
  method: 'PUT',
  path: '/demos/{id}',
  handler: DemoController.update
});

server.route({
  method: 'DELETE',
  path: '/demos/{id}',
  handler: DemoController.remove
});

(async () => {
  try {  
    await server.start();
    // Once started, connect to Mongo through Mongoose
    mongoose.connect(MongoDBUrl, {}).then(() => { console.log(`Connected to Mongo server`) }, err => { console.log(err) });
    console.log(`Server running at: ${server.info.uri}`);
  }
  catch (err) {  
    console.log(err)
  }
})();
Copy the code

Test the API

Use the postman test at http://localhost:3000/demos

  • demo

Adding authorization authentication

At present, there are a lot of steps, and you still need to register a platform, so I won’t go into details

reference

  • GitHub:github.com/hapijs/hapi
  • website: hapijs.com/
  • Issue:github.com/hapijs/disc…
  • developing-restful-apis-with-hapi v17
  • Github.com/hapijs/hapi…

For learning and communication only