最近一直在学习hapiJs,有点koa2的基础觉得会容易呢,可是全英文的API,不一样于koa2的实现方式,看起来大写的懵啊,整理此文,但愿可以帮助到一些想要入门hapi的新人。html
1.1 首先咱们建立一个目录‘hapiDemo’做为项目目录,输入命令:node
makdir hapiDemo。
1.2 打开项目目录,初始化,命令以下:mysql
cd hapiDemo, 初始化:npm init,
1.3 项目基础配置:git
安装hapi: npm install --save hapi;
项目使用了ES6语法安装babel: npm intall --save hapi;
npm start默认是的启动文件是sever.js,本项目是index.js,修改启动命令,程序员
下文中仍是用了一些插件,请自行安装。github
1.4 初始化并安装hapi是第一步,hapiDemo 项目的基础项目结构以下图:web
这些文件的做用是:sql
config:配置文件目录,db_config:数据库的配置信息,plugin_config:注册插件的相关信息数据库
controllers:controllers下是业务逻辑npm
models:model 层
public:静态文件
routes:路由信息
log:日志信息
index.js:项目启动入口文件
server.js:服务配置信息
2.1 建立启动服务配置文件server.js,输入一下代码:
const Hapi = require('hapi'); //Create a hapi server var server = new Hapi.Server(); /**************server config********/ let connectionOptions={ port: 3333, host: 'localhost' }; server.connection(connectionOptions); // Export the server to be required elsewhere. module.exports = server;
2.2 配置完服务文件,如今咱们来启动服务,先新建一个index.js文件:
const server=require('./server'); server.start(err=>{ if(err) throw err; console.log( `Server running at: ${server.info.uri}`); }); 输入node启动命令:npm start 将会显示:Server running at: http://localhost:3333。OK,项目启动成功。 咱们在浏览器中输入url:http://localhost:3333,
找不到路由。
3.1 将路由文件放在routes文件夹里,咱们将建立多个路由,分模块建立,首先修改server.js文件,新增以下代码:
const route=require('./routes'); // Add the server routes route.forEach(function(api){ server.route(api); });
在routes新建index.js,每新增一个路由文件,在index.js文件中引入。
module.exports=[ require(__dirname+'/helloWorld.js'), require(__dirname+'/login.js'), require(__dirname+'/file.js'), require(__dirname+'/auth.js') ]
3.2 定义路由须要三个基础元素:path,method,handler。Methods的选项能够是任何有效的HTTP方法,也能够是方法数组。path选项必须是字符串,尽管它能够包含命名参数。若要在路径中命名参数,只需用{ }将其包装。handler选项是一个函数,它接受两个参数:request和request。
在routes里新建一个helloWorld.js:
let index={ method: 'GET', path: '/', handler: function(request, reply){ reply('hello,world'); } }; let hello={ method: ['GET', 'POST'], path: '/hello/{user?}', handler: function (request, reply) { reply('Hello ' + encodeURIComponent(request.params.user) + '!'); } }; module.exports=[index,hello];
保存重启服务,在浏览器中访问,显示以下:
更多用法请查看api:https://hapijs.com/api#route-...
通常在nodeJS中,咱们加载一个插件,安装后使用require 插件名称就OK了,可是在hapiJS中,须要经过server.register()方法引入。
如下文中使用处理静态文件的插件 inert 举例:
server.register(require('inert'), (err) => { if (err) { console.error('Failed to load a plugin:', err); } });
但不是全部的插件都须要使用server.register()引入,直接使用require便可。
为何使用server.register()引用,我至今不是很清楚。
在本项目中,我把全部的插架配置放在了config/plugin_config.js中:
const SwaggerOptions = { info: { 'title': 'hapiDemo API Documentation', 'version': '0.0.1' } }; const goodOptions = { ops: { interval: 1000 }, reporters: { myConsoleReporter: [{ module: 'good-squeeze', name: 'Squeeze', args: [{ log: '*', response: '*' }] }, { module: 'good-console' }, 'stdout'], myFileReporter: [{ module: 'good-squeeze', name: 'Squeeze', args: [{ log: '*', response: '*' ,request:'*'}] }, { module: 'good-squeeze', name: 'SafeJson' }, { module: 'good-file', args: ['./log/fixtures/awesome_log'] }], myHTTPReporter: [{ module: 'good-squeeze', name: 'Squeeze', args: [{ error: '*' }] }, { module: 'good-http', args: ['http://prod.logs:3000', { wreck: { headers: { 'x-api-key': 12345 } } }] }] } }; module.exports = [ { register:require('good'), goodOptions, }, { register:require('hapi-auth-jwt2') }, { register:require('inert') }, { register:require('hapi-auth-basic') }, { register:require('./../auth') }, { 'register': require('hapi-swagger'), 'options': SwaggerOptions }, { register:require('vision') } ];
在server.js中:
const plugins=require('./config/plugin_config'); //Register all plugins server.register(plugins, function (err) { if (err) { throw err; // something bad happened loading a plugin } });
5.1 在Web应用程序中,不可避免地,须要提供一个简单的文件,图片或者静态html。在hapi 中使用 inert 插件来处理静态文件。
npm install --save inert
在routes文件夹中建立一个file.js:
let static={ method: 'GET', path: '/staticFile', handler: function (request, reply) { reply.file('./public/static.html'); } }; module.exports=static;
在public文件夹下新增一个static.html的文件,内容随意。保存而后运行。
5.2 hapi 能够使用模板渲染,hapi默认使用的是handlebars,要开始视图,首先咱们必须在服务器上配置至少一个模板引擎。这是经过使用server.views方法作的,修改server.js文件:
server.register(plugins, function (err) { server.views({ engines: { 'html': { module: require('handlebars') } }, relativeTo:__dirname, path:'public/templates' }); if (err) { throw err; // something bad happened loading a plugin } });
加载 vision 插件,它增长了模板渲染支持哈啤。
更多配置项:https://hapijs.com/tutorials/...
渲染势图,在file.js文件中新增路由:
let temp={ method: 'GET', path: '/view', config: { auth: false, handler: function (request, reply) { reply.view('login'); } } }; module.exports=[static,temp];
login的内容自行填充
在web应用程序中,咱们可能写特别多数据库访问层的代码,数据库保存,删除,读取,那hapi如何访问数据库呢?本demo以MySQL为例。
不懂数据库的程序员不是好程序员,可是我早早就把数据库的一点皮毛还给了老师,我选择Node的ORM框架Sequelize来操做数据库。
hapi-sequelize插件对sequelize作了很简单的封装,可是它对Hapi和sequelize的版本有要求,在本项目中没有使用,有兴趣的的能够研究 https://github.com/danecando/...
6.1 在server.js添加代码:
const models=require('./models'); //Connect database var initDb = function(){ var sequelize = models.sequelize; //Determine if the database connection is successful sequelize.sync({force: false}).then(function() { console.log("connection successed"); }).catch(function(err){ console.log("connection failed due to error: %s", err); }); }; initDb();
6.2 使用Sequelize操做MySQL须要先作两件准备工做,
(1)建立一个sequelize对象实例,链接数据库,在models新增index.js,代码以下:
const fs = require("fs"); const path = require("path"); const Sequelize = require("sequelize"); const config = require('../config/db_config'); let db = {}; //建立一个sequelize对象实例,链接数据库 let sequelize = new Sequelize(config.database, config.username, config.password,{ host: config.host, dialect: 'mysql', pool: { max: 5, min: 0, idle: 30000 } }); fs .readdirSync(__dirname) .filter(function(file) { return (file.indexOf(".") !== 0) && (file !== "index.js"); }) .forEach(function(file) { var model = sequelize["import"](path.join(__dirname, file)); db[model.name] = model; }); db.sequelize = sequelize; db.Sequelize = Sequelize; module.exports = db;
db_config文件是数据库的配置信息。
(2)定义模型文件user(在本项目中主要是实现登录),告诉Sequelize如何映射数据库表。
module.exports = function(sequelize, DataTypes) { var User = sequelize.define("User", { id:{ type: DataTypes.INTEGER, primaryKey: true }, user_no:DataTypes.STRING, old_kn_userid:DataTypes.STRING, nickname:DataTypes.STRING, password:DataTypes.STRING, }, { freezeTableName: true, // Model 对应的表名将与model名相同 timestamps: false }); return User; };
更多Sequelize的学习能够参考:https://itbilu.com/nodejs/npm...
6.3 通过配置后,接下来咱们能够在路由handler中使用这个实例啦。
新建一个login.js:
const Joi=require('joi'); const controllers=require('../controllers'); let login2={ method: 'get', path: '/tologin2', config: { validate:{ query: { nickname:Joi.min(6).max(30)required(),//校验 } }, id: 'login2' }, handler: controllers.user.login2, }; module.exports=login2;
joi 是 hapijs 自带的数据校验模块,他已经高度封装经常使用的校验功能,更多用法:https://github.com/hapijs/joi...。
6.4 接下来咱们就要访问数据库啦。
(1)新建index.js
const requireDirectory = require('require-directory'); module.exports = requireDirectory(module);
require-directory的做用是递归遍历指定目录,require()每一个文件,并返回一个包含这些模块嵌套的hash结构。
(2)user.js:
let models=require('../models') module.exports={ login2:function(request,reply){ let userInfo=models.User.findOne({ where:{ nickname: request.query.nickname } }).then(function(result){ let reponseMess={}; if(result!==null){ reponseMess={ code:1, message:'已经在数据库中查询到' } }else{ reponseMess={ code:-1, message:'未已经在数据库中查询到' } } reply(reponseMess); }); } };
简单的demo查询,用户是否已存在
使用hapi写api时,有种代码既文档的感受,并且这些代码也真的能够自动生成swagger文档。
使用hapi插件hapi-swagger,简单配置下插件,先修改下plugin_config.js文件:
const SwaggerOptions = { info: { 'title': 'hapiDemo API Documentation', 'version': '0.0.1' } }; module.exports = [ { 'register': require('hapi-swagger'), 'options': SwaggerOptions }, ];
而后修改/tologin2:
let login2={ method: 'get', path: '/tologin2', config: { auth:false, description: 'Routing with parameters', notes: 'login api', tags: ['api'],//写上这句,开启生成swagger功能 validate:{ query: { nickname:Joi.required(), } }, id: 'login2' }, handler: controllers.user.login2, };
运行,打开 http://localhost:3333/documen...
未完待续……