ทดลองใช้ Hapi.js สร้าง RESTFul API แบบง่ายๆ

ทดลองใช้ Hapi.js สร้าง RESTFul API แบบง่ายๆ Cover Image

ช่วงนี้ผมสนใจงานด้าน Web Development ซะส่วนใหญ่ และก็กำลังหัดเล่นและใช้งาน MEAN Stack ทำให้ตอนนี้มุ่งเน้นไปที่ Node.js Express.js MongoDB ส่วน AngularJS รู้แค่เบสิคๆ และเผอิญได้อ่านข่าว Node.js วงแตก นักพัฒนาหลักแยกตัวเป็น Io.js รวมถึงข่าวนี้อีก TJ Holowaychuk Passes Sponsorship of Express to StrongLoop

ทำให้เริ่มกังวลกับทิศทางในอนาคต แต่ยังไงก็ยังรู้สึกว่า Node.js ก็ยังน่าสนใจและผมก็ยังจะหัดเขียนต่อไป (บอกตามตรง เพราะผมไม่รู้ว่า Node.js กับ io.js มันต่างกันยังไง นี่ซิ) ขอสนุกกับ Node.js ต่อดีกว่า หลังจากลองเล่น Node.js + Express.js ไปซักระยะ ก็เลยอยากลองหา Node.js Framework ตัวอื่นๆดูบ้าง ว่ามันเป็นไง ใช้งานง่ายและยาก รวมถึงเรียนรู้เป็นอย่างไรบ้าง หลักจาก research ดูก็พบว่ามีตัวเลือกที่น่าสนใจจากทั้งหมดเป็น 10 เลยเลือกมาแค่นี้

จริงๆว่าจะลองเล่นทุกๆอันเลย ถ้ามีเวลาว่าง แต่ตอนนี้ขอเลือก Hapi.js ก่อนละกัน หากมีผู้หลงเข้ามาอ่านและใช้งานอยู่ เห็นว่าโค๊ดตรงไหนผิดพลาดหรือผมเข้าใจผิด รบกวนชี้แนะด้วยนะครับ :)

เตรียมความพร้อม

สิ่งที่ต้องมีก็คือ ติดตั้ง Node.js นะครับ หากไม่มีหรือยังไม่รู้จักก็ นี้เลย Node.js

ส่วนด้านล่างนี้คือ รายละเอียด OS เวอร์ชันของ node/npm และ Hapi ณ เวลาที่เขียนนะครับ

  • Ubuntu 14.04
  • Node v0.10.36
  • npm 1.4.28
  • hapi v8.1.0

Step 1 : สร้างโปรเจ็ค

ทำการสร้างโปรเจ็คขึ้นมา ผมทำการสร้างโฟลเดอร์ชื่อว่า hello-hapi จากนั้นก็สร้างไฟล์ package.json ขึ้นมา ดังนี้

mkdir hello-hapi
cd hello-hapi
touch package.json

ไฟล์ package.json ทำการตั้งชื่อโปรเจ็คและเวอร์ชั่น ซะ

{
  "name": "hello-hapi",
  "version": "0.0.1"
}

Step 2 : ติดตั้ง Hapi.js

ต่อมาทำการติดตั้ง hapi.js โดยเลือกติดตั้งแบบ local และเซฟ dependencies เป็นแบบ devDependencies

npm install hapi --save-dev

เมื่อติดตั้ง dependencies ต่างๆเรียบร้อยแล้ว จะมีโฟลเดอร์ node_modules เพิ่มขึ้นมาในโปรเจ็ค ตอนนี้ไฟล์ package.json จะเป็นดังนี้

{
  "name": "hello-hapi",
  "version": "0.0.1",
  "devDependencies": {
    "hapi": "^8.1.0"
  }
}

Step 3 : สร้างไฟล์ app.js

