iT邦幫忙

4

node.js - express #5

pyk 2017-05-04 20:37:4331357 瀏覽

這幾天一直看到 RESTful REST blahblah的資料,
但其實一直沒有很明白RESTful是什麼意思,因此決定透過實做來了解什麼是RESTful了/images/emoticon/emoticon01.gif

首先,要來介紹什麼是 REST

REST (Representational State Transfer) 中文翻譯叫做「具象狀態傳輸」,
是一種網路架構風格,目的是便於不同軟體/程序在網絡(例如網際網路)中互相傳遞信息。
-- Wikipedia

符合REST風格的Web API就被稱為 RESTful API

以 API 而言,假設我們正在撰寫一組待辦事項的 API,

  • 可能會有以下方式來作為 API 的 interface:

獲取使用者資料 /getAllUsers
獲取使用者1號資料 /getUser/1
新增使用者資料 /createUser
更新使用者資料 /updateUser/1
刪除使用者資料 /deleteUser/1

  • 若是以 REST 風格來開發 RESTful API 的話:

獲取使用者資料 /GET /users
獲取使用者1號資料 /GET /user/1
新增使用者資料 /POST /user
更新使用者資料 /PUT /user/1
刪除使用者資料 /DELETE /user/1
--什麼是 REST/RESTful

從這邊就可以看出REST風格開發的充分利用了前面說過的HTTP method

而設計一個好的RESTful API有以下需要先了解

  • HTTP動詞(只擷取常見的)

    GET: 讀取資源
    PUT: 替換資源
    DELETE: 刪除資源
    POST: 新增資源;也作為萬用動詞,處理其它要求

  • URI名詞

    URI由prefix + API endpoint組成,而Prefix的部份可有可無 (/api 可以省略)。

  • HTTP回傳狀態碼

    2xx: 成功
    3xx: 重新導向
    4xx: 用戶端錯誤(用戶端不應retry原始請求)
    5xx: 伺服器錯誤(用戶端可合理retry)

  • HTTP Header

  • HTTP Body: JSON或XML格式

RESTful API是一種設計風格,使API設計具有整體一致性,易於維護、擴展,且充份利用HTTP協定的特點。
-- 簡明RESTful API設計要點

有個大略的了解後就開始來設計RESTful API吧!

第五個應用:製作RESTful Web API

參考來源: Build Node.js RESTful APIs in 10 Minutes

這次要來作一個簡單的 ToDo List (底下的事項稱作task)

  • 建立一個待辦事項(POST): /tasks
  • 讀取一個待辦事項(GET): /tasks/:taskId
  • 刪除一個待辦事項(DELETE): /tasks/:taskId
  • 讀取整個待辦事項列表(GET): /tasks
  • 更新一個待辦事項(PUT): /tasks/:taskId

備註

  • 因為Web API出錯時通常傳回的是HTTP狀態碼,因此如上面所說,必須要能看懂基本的意涵。
  • 如果想讓他人也能存取API的話,可以參考跨來源資源共享 (CORS) 來管理

因為這次的練習牽涉到了後端,因此採用 Mongoose 來實作資料庫。
Mongoos是一套給 Node.js 用的 MongoDB ODM 資料庫

  • 安裝 MongoDB Windows / Linux / OS X 才能將結果存於資料庫
  • 下載 Postman Chrome plugin 可以做HTTP動作的plugin,在之後可以幫忙做測試

上述都做好後就能開始做Todo List了!

  1. 打開你的終端機,在你想要建立todoListApi資料夾的地方輸入 mkdir todoListApi

  2. 前往該資料夾 cd todoListApi
    http://ithelp.ithome.com.tw/upload/images/20170504/20105154CUhcGUUrQg.png
    如上圖,我自己是建立在桌面

  3. 輸入npm init,之後會要求你輸入名字、版本等訊息,
    只有名字是必須輸入的,其他均可以略過,我輸入的名字是todolist
    我們可以透過 npm init 來生成 package.json來定義相關套件,更多資訊可以點此處

  4. 輸入 touch server.js 在這個資料夾內建立 server.js

  5. 輸入 mkdir api 建立一個api資料夾,並輸入 mkdir api/controllers api/models api/routes api在底下建立三個不同的資料夾(models, routes, controllers)

  6. 輸入 touch api/controllers/todoListController.js api/models/todoListModel.js api/routes/todoListRoutes.js 在三個資料夾底下分別建立對應的js檔(還是空的)

