最近一直在學習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...
未完待續……