草庐IT

express写CRUD需求接口案例

似朝朝我心 2023-09-30 原文

需求:实现对任务清单的CRUD接口服务

  • 查询任务列表
    GET /todos

  • 根据 ID 查询单个任务
    GET /todos/:id

  • 添加任务
    POST /todos

  • 修改任务
    PATCH /todos/:id

  • 删除任务

DELETE /todos/:id

目录结构及启动示意图

代码视图

  • app.js项目入口文件
const express = require('express')
const fs = require('fs')
const { getDb, saveDb } = require('./db')
const app = express()
const bodyParser = require('body-parser') 
app.use(express.json()) //配置解析表单请求头:application/json
app.use(express.urlencoded()) //配置解析表单请求头:application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))

app.get('/todos', async (req, res) => {
    try {
        const db = await getDb()
        res.status(200).json(db.todos)
    } catch (err) {
        res.status(500).json({
            error: err.message
        })
    }
})

app.get('/todos/:id', async (req, res) => {
    try {
        const db = await getDb()
        const todo = db.todos.find(todo => todo.id === Number.parseInt(req.params.id))
        if (!todo) {
            return res.status(404).end()
        }
        res.status(200).json(todo)
    } catch (err) {
        res.status(500).json({
            error: err.message
        })
    }
})

/** 2.增加接口**/
app.post('/todos', async (req, res) => {
    try {
        const todo = req.body // 1.获取客户端请求参数
        console.log(todo.title);
        if (!todo.title) { // 2.数据验证
            return res.status(422).json({
                error: 'The field title is required.'
            })
        }
        // 3.数据验证通过,把数据存储到db中
        const db = await getDb()
        const lastTodo = db.todos[db.todos.length - 1]
        //id唯一,重新写入到db文件中不覆盖,db文件是空的话,id = 1
        todo.id = lastTodo ? lastTodo.id + 1 : 1,
        db.todos.push(todo)
        await saveDb(db) //保存文件
        // 4.发送响应
        res.status(201).json(todo)
    } catch (err)  {
        res.status(500).json({
            error: err.message
        })
    }
})

/* 3.修改接口 */
app.patch('/todos/:id', async (req, res) => {
    try {
      const todo = req.body //获取表单数据
      //查找到要修改的任务项
      const db = await getDb()
      const result = db.todos.find(todo => todo.id === Number.parseInt(req.params.id))
      if(!result){ //修改项不存在
          return res.status(404).end()
      }
      Object.assign(result,todo) //合并数据
      await saveDb(db) //数据存储
      res.status(200).json(result)
    } catch (err) {
        res.status(500).json({
            error: err.message
        })
    }
})

/* 4.删除接口 */
app.delete('/todos/:id', async (req, res) => {
    try {
        //查找到要修改的任务项
        const todoId = Number.parseInt(req.params.id)
        const db = await getDb() //获取数据库
        const index = db.todos.findIndex(todo => todo.id === todoId) //根据索引进行删除
        if(index === -1){ // -1代表找不到
            return res.status(404).end
        }
        db.todos.splice(index,1) //根据索引删除一项
        await saveDb(db) //数据存储
        res.status(204).end() //发送状态码并且结束响应
      } catch (err) {
          res.status(500).json({
              error: err.message
          })
      }
})

app.listen(3000, () => {
    console.log('Server is running at http://localhost:3000');
})


/*
    没封装db.js的写法
*/
// app.get('/todos', (req, res) => {
//     fs.readFile('./db.json', 'utf-8', (err, data) => {
//         if (err) {
//             res.status(500).json({
//                 error: err.message
//             })
//         }
//         const db = JSON.parse(data)
//         res.status(200).json(db.todos)
//     })
// })
  • db.js 是一个封装好的db模块,封装了用于读取和保存数据的方法。
/*
    封装db模块
*/

const fs = require('fs')
const { promisify } = require('util')
const readFile = promisify(fs.readFile) //提供promise支持的异步读文件操作
const writeFile = promisify(fs.writeFile)
const path = require('path')

const dbPath = path.join(__dirname,'./db.json') //动态拼接路径 
exports.getDb = async () => {
    const data = await readFile(dbPath, 'utf-8')
    return JSON.parse(data) //读取json文件并转换
}

exports.saveDb = async db => {
    const data = JSON.stringify(db, null, '  ') //后2个参数让写入内容的时候是换行对其
    await writeFile(dbPath, data)
}
  • db.json 模拟充当数据库存储
{
  "todos": [
    {
      "id": 1,
      "title": "看电视"
    },
    {
      "id": 2,
      "title": "吃饭"
    },
    {
      "id": 3,
      "title": "敲代码"
    },
    {
      "title": "看电视",
      "id": 4
    }
  ],
  "users": []
}

Postman工具测试检验接口

  1. 查询任务列表


  2. 根据ID查询单个任务


  3. 添加任务项



    我们再来看看db.json有没有多出了id为5的任务项。


  4. 根据ID修改查询到的单个任务



    db.json有没有修改成功?


  5. 根据ID删除查询到的单个任务



    db.json查看还有没有id为4的任务项。


express.json()和express.urlencoded()的区别

以POSTMAN工具为例子

  • 总结:express.urlencoded()以键值对的形式填写请求,express.json()以json格式填写请求.