所以現在你的資料夾看起來像是這樣
http://ithelp.ithome.com.tw/upload/images/20170504/20105154Nvj8dFGc8S.png

  1. 輸入 npm install --save-dev nodemon 安裝nodemon協助程式開發

  2. 輸入 npm install express --save

  3. 輸入 npm install mongoose --save 安裝Mongoose

  4. 打開package.json在script的部分加上 "start": "nodemon server.js"
    http://ithelp.ithome.com.tw/upload/images/20170504/2010515468DKWTF598.png

補充: --save-dev 和 --save的用意

做完以上步驟後就能開始打code了!

設定伺服器(Server)

先打開 server.js 貼上以下的程式碼

var express = require('express'),
    app = express(),
    port = process.env.PORT || 300;

app.listen(port);

console.log('todo list RESTful API server started on: ' + port);

在終端機輸入 npm run start 就會發現server開始運作
http://ithelp.ithome.com.tw/upload/images/20170504/20105154F3xyPVhxVW.png

設定資料表格式(Schema)

打開 todoListModel.js 貼上以下的程式碼

'use strict'; //未必要寫

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

//建立一個model表現collection的樣子(name, Created_date, status)並規定它的格式
//collection包含name:任務名字 Created_date:建立日期 status:目前狀態('pending', 'ongoing', 'completed')
var TaskSchema = new Schema({
  name: {
    type: String,
    Required: 'Kindly enter the name of the task'
  },
  Created_date: {
    type: Date,
    default: Date.now
  },
  status: {
    type: [{
      type: String,
      enum: ['pending', 'ongoing', 'completed']
    }],
    default: ['pending']
  }
});

module.exports = mongoose.model('Tasks', TaskSchema);

設定路由(Routes)

打開 todoListRoutes.js 貼上以下程式碼

'use strict';

module.exports = function(app) {
    var todoList = require('../controllers/todoListController');


    // todoList Routes
    app.route('/tasks')
        .get(todoList.list_all_tasks)
        .post(todoList.create_a_task);


    app.route('/tasks/:taskId')
        .get(todoList.read_a_task)
        .put(todoList.update_a_task)
        .delete(todoList.delete_a_task);
};

routing決定了server會如何回應HTML的請求(request)
這裡有兩種route(/tasks/tasks/:taskId)分別對應到不同的請求(GET/POSTGET/PUT/DELETE)以及回應

設定控制器(Controller)

打開 todoListController.js 貼上以下的程式碼

'use strict';

var mongoose = require('mongoose'),
    Task = mongoose.model('Tasks');  //一開始建立的Tasks schema

//針對不同request的回應(json格式)

exports.list_all_tasks = function(req, res) {
    Task.find({}, function(err, task) {
        if (err)
            res.send(err);
        res.json(task);
    });
};

//CRUD

exports.create_a_task = function(req, res) {
    var new_task = new Task(req.body);
    new_task.save(function(err, task) {
        if (err)
            res.send(err);
        res.json(task);
    });
};

exports.read_a_task = function(req, res) {
    Task.findById(req.params.taskId, function(err, task) {
        if (err)
            res.send(err);
        res.json(task);
    });
};

exports.update_a_task = function(req, res) {
    Task.findOneAndUpdate(req.params.taskId, req.body, { new: true }, function(err, task) {
        if (err)
            res.send(err);
        res.json(task);
    });
};

exports.delete_a_task = function(req, res) {


    Task.remove({
        _id: req.params.taskId
    }, function(err, task) {
        if (err)
            res.send(err);
        res.json({ message: 'Task successfully deleted' });
    });
};

