30分鐘用Node.js構建一個API服務器

翻譯:瘋狂的技術宅
原文: https://medium.freecodecamp.o...

本文首發微信公衆號:前端先鋒
歡迎關注,天天都給你推送新鮮的前端技術文章javascript


Node.js 對初學者來講多是使人望而卻步的,其靈活的結構和缺少嚴格的規範使它看起來很複雜。前端

本教程是 Node.js,Express 框架和 MongoDB 的快速指南,重點介紹基本的 REST 路由和基本的數據庫交互。你將構建一個簡單的 API 框架模版,而後能夠將其用做任何應用。java

本教程適用於:你應該對 REST API 和 CRUD 操做有基本的瞭解,還有基本的 JavaScript 知識。我用的是 ES6(主要是箭頭函數),但並非很複雜。node

在本教程中,咱們將爲建立一個網絡筆記應用的後端骨架 —— 相似於Google Keep,可以執行全部的四個CRUD操做:建立、讀取、更新和刪除。git

配置

若是你沒有安裝Node,請參閱此處程序員

建立一個新目錄,運行 npm init,而後按照提示操做,把你的應用程序命名爲「notable」(或者你可能喜歡的其餘名字)。github

npm init

一旦完成,在你的目錄中會有一個 package.json 文件。你能夠開始安裝項目所需的依賴項了。面試

咱們將使用 Express 做爲本身的框架,MongoDB 做爲數據庫,還有一個名爲 body-parser 的包來幫助處理 JSON 請求。mongodb

npm install --save express mongodb@2.2.16 body-parser

我還強烈建議將 Nodemon 安裝爲 dev 依賴項。這是一個很是簡單的小包,可在文件被更改時自動重啓服務器。數據庫

若是你運行:

npm install --save-dev nodemon

而後將如下腳本添加到 package.json

// package.json
  "scripts": {
    "dev": "nodemon server.js"
  },

完整的 package.json 應以下所示:

// package.json
{
  "name": "notable",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "scripts": {
    "dev": "nodemon server.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.15.2",
    "express": "^4.14.0",
    "mongodb": "^2.2.16"
  },
  "devDependencies": {
    "nodemon": "^1.11.0"
  }
}

如今,你能夠建立 server.js 文件並構建 API 了。

咱們的服務器

首先導入 server.js 中的全部依賴項。

// server.js
const express        = require('express');
const MongoClient    = require('mongodb').MongoClient;
const bodyParser     = require('body-parser');
const app            = express();

咱們將使用 MongoClient 與數據庫進行交互。還會將應用初始化爲 Express 框架的實例。

最後一件事就是告訴你的程序開始監聽請求。

你能夠指定一個端口,並像這樣開始監聽:

// server.js
const port = 8000;
app.listen(port, () => {
  console.log('We are live on ' + port);
});

如今,若是你運行 npm run dev(或 node server.js,若是你沒有安裝 Nodemon 的話),應該在終端中看到「We are live on port 8000」的提示。

你的服務器已經啓動了。但它如今還什麼也作不了。

接下來讓咱們解決這個問題。

CRUD 路由

對於本例,你要構建4條路由; 建立筆記,閱讀筆記,更新筆記和刪除筆記。

這將使你瞭解如何使用 Node 構建幾乎全部的基本路由。

可是,要測試你的API,還須要模仿客戶端發出請求。爲此,咱們將使用名爲 Postman 的優秀應用。它容許你使用自定義的頭和參數進行簡單的 HTTP 請求。

安裝Postman,讓咱們開始設置路由。

項目結構

大多數 Node.js 教程(以及許多真實的案例)都將全部路由放在一個很大的 routes.js 文件中。這讓我有點不舒服。相比之下,將文件拆到爲單獨的文件夾能夠提升可讀性,並使大型應用更易於管理。

雖然咱們如今作的不是大型應用,但仍然能夠這樣作。建立如下目錄:一個 app 文件夾,裏面有一個routes文件夾,routes 裏面有 index.jsnote_routes.js 文件。

mkdir app
cd app
mkdir routes
cd routes
touch index.js
touch note_routes.js

對於你的簡單小程序來講,這些目錄可能看起來有些過度,但從一開始就作好老是有意義的。

你的第一個路由

讓咱們從 CRUD 中的 C 開始。你將會如何建立一個筆記?

那麼,在你開始以前,必須先要打好基礎。在Express中,路由包含在一個函數中,該函數將 Express 實例和數據庫做爲參數。

像這樣:

// routes/note_routes.js
module.exports = function(app, db) {
};

而後,你能夠經過 index.js 導出此函數:

// routes/index.js
const noteRoutes = require('./note_routes');
module.exports = function(app, db) {
  noteRoutes(app, db);
  // Other route groups could go here, in the future
};

而後導入它以便在 server.js 中使用:

// server.js
const express        = require('express');
const MongoClient    = require('mongodb').MongoClient;
const bodyParser     = require('body-parser');
const app            = express();
const port = 8000;
require('./app/routes')(app, {});
app.listen(port, () => {
  console.log('We are live on ' + port);
});