เมื่อติดตั้ง Hapi.js เรียบร้อยแล้ว ต่อมาก็ทำการสร้างไฟล์ app.js ขึ้นมา ไฟล์นี้จะเป็นไฟล์หลักที่ใช้เขียนนะครับ (จริงๆจะตั้งชื่ออะไรก็แล้วแต่ ตามสะดวก จะ server.js , index.js ก็ว่าไป) ซึ่งตอนนี้โปรเจ็คเราจะมีโครงสร้างดังนี้

├── app.js
├── node_modules
│   └── hapi
└── package.json

ทีนี้ไฟล์ app.js ก็ใส่โค๊ดด้านล่างนี้ลงไป

// 1. ทำการเรียกใช้ module hapi
var Hapi = require('hapi');

// 2. สร้างออปเจ็คของ Hapi Server ขึ้นมา โดยใช้ตัวแปร server
// จากนั้นทำการเชื่อมต่อ server ด้วยฟังค์ชัน `connection()` โดยใช้ออปเจ็คที่ระบุคีย์เป็น host และ port
var server = new Hapi.Server();
server.connection({
  host: 'localhost',
  port: 5555
});

// 3. ทำการระบุ route โดยส่งออปเจ็คเป็น arg ที่มีคีย์ดังนี้
// - method : สำหรับระบุ HTTP Method เช่น GET, POST
// - path : เอาไว้ระบุ path URI
// - handler: เป็นฟังค์ชันที่มี 2 parameters คือ request และ reply
// โดย request เป็นค่าที่รับมาจาก user ส่วน reply ก็เป็นเมธอดที่เอาไว้ส่ง response กลับไป
server.route({
  method: 'GET',
  path: '/hello',
  handler: function(request, reply) {
    reply('<h1>Hello Hapi :)</h1');
  }
});

// 4. ทำการ start server โดยสั่ง callback เป็นออปชั่นเสริม เพื่อสั่ง console.log
server.start(function() {
  console.log('Hapi running at: ', server.info.uri);
});

ทดสอบ รันโค๊ดนี้ด้วย

node app.js

และเปิดหน้า localhost:5555/hello/ จะเห็นข้อความว่า “Hello Hapi” :)

Step 4 : ทำ RESTFul API ด้วย Hapi.js

ต่อมา ผมลองทำ RESTFul API ด้วย Hapi.js โดยอ้างอิงจากบทความเก่าที่ผมเคยเขียน มาทำ RESTFul API ด้วย Node.js กับ Express กันดีกว่า เป้าหมายเหมือนกันเลย คือ

  • GET localhost:7777/ : ให้แสดงข้อความต้อนรับ
  • GET localhost:7777/users : ให้แสดงรายชื่อ user ทั้งหมดในระบบ
  • GET localhost:7777/user/:id : แสดงชื่อ user นั้นๆ โดย :id คือ เลข id ของ user
  • POST localhost:7777/newuser : เอาไว้สำหรับส่งค่า POST เพื่อเพิ่มข้อมูล user

ก็เลยใช้ไฟล์ users.js เพื่อเอาไว้แสดงข้อมูลเฉยๆ ไฟล์ที่ได้มีดังนี้

var users = [
    {
        "id": 1,
        "username": "goldroger",
        "name": "Gol D. Roger",
        "position": "Pirate King"
    },
    {
        "id": 2,
        "username": "mrzero",
        "name": "Sir Crocodile",
        "position": "Former-Shichibukai"
    },
    {
        "id": 3,
        "username": "luffy",
        "name": "Monkey D. Luffy",
        "position": "Captain"
    },
    {
        "id": 4,
        "username": "kuzan",
        "name": "Aokiji",
        "position": "Former Marine Admiral"
    },
    {
        "id": 5,
        "username": "shanks",
        "name": "'Red-Haired' Shanks",
        "position": "The 4 Emperors"
    }
];

exports.findAll = function() {
    return users;
};

exports.findById = function (id) {
    for (var i = 0; i < users.length; i++) {
        if (users[i].id == id) return users[i];
    }
};

exports.save = function(user) {
    users.push(user);
}

รายละเอียด อ่านเอาจากบทความเก่านะครับ ไม่ขอพูดถึง