連接所有設定

修改 server.js 貼上以下的程式碼

var express = require('express'),
    app = express(),
    port = process.env.PORT || 3000,
    mongoose = require('mongoose'),
    Task = require('./api/models/todoListModel'),
    bodyParser = require('body-parser');

mongoose.Promise = global.Promise;
mongoose.connect('mongodb://localhost/Tododb');

app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

var routes = require('./api/routes/todoListRoutes');
routes(app);

app.listen(port);

console.log('todo list RESTful API server started on: ' + port);
  1. 透過URL連接MongoDB (Tododb)到server上

  2. 載入寫好的Schema Tasks

  3. 安裝、使用 bodyParser 解析回傳的json資料

$ npm install --save body-parser
  1. 把之前寫好的routes (todoListRoutes)掛上server的route上

  2. 啟動mongoDB (可能要在mongoDB安裝處才可使用此指令)

$ mongod

假使你的mongoDB需要重新啟動,輸入 rs 就能重新啟動了

http://ithelp.ithome.com.tw/upload/images/20170504/201051541CPINuM4GD.png
server成功畫面如上圖,可以開始測試功能了

使用Postman測試操作

開啟你的Postman 輸入 http://localhost:3000/tasks
得到的值應該要是 [] ,因為還沒有任何task被建立

http://ithelp.ithome.com.tw/upload/images/20170504/2010515466f40P8iWR.png

動作改為 POST,在key的部分寫上name,value的部分寫上task名稱後送出就能新增task了
重複做多次後就如下圖,使用GET得到的就不再是[]了

http://ithelp.ithome.com.tw/upload/images/20170504/20105154qTNzyQ3DR1.png

要刪除task的話,把動作改為 DELETE,網址改為 http://localhost:3000/tasks/taskid
就能夠成功刪除

http://ithelp.ithome.com.tw/upload/images/20170504/20105154AcWLNh1oh1.png

GET,網址一樣用 http://localhost:3000/tasks/taskid ,則是能得到單筆資料情形

http://ithelp.ithome.com.tw/upload/images/20170504/20105154jwZS5vqT93.png

以上就是簡單的restful api練習!

因為感冒 + 期中考 + 作業纏身,這篇文打了好久好久好久......


1 則留言

0
cheangerlove
iT邦新手 5 級 ‧ 2017-07-27 10:39:06

補充

我是個nodejs初學者,在學習這篇的mongoose應用的時候遇到一點問題,也順利解決了,所以留個註記,給跟我遇到一樣問題的人看,並解決問題。


事情是這樣的

文章從

輸入 npm install mongoose --save 安裝Mongoose
打開package.json在script的部分加上 "start": "nodemon server.js"

開始出現一個mongoose後續設定的斷層,導致最後執行node server.js的時候會跳Error

如何解決

  • 首先安裝完mongodb之後,進入mongodb根目錄,創建一個資料夾Tododb這是用來存放資料的
  • 進入mongodb/bin並執行 mongod --dbpath=D:\mongodb\Tododb
  • mongod會自動建立所有用到的物件並啟動資料庫
  • 當mongodb啟動之後,再回到node執行node server.js就可以順利跑起來了

結論

我遇到的問題是mongodb一開始沒有啟動與設定,所以才會在最後卡關,不過啟動mongodb之後,所有問題就迎刃而解了,題外話... 除了用Brackets寫nodejs還有更好的選擇嗎?用Eclipse寫程式寫久了,都會忘記去注意一些打錯字的問題,有時候遇到Bug找很久才發現是字母打錯..

pyk iT邦新手 5 級 ‧ 2017-08-14 09:07:19 檢舉

我自己是用sublime去寫
可能是因為我是MacOS系統所以沒有出現那個問題吧QQ

RocMark iT邦新手 5 級 ‧ 2017-12-19 02:35:42 檢舉

推VS CODE 很多插件可以裝還蠻不錯的

我要留言

立即登入留言