用Node.js怎样快速构建一个API效劳器?
Node.js 对初学者来说大概是令人望而生畏的,其灵敏的构造和缺乏严厉的标准使它看起来很复杂。【视频教程引荐:node js教程 】
本教程是 Node.js,Express 框架和 MongoDB 的快速指南,重点介绍根本的 REST 路由和根本的数据库交互。你将构建一个简便的 API 框架模版,然后可以将其用作任何利用。
本教程适用于:你应当对 REST API 和 CRUD 操纵有根本的理解,还有根本的 JavaScript 知识。我用的是 ES6(主如果箭头函数),但并不是很复杂。
在本教程中,我们将为创立一个网络笔记利用的后端骨架 —— 相似于Google Keep,能够施行所有的四个CRUD操纵:创立、读取、更新和删除。
配置
假如你没有安置Node,请参阅此处。
创立一个新名目,运转 npm init
,然后依照提醒操纵,把你的利用程序命名为“notable”(或者你大概喜爱的其他名字)。
npm init
一旦完成,在你的名目中会有一个 package.json 文件。你可以开端安置项目所需的依靠项了。
我们将使用 Express 作为本人的框架,MongoDB 作为数据库,还有一个名为 body-parser 的包来帮忙处置 JSON 恳求。
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.js 和 note_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 来测试。
你应当得到回复:'Hello'。
太好了!你创立了第一个真正的路由。
下一步是在你的恳求中增加一些参数并在 API 中处置它们,最后增加到你的数据库中。
恳求参数
在 Postman 中,在选中 x-www-form-urlencoded 单选按钮后,转到 Body 选项卡并增加一些键值对。
这会将编码后的表单数据增加到你的恳求中,你可以使用 API ??处置该恳求。
你可以去尝试更多的设定项。
此刻在你的 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 摆设后,将会员的会员名和密码增加到数据库:
然后复制这里第二个 URL:
在项目根名目的名目配置中,创立一个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 选项卡下设定 title 和 body。
响应应如下所示:
假如你登录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,它应如下所示:
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); } }); }); // ...
此刻你可以更新任何笔记,如下所示:
请留意这些代码还不完善 —— 比方你没有供给正文或标题,PUT 恳求将会使数据库中的笔记上的那些字段无效。
API 完成
就这么简便!你完成了可以停止 CRUD 操纵的 Node API。
本教程的目的是让你熟知 Express、Node 和 MongoDB —— 你可以用简便的程序作为进军更复杂项目的跳板。
未来我将会编写系列教程,用不一样的说话和框架创立更简便的API。假如你有乐趣,请点击关注!