使用node开发restful风格api,一块儿“云养猫”

为啥要选用node

  1. 不须要学习额外的语言特性;
  2. 扩展网络和数据库的知识面;
  3. 一个字,快!

安装环境快,一键式无脑安装,不用担忧各类繁琐配置;
启动服务快,只须要短短几行代码就能生成一个web服务器;
上手更快。html

思路

经过下述步骤对使用node开发web服务有一个大概的认识
  1. 安装数据库,这里选用mongodb;
  2. 定义数据模式,即数据的结构和行为;
  3. 定义数据模型,对数据库进行操做须要经过该模型;
  4. 定义路由,在该路由路径被访问时,触发对应的函数,进行数据库操做。

其实很简单,就三步。经过一些代码层面的优化,甚至只须要咱们实现第二步定义好咱们所须要的数据结构以后就能生成restful风格的api。前端

restful风格的api?

宁静的数据接口?什么鬼?
  • 先说api,实际上是一个很广的命题。这里咱们理解的api是打通先后端的交互的数据接口。而在有一些语义下,它能够是你封装的一个工具函数方法。
  • restful风格咱们能够这么理解
  1. 设计路径:在第二、3步定义好数据结构后,经过路径去访问该数据资源。
  2. 定义http动词:访问资源后,咱们须要什么样的操做

咱们耳熟能详的增删改查其实就对应着 post、delete、put、get这四个http动词。
例如:get /api/user/ => 查看/api/user这个路径下全部用户信息的资源node

尝试开发

其实开发web服务,大部分操做就是围绕着操做数据库,而操做数据库确定有额外的学习成本。毕竟这是不少前端er没接触过的。

就我我的而言,学习一个新的知识点,查阅官方文档无疑是最好的办法。react

假设已经安装完了mongodb,咱们要操做数据库还须要另外一个东西:mongoose,翻译过来是猫鼬,又是一个不知道什么鸟东西,在这儿能够简单的理解,经过它能够更加方便的操做数据库。git

其实官方的例子特别的好,跟着猫鼬一块儿云养猫
还记得前面将的思路和步骤嘛,首先咱们要使用node的一个框架express生成项目模板github

  1. 设计路径:在routes文件夹建立一个cat.js文件,这个就是咱们要访问的资源;
  2. 定义数据模型:定义数据结构、生成数据模型;
  3. 定义路由:使用express框架的路由功能,根据http动词触发对应函数操做数据库;
const express = require('express');
const router = express.Router();
const mongoose = require("mongoose")

//猫的模式:假设每一只猫都有名字和颜色的属性。
const catSchema = mongoose.Schema({
  name: String,
  color:String
})
//猫的模型:经过传入猫的模式,咱们有了一个模型,而后就能够根据该模型生成好多猫了!
const CatModel = mongoose.model('Cat', catSchema)

router.get('/cat', function (req, res, next) {
  //后来猫愈来愈多,就能够经过模型来查找小猫
  CatModel.find((err, allCats) => res.json(allCats))
});

router.post('/cat', ((req, res, next) => {
  //假设咱们要增长一只小猫,猫咪的信息经过post请求的请求体传输到服务端。
  const catInfo = req.body //假如请求体内容为{name:'小白',color:'黑色'}
  //根据猫的模型生成的小猫就有了  名字为小白,颜色为黑色的属性。
  const lititleCat = new CatModel(catInfo)
  //小猫在调用save方法后保存到数据库
  lititleCat.save((err, saved) => res.json(saved))
}))

router.delete('/cat', ((req, res, next) => {
  const { id } = req.body
  //根据传入的猫的id,删除该猫的信息
  CatModel.findByIdAndRemove(id, (err, removed) => res.json(removed))
}))

router.put('/cat', ((req, res, next) => {
  const { id } = req.body
  //根据传入的猫的id,更新猫的信息
  CatModel.findByIdAndUpdate(id, { ...req.body }, { new: true }, (err, updated) => res.json(updated))
}))

这个时候启动服务,其实未生效,这是由于咱们写了一大堆,并无触发,须要在入口文件app.js引入咱们的路由文件。web

//引入猫的路由
const catRouter = require('./routes/cat');
//app就是咱们的服务器,当服务器资源路径 /api被调用时,就会映射到咱们猫的路由
app.use('/api', catRouter);
// localhoset:3000/api/cat  便是咱们要请求猫的资源的 路径,最后经过http动词,触发对应的数据库操做,咱们就生成了第一个符合restful风格的api。

进阶

  1. 假设咱们要将猫的信息和它的饲养员的信息绑定在一块儿,就须要联表
  2. mongoose的语法充斥着各类回调,就须要async await来优化

接下来修改一下上面生成猫的例子mongodb