請注意,因爲尚未設置數據庫,所以只需傳入一個空對象。

好的,如今你能夠製做本身的 CREATE 路由了。

語法很簡單:

// note_routes.js
module.exports = function(app, db) {
  app.post('/notes', (req, res) => {
    // You'll create your note here.
    res.send('Hello')
  });
};

當應用程序收到對 '/ notes' 路徑的 post 請求時,它將執行回調內的代碼 —— request 對象(包含請求的參數或JSON)和 response 對象。

你可使用 Postman 將 POST 請求發送到 localhost:8000/notes 來測試。

clipboard.png

你應該獲得回覆:'Hello'。

太好了!你建立了第一個真正的路由。

下一步是在你的請求中添加一些參數並在 API 中處理它們,最後添加到你的數據庫中。

請求參數

在 Postman 中,在選擇 x-www-form-urlencoded 單選按鈕後,轉到 Body 選項卡並添加一些鍵值對。

這會將編碼後的表單數據添加到你的請求中,你可使用 API ​​處理該請求。

clipboard.png

你能夠去嘗試更多的設置項。

如今在你的 note_routes.js 中,讓咱們輸出 body 的內容。

// note_routes.js
module.exports = function(app, db) {
  app.post('/notes', (req, res) => {
    console.log(req.body)
    res.send('Hello')
  });
};

用 Postman 發送請求,你會看到……undefined。

不幸的是,Express 沒法自行處理 URL 編碼的表單。雖然你確實安裝了這個 body-parser 包......

// server.
const express        = require('express');
const MongoClient    = require('mongodb').MongoClient;
const bodyParser     = require('body-parser');
const app            = express();
const port = 8000;
app.use(bodyParser.urlencoded({ extended: true }));
require('./app/routes')(app, {});
app.listen(port, () => {
  console.log('We are live on ' + port);
});

Now you should see the body as an object in the terminal.
如今你應該將 body 視爲終端中的對象。

{ title: 'My Note Title', body: 'What a great note.' }

第一個路由的最後一步:設置數據庫,而後添加數據。

最簡單方法是經過 mLab 設置 Mongo 數據庫的:它是最小的並且是免費的,設置的速度很是快。

建立賬戶和 MongoDB 部署後,將用戶的用戶名和密碼添加到數據庫:

clipboard.png

而後複製這裏第二個 URL:

clipboard.png

在項目根目錄的目錄配置中,建立一個db.js文件。

mkdir config 
cd config
touch db.js

在裏面,添加剛纔的URL:

module.exports = {
  url : YOUR URL HERE
};

別忘了把你的用戶名和密碼(來自數據庫用戶的密碼,而不是你的 mLab 賬戶)添加到URL中。 (若是你要將此項目提交到 Github 上,請確保包含 .gitignore 文件 像這樣, ,不要與任何人分享你的密碼。)

如今在你的 server.js 中,能夠用 MongoClient 鏈接到數據庫了,使用它來包裝你的應用程序設置:

// server.js
const express        = require('express');
const MongoClient    = require('mongodb').MongoClient;
const bodyParser     = require('body-parser');
const db             = require('./config/db');
const app            = express();
const port = 8000;
app.use(bodyParser.urlencoded({ extended: true }));
MongoClient.connect(db.url, (err, database) => {
  if (err) return console.log(err)
  require('./app/routes')(app, database);
  app.listen(port, () => {
    console.log('We are live on ' + port);
  });               
})

若是你用的是最新版本的 MongoDB(3.0+),請將其修改成:

// server.js
const express        = require('express');
const MongoClient    = require('mongodb').MongoClient;
const bodyParser     = require('body-parser');
const db             = require('./config/db');
const app            = express();
const port = 8000;
app.use(bodyParser.urlencoded({ extended: true }));
MongoClient.connect(db.url, (err, database) => {
  if (err) return console.log(err)
                      
  // Make sure you add the database name and not the collection name
  const database = database.db("note-api")
  require('./app/routes')(app, database);
  app.listen(port, () => {
    console.log('We are live on ' + port);
  });               
})

這是你的基礎架構的最後一個設置!

添加到你的數據庫

MongoDB將數據存儲在 collections 中。在你的項目中,你但願將筆記存儲在一個名爲 notes 的 collection 中。

因爲將數據庫做爲路徑中的 db 參數傳入,所以能夠像這樣訪問它:

db.collection('notes')

建立筆記就像在集合上調用 insert 同樣簡單:

const note = { text: req.body.body, title: req.body.title}
  db.collection('notes').insert(note, (err, results) => {
}

插入完成後(或因爲某種緣由失敗),要麼返回錯誤或反回新建立的筆記對象。這是完整的 note_routes.js 代碼:

// note_routes.js
module.exports = function(app, db) {
  const collection = 
  app.post('/notes', (req, res) => {
    const note = { text: req.body.body, title: req.body.title };
    db.collection('notes').insert(note, (err, result) => {
      if (err) { 
        res.send({ 'error': 'An error has occurred' }); 
      } else {
        res.send(result.ops[0]);
      }
    });
  });
};

試試看!使用 Postman 發送 x-www-form-urlencoded POST 請求,在 Body 選項卡下設置 titlebody

響應應以下所示:

clipboard.png

若是你登陸mLab,你還應該可以在數據庫中看到建立的筆記。

READ 路由

如今能夠稍微加快步伐。

假設你但願經過導航到 localhost:8000/notes/{id} 來獲取剛建立的筆記。這是連接應該是localhost:8000/notes/585182bd42ac5b07a9755ea3。(若是你沒有獲得其中筆記的 ID,能夠經過檢查 mLab 或建立一個新的筆記)。

如下是 note_routes.js 中的內容:

// note_routes.js
module.exports = function(app, db) {
  app.get('/notes/:id', (req, res) => {
    
  });
  app.post('/notes', (req, res) => {
    const note = { text: req.body.body, title: req.body.title };
    db.collection('notes').insert(note, (err, result) => {
      if (err) { 
        res.send({ 'error': 'An error has occurred' }); 
      } else {
        res.send(result.ops[0]);
      }
    });
  });
};

就像之前同樣,你將在數據庫 collection 中調用一個方法。在這裏,它被恰當地命名爲 findOne。

// note_routes.js
module.exports = function(app, db) {
  app.get('/notes/:id', (req, res) => {
    const details = { '_id': <ID GOES HERE> };
    db.collection('notes').findOne(details, (err, item) => {
      if (err) {
        res.send({'error':'An error has occurred'});
      } else {
        res.send(item);
      }
    });
  });
app.post('/notes', (req, res) => {
    const note = { text: req.body.body, title: req.body.title };
    db.collection('notes').insert(note, (err, result) => {
      if (err) { 
        res.send({ 'error': 'An error has occurred' }); 
      } else {
        res.send(result.ops[0]);
      }
    });
  });
};

你能夠經過 req.params.id 從 URL 參數中獲取 id。可是,若是你試圖將字符串插入上面的 <ID GOES HERE> 位置,它將沒法正常工做。

MongoDB 不只要求 ID 爲字符串,還要求 ID 是一個對象,它們被之爲 ObjectID。

別擔憂,這很容易解決。這是完整的代碼:

// note_routes.js
var ObjectID = require('mongodb').ObjectID;
module.exports = function(app, db) {
  app.get('/notes/:id', (req, res) => {
    const id = req.params.id;
    const details = { '_id': new ObjectID(id) };
    db.collection('notes').findOne(details, (err, item) => {
      if (err) {
        res.send({'error':'An error has occurred'});
      } else {
        res.send(item);
      } 
    });
  });
app.post('/notes', (req, res) => {
    const note = { text: req.body.body, title: req.body.title };
    db.collection('notes').insert(note, (err, result) => {
      if (err) { 
        res.send({ 'error': 'An error has occurred' }); 
      } else {
        res.send(result.ops[0]);
      }
    });
  });
};

嘗試使用一個筆記 ID,它應以下所示:

clipboard.png

DELETE 路由

實際上刪除對象與查找對象幾乎相同。你只需用 remove 函數替換 findOne 便可。這是完整的代碼:

// note_routes.js
// ...
  app.delete('/notes/:id', (req, res) => {
    const id = req.params.id;
    const details = { '_id': new ObjectID(id) };
    db.collection('notes').remove(details, (err, item) => {
      if (err) {
        res.send({'error':'An error has occurred'});
      } else {
        res.send('Note ' + id + ' deleted!');
      } 
    });
  });
// ...

UPDATE 路由

最後一個! PUT 方法基本上是 READ 和 CREATE 的混合體。你找到該對象,而後更新它。若是剛纔你刪除了數據庫中惟一的筆記,那就再建立一個!

代碼:

// note_routes.js
// ...
  app.put('/notes/:id', (req, res) => {
    const id = req.params.id;
    const details = { '_id': new ObjectID(id) };
    const note = { text: req.body.body, title: req.body.title };
    db.collection('notes').update(details, note, (err, result) => {
      if (err) {
          res.send({'error':'An error has occurred'});
      } else {
          res.send(note);
      } 
    });
  });
// ...

如今你能夠更新任何筆記,以下所示:

clipboard.png

請注意這些代碼還不完美 —— 好比你沒有提供正文或標題,PUT 請求將會使數據庫中的筆記上的那些字段無效。

API 完成

就這麼簡單!你完成了能夠進行 CRUD 操做的 Node API。

本教程的目的是讓你熟悉 Express、Node 和 MongoDB —— 你能夠用簡單的程序做爲進軍更復雜項目的跳板。

未來我將會編寫系列教程,用不一樣的語言和框架建立更簡單的API。若是你有興趣,請點擊關注!


本文首發微信公衆號:前端先鋒

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章


歡迎繼續閱讀本專欄其它高贊文章:


相關文章
相關標籤/搜索