有关express写CRUD需求接口案例的更多相关文章

  1. 「Python|Selenium|场景案例」如何定位iframe中的元素? - 2

    本文主要介绍在使用Selenium进行自动化测试或者任务时,对于使用了iframe的页面,如何定位iframe中的元素文章目录场景描述解决方案具体代码场景描述当我们在使用Selenium进行自动化测试的时候,可能会遇到一些界面或者窗体是使用HTML的iframe标签进行承载的。对于iframe中的标签,如果直接查找是无法找到的,会抛出没有找到元素的异常。比如近在咫尺的例子就是,CSDN的登录窗体就是使用的iframe,大家可以尝试通过F12开发者模式查看到的tag_name,class_name,id或者xpath来定位中的页面元素,会抛出NoSuchElementException异常。解决

  2. postman接口测试工具-基础使用教程 - 2

    1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,

  3. ruby-on-rails - 如何在 RubyOnRails 中使用 'acts as nested set' 创建一个可排序的接口(interface) - 2

    我一直在为使用acts_as_list的模型实现一些不错的交互界面,这些界面可以对我的mRails应用程序中的列表进行排序。我有一个排序函数,在每次拖放之后使用sortable_elementscript.aculo.us函数调用并设置每条记录的位置。这是在拖放完成后处理排序的Controller操作示例:defsortparams[:documents].each_with_indexdo|id,index|Document.update_all(['position=?',index+1],['id=?',id])endend现在我正在尝试对嵌套集模型(acts_as_nested

  4. ruby - Rails 3.2 CRUD : . 其中 'or' 有条件 - 2

    使用ruby​​onrails,我想做类似的事情:@tasks=Task.where(:def=>true||:house_id=>current_user.house_id)执行此操作的最有效/最干净的方法是什么? 最佳答案 你可以这样做:Task.where("def=?orhouse_id=?",true,current_user.house_id)一般情况是:Model.where("column=?orother_column=?",value,other_value)您还可以利用Arel:t=Task.arel_tabl

  5. ruby &&= 边缘案例 - 2

    有点边缘情况,但知道为什么&&=会这样吗?我正在使用1.9.2。obj=Object.newobj.instance_eval{@bar&&=@bar}#=>nil,expectedobj.instance_variables#=>[],soobjhasno@barinstancevariableobj.instance_eval{@bar=@bar&&@bar}#ostensiblythesameas@bar&&=@barobj.instance_variables#=>[:@bar]#whywouldthisversioninitialize@bar?为了比较,||=将实例变量初始

  6. 你真正了解什么是接口测试么?接口实战一“篇”入魂 - 2

    最近在工作中,看到一些新手测试同学,对接口测试存在很多疑问,甚至包括一些从事软件测试3,5年的同学,在聊到接口时,也是一知半解;今天借着这个机会,对接口测试做个实战教学,顺便总结一下经验,分享给大家。计划拆分成4个模块跟大家做一个分享,(接口测试、接口基础知识、接口自动化、接口进阶)感兴趣的小伙伴记得关注,希望对你的日常工作和求职面试,带来一些帮助。注:文章较长有5000多字,希望小伙伴们认真看完,当然有些内容对小白同学不是太友好,如果你需要详细了解其中的一些概念或者名词,请在文章之后留言,后续我将针对大家的疑问,整理输出一些大家感兴趣的文章。随着开发模式的迭代更新,前后端分离已不是新的概念,

  7. vue 实现内容超出两行显示展开更多功能,可依据需求自定义任意行数! - 2

    平时开发中我们经常会遇到这样的需求,在一个不限高度的盒子中会有很多内容,如果全部显示用户体验会非常不好,所以可以先折叠起来,当内容达到一定高度时,显示展开更多按钮,点击即可显示全部内容,先来看看效果图: 这样做用户体验瞬间得到提升,接下来看看具体细节。0">主要操作在内容这里{{item.username}},……展开更多样式大家可依据自己项目需求进行设计,这里就不贴了,主要说几个关键的。1、在data中定义三个属性isShowMore:false, //控制展开更多的显示与隐藏textHeight:null, //框中内容的高度status:false, //内容状态是否打开2.计算内容是否

  8. ruby - 什么 ([^ :"]+) do in a Ruby regular expression? - 2

    对于^、:和"字符的特殊用途,我找不到很好的引用。 最佳答案 它匹配不是:或"的字符block。[...]-字符类-匹配此类中的字符。例如,[abc]将匹配一个字符,a或b或c。[^...]-否定字符类。+-匹配一个或多个另请参阅:CharacterClasses 关于ruby-什么([^:"]+)doinaRubyregularexpression?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/

  9. IDC最新MarketScape报告:DevOps市场需求广泛 - 2

    日前,全球著名咨询机构IDC最新MarketScape报告《中国DevOps平台市场厂商评估,2022》正式发布,此报告中对中国主流DevOps云厂商分别从现有能力和未来战略维度两个层面对厂商进行评估,IDC对具有代表性的8家提供商进行了深度研究,他们分别是(按照拼音字母顺序):AWS、阿里云、百度、博云、华为云、京东云、微软、腾讯云(CODING)。华为云、阿里云和腾讯云CODING均在战略和能力两大维度表现强势,成功入席领导者(Leaders)位置。IDC MarketScape:中国DevOps平台市场厂商评估,2022华为云软件开发生产线DevCloud在市场份额和发展战略两大维度均排

  10. ruby - 使用散列或案例陈述 [Ruby] - 2

    一般来说哪个更好用?:casenwhen'foo'result='bar'when'peanutbutter'result='jelly'when'stack'result='overflow'returnresult或map={'foo'=>'bar','peanutbutter'=>'jelly','stack'=>'overflow'}returnmap[n]更具体地说,什么时候应该使用案例陈述,什么时候应该只使用散列? 最佳答案 散列是一种数据结构,而case语句是一种控制结构。当你只是检索一些数据时,你应该使用散列(就像你

随机推荐