const express = require('express');
const router = express.Router();
const mongoose = require("mongoose")
const mongoose = require('mongoose')

+ const feederSchema = mongoose.Schema({
+  feederName: String,
+  cat: {
+    type: mongoose.Schema.Types.ObjectId,//联表查询必须这样的格式来存储对应表的_id
+    ref: 'Cat'//联表关系的表名,注意是生成模型的类,与模型名区分开
+  }
+ })

//猫的模式:假设每一只猫都有名字和颜色的属性。
const catSchema = mongoose.Schema({
  name: String,
  color:String
})

+ const feederModel = mongoose.model("Feeder", feederSchema)
//猫的模型:经过传入猫的模式,咱们有了一个模型,而后就能够根据该模型生成好多猫了!
const CatModel = mongoose.model('Cat', catSchema)

router.get('/cat',  (req, res, next)=> {
  //后来猫愈来愈多,就能够经过模型来查找小猫
  CatModel.find((err, allCats) => res.json(allCats))
});

router.post('/cat', async((req, res, next) => {
   //假设咱们要增长一只小猫,猫咪的信息经过post请求的请求体传输到服务端。
+  const { name, color, feederName } = req.body //假如请求体内容为{name:'小白',color:'黑色',feederName:"张三"}
+  const catInfo = { name, color } //猫的信息
+  const feederInfo = { feederName }  //饲养员信息
   //根据猫的模型生成的小猫就有了  名字为小白,颜色为黑色的属性。
   const lititleCat = new CatModel(catInfo)
   //小猫在调用save方法后保存到数据库
+  const { _id } = await lititleCat.save()
   //将小猫的id与用户的猫关联起来
+  const newFeeder = new feederModel({ ...feederInfo, cat: _id })
   //保存用户信息
+  await newFeeder.save()
   //经过populate()能够查询联表的属性,exec()能够更好的追踪堆栈,让查询的函数返回的是一个完整的promise对象
+  const data = await feederModel.find().populate("cat").exec()
+  res.json(data)
  
}))

router.delete('/cat', (req, res, next) => {
  const { id } = req.body
  //根据传入的猫的id,删除该猫的信息
  CatModel.findByIdAndRemove(id, (err, removed) => res.json(removed))
})

router.put('/cat', (req, res, next) => {
  const { id } = req.body
  //根据传入的猫的id,更新猫的信息
  CatModel.findByIdAndUpdate(id, { ...req.body }, { new: true }, (err, updated) => res.json(updated))
})

能够下载postman测试一下代码
image数据库

优化

当你使用postman测试了几回代码以后你会发现每次post请求都新增重复数据,哪怕内容是没有变化的,mongoose会为保存时的数据添加惟一的_id标识。

按照正常的逻辑应该是express

  1. 当没有这条数据时,插入一个新数据;
  2. 当数据存在时,根据新的内容更新它;
  3. 而判断该数据是否存在,咱们须要一个做为惟一标识的查询条件

因此咱们可使用findOneAndUpdate这个api插入或更新咱们的数据,修改post请求的代码

router.post('/cat', async((req, res, next) => {
  //假设咱们要增长一只小猫,猫咪的信息经过post请求的请求体传输到服务端。
  const { name, color, feederName } = req.body //假如请求体内容为{name:'小白',color:'黑色',feederName:"张三"}
  const catInfo = { name, color } //猫的信息
  const feederInfo = { feederName }  //饲养员信息
  //这里根据猫的名称做为插入或更新的查询标识
+ const {_id} = await CatModel.findOneAndUpdate({name},catInfo,{ upsert: true, new: true, setDefaultsOnInsert: true }).exec()
  //这里根据饲养员的名称做为插入或更新的查询标识
+ await feederModel.findOneAndUpdate({feederName},{...feederInfo,cat:_id},{ upsert: true, new: true, setDefaultsOnInsert: true })
  //经过populate()能够查询联表的属性,exec()能够更好的追踪堆栈,让查询的函数返回的是一个完整的promise对象
  const data = await feederModel.find().populate("cat").exec()
  res.json(data)
 
}))

总结

固然,这些都是node最基础的操做,可是这些特别简单的东西,扩展了不少知识,经过断点调试你能够更加深入地了解到http请求通讯过程当中的数据传输、数据库模型的操做等等,甚至你还会开始思考如何使用node作更多的东西。
例如:
快速的接口mock,在拟定好协议以后使用node开发数据接口,提升接口联调的效率;
甚至搭一个可视化的mock数据的平台,经过可编辑表格操做去生成数据接口;
又或者你能够新建一个本身的网站,使用node搭建本身的服务器等等等。

最后贴上本身的github地址:
https://github.com/kangjs7854...臭不要脸的求个star,万分感谢~

相关文章
相关标签/搜索