ต่อมา แก้ไขไฟล์ app.js โดยการเพิ่มโมดูล users.js เข้าไปด้วย และจัดการเปลี่ยน route ใหม่ทั้งหมด เป็นดังนี้

var Hapi = require('hapi');
var users = require('./users');

var server = new Hapi.Server();
server.connection({
  host: 'localhost',
  port: 7777
});

server.route({
  method: 'GET',
  path: '/',
  handler: function(request, reply) {
    reply('<h1>Hello Hapi :)</h1');
  }
});

server.route({
  method: 'GET',
  path: '/users',
  handler: function(request, reply) {
    reply(users.findAll());
  }
});

server.route({
  method: 'GET',
  path: '/user/{id}',
  handler: function(request, reply) {
    var id = request.params.id;
    reply(users.findById(id));
  }
});

server.route({
  method: 'POST',
  path: '/newuser',
  handler: function(request, reply) {
    user = {
      id: request.payload.id,
      username: request.payload.username,
      name: request.payload.name,
      position: request.payload.position
    }
    users.save(user);
    reply(user);
  }
});

server.start(function() {
  console.log('Hapi running at: ', server.info.uri);
});

Step 5 : ทดสอบ

  • ขั้นแรกทดสอบด้วยการเข้า http://localhost:7777/users จะต้องแสดงรายชื่อจากไฟล์ users.js ทั้งหมด ดังรูป

Route /users

Note: พอดีว่าผมใช้ Chrome Plugin ชื่อว่า JSONView มันเลยจัดรูปแบบ JSON ให้ดูอ่านง่ายขึ้น เผื่อใครสนใจ ก็ลองไปโหลดดูครับ

  • ทดสอบลองเข้า โดยระบุ user/{id} (ส่วนนี้จะต่างจาก Express.js ตรงที่ Express.js ใช้ :id ในขณะที่ Hapi.js ใช้ {id} ส่วน request.params.id เหมือนกันเลย)

Route /user/1

  • ทดสอบด้วยการเซฟข้อมูลลง array ด้วย HTTP POST (ส่วนนี้ต่างจากของ Express.js ตรงที่ Hapi.js จะเรียกผ่าน request.payload ใน Express.js คือ request.body

โดยการทดสอบ POST จะทำผ่าน Postman

Post /newuser

หรือใครถนัด curl ก็จัดไปครับ

curl http://localhost:7777/newuser \
-X POST \
-H "Content-Type: application/json" \
-d '{"id": 6, "username": "bb", "name": "Blackbeard", "position": "The 4 Emperors"}'

เมื่อเพิ่มข้อมูลแล้ว เราสามารถเรียกดูรายชื่อทั้งหมด http://localhost:7777/users/ ก็จะมีข้อมูลเพิ่มขึ้นมาให้ดูนะครับ แต่จะได้เฉพาะตอน Server รันอยู่เท่านั้น เนื่องจากว่า Array#push() แค่ตอน runtime ไม่ได้เซฟข้อมูลลงไปที่ไฟล์ users.js หากอยากให้เซฟก็ลองใช้โมดูล fs ของ Node ดูนะครับ

สุดท้ายหวังว่า การทดลองเล่น Hapi.js ของผมจะมีประโยชน์แก่ผู้ที่สนใจนะครับ จริงๆก็ยังเหลือหลายๆอย่างที่ไม่ได้เขียน เช่น Config, Validation, View&Static file, Caching ซึ่งหากใครอยากอ่านเพิ่มเติมก็ตาม References ด้านล่างที่ผมแนบไว้เลย (ผมก็กำลังอ่านอยู่เช่นกัน :D)

Happy Coding <3

Source Code

References

Chai Chai Phonbopit : Web Developer @Nimbl3 • ผู้ชายธรรมดาๆ ที่ชื่นชอบ Node.js, JavaScript และ Open Source มีงานอดิเรกเป็น Acoustic Guitar และ Football

บทความล่าสุด