使用Express.js和SQLite3构建简单TODO应用的后端API

news2025/2/4 22:49:00

使用Express.js和SQLite3构建简单TODO应用的后端API

        • 引言
        • 环境准备
        • 代码解析
          • 1. 导入必要的模块
          • 2. 创建Express应用实例
          • 3. 设置数据库连接
          • 4. 初始化数据库表
          • 5. 配置中间件
          • 6. 定义数据接口
          • 7. 定义路由
            • 7.1 获取所有TODO项
            • 7.2 创建TODO项
            • 7.3 更新TODO项
            • 7.4 删除TODO项
          • 8. 启动服务器
        • 优化建议
        • 总结

引言

在现代Web开发中,TODO列表应用是一个经典的示例,用于展示如何使用前端和后端技术构建一个简单的任务管理工具。本文将详细介绍如何使用Express.js框架和SQLite3数据库来构建一个TODO列表应用,并解释代码的各个部分,帮助读者理解其工作原理。

前端UI请参考,使用React和Material-UI构建TODO应用的前端UI

环境准备

在开始之前,请确保你已经安装了以下工具和库:

  1. Node.js:确保你已经安装了Node.js,可以从Node.js官网下载并安装。
  2. npm:Node.js的包管理工具,随Node.js一起安装。
  3. Express.js:一个轻量级的Node.js Web应用框架,可以通过npm安装。
  4. SQLite3:一个文件数据库,适用于小型应用,同样可以通过npm安装。
  5. TypeScript:可选,但推荐使用,以提升代码的可维护性和类型安全性。

安装所需的依赖:

npm install express cors sqlite3
代码解析

让我们逐步分析代码,理解每个部分的功能。

1. 导入必要的模块
import express from 'express';
import cors from 'cors';
import sqlite3 from 'sqlite3';
import path from 'path';
  • Express:用于创建Web服务器。
  • CORS:处理跨域请求,允许前端应用从不同的域名访问后端API。
  • SQLite3:用于与SQLite数据库进行交互。
  • Path:处理文件路径,确保在不同操作系统下路径正确。
2. 创建Express应用实例
const app = express();

这行代码创建了一个Express应用实例,后续的所有中间件和路由都将注册到这个实例上。

3. 设置数据库连接
const db = new sqlite3.Database(path.join(__dirname, '../database/db.sqlite'));

这里创建了一个SQLite3数据库连接,数据库文件位于../database/db.sqlitepath.join用于确保路径在不同操作系统下都能正确解析。

4. 初始化数据库表
db.serialize(() => {
    db.run(`
        CREATE TABLE IF NOT EXISTS todos
        (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            title TEXT NOT NULL,
            description TEXT,
            completed BOOLEAN DEFAULT 0,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP
        )
    `);
});

这段代码在数据库中创建了一个名为todos的表,如果该表不存在的话。表结构如下:

  • id:整数类型,主键,自增。
  • title:文本类型,非空。
  • description:文本类型,可选。
  • completed:布尔类型,默认值为0(即false)。
  • created_at:日期时间类型,默认值为当前时间戳。
5. 配置中间件
app.use(cors());
app.use(express.json());
  • CORS中间件:允许来自不同域名的请求,防止跨域问题。
  • JSON中间件:解析请求体中的JSON数据,使得req.body可以访问到客户端发送的数据。
6. 定义数据接口
interface Todo {
    id?: number;
    title: string;
    description?: string;
    completed?: boolean;
    created_at?: string;
}

这是一个TypeScript接口,定义了TODO项的结构。iddescriptioncompletedcreated_at是可选的,而title是必填的。

7. 定义路由
7.1 获取所有TODO项
app.get('/api/todos', (req: express.Request, res: express.Response) => {
    const search = (req.query.q as string) || '';
    db.all<Todo>(
        `SELECT *
         FROM todos
         WHERE title ILIKE ? 
            OR description ILIKE ?
         ORDER BY created_at DESC`,
        [`%${search}%`, `%${search}%`],
        (err, rows) => {
            if (err) return res.status(500).json({ error: err.message });
            res.json(rows);
        }
    );
});
  • 功能:获取所有TODO项,支持通过q参数进行模糊搜索。
  • 查询参数q用于模糊搜索标题或描述。
  • 数据库操作:使用ILIKE进行不区分大小写的匹配,按创建时间降序排列。
  • 错误处理:如果数据库操作失败,返回500状态码和错误信息。
7.2 创建TODO项
app.post('/api/todos', (req: express.Request, res: express.Response) => {
    const { title, description } = req.body as Todo;
    if (!title) {
        return res.status(400).json({ error: 'Title is required' });
    }

    db.run(
        'INSERT INTO todos (title, description) VALUES (?, ?)',
        [title, description],
        function (err) {
            if (err) return res.status(500).json({ error: err.message });
            db.get<Todo>(
                'SELECT * FROM todos WHERE id = ?',
                [this.lastID],
                (err, row) => {
                    if (err) return res.status(500).json({ error: err.message });
                    res.status(201).json(row);
                }
            );
        }
    );
});
  • 功能:创建一个新的TODO项。
  • 请求体:必须包含titledescription可选。
  • 数据库操作:插入新记录,然后查询新插入的记录并返回。
  • 错误处理:检查title是否为空,返回400错误;数据库操作失败返回500错误。
7.3 更新TODO项
app.put('/api/todos/:id', (req: express.Request, res: express.Response) => {
    const { id } = req.params;
    const { title, description, completed } = req.body as Todo;

    db.run(
        `UPDATE todos
         SET title       = ?,
             description = ?,
             completed   = ?
         WHERE id = ?`,
        [title, description, completed ? 1 : 0, id],
        function (err) {
            if (err) return res.status(500).json({ error: err.message });
            if (this.changes === 0) {
                return res.status(404).json({ error: 'Todo not found' });
            }
            db.get<Todo>(
                'SELECT * FROM todos WHERE id = ?',
                [id],
                (err, row) => {
                    if (err) return res.status(500).json({ error: err.message });
                    res.json(row);
                }
            );
        }
    );
});
  • 功能:更新指定ID的TODO项。
  • 请求体:包含titledescriptioncompleted
  • 数据库操作:更新记录,completed字段转换为10
  • 错误处理:如果没有记录被更新,返回404错误;数据库操作失败返回500错误。
7.4 删除TODO项
app.delete('/api/todos/:id', (req: express.Request, res: express.Response) => {
    const { id } = req.params;
    db.run(
        'DELETE FROM todos WHERE id = ?',
        [id],
        function (err) {
            if (err) return res.status(500).json({ error: err.message });
            if (this.changes === 0) {
                return res.status(404).json({ error: 'Todo not found' });
            }
            res.status(204).send();
        }
    );
});
  • 功能:删除指定ID的TODO项。
  • 数据库操作:删除记录。
  • 错误处理:如果没有记录被删除,返回404错误;数据库操作失败返回500错误。
8. 启动服务器
const PORT = 3002;
app.listen(PORT, () => {
    console.log(`Server running on port ${PORT}`);
});

服务器监听在3002端口,启动后在控制台输出提示信息。

优化建议

尽管这段代码已经可以正常工作,但为了提升应用的性能和可维护性,可以考虑以下优化:

  1. 使用连接池: SQLite3支持连接池,可以提高数据库操作的效率,特别是在高并发情况下。
  2. 添加输入验证:使用中间件如express-validator对请求体进行验证,确保数据的合法性和完整性。
  3. 添加分页功能:在获取TODO列表时,添加分页功能,限制每页返回的记录数,提高性能。
  4. 使用ORM工具:如SequelizeKnex.js,简化数据库操作,提高代码的可读性和可维护性。
  5. 添加日志记录:使用winstonmorgan记录请求和错误信息,便于调试和监控。
  6. 添加速率限制:防止恶意攻击,限制同一IP地址的请求频率。
总结

通过本文,我们详细解析了一个使用Express.js和SQLite3构建的TODO列表应用。从数据库的初始化、路由的定义到错误处理,每个部分都进行了详细的解释。希望这篇文章能够帮助读者理解如何使用这些技术构建一个简单的Web应用,并为进一步的学习和开发打下基础。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2292016.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

找不到msvcp140.dll解决方法

您可以尝试以下方案进行修复&#xff0c;看看是否可以解决这个问题&#xff1a; 一、重新注册 msvcp140.dll 运行库文件&#xff1a; “WinR”打开运行&#xff0c;键入&#xff1a;regsvr32 MSVCP140.dll&#xff0c;回车即可&#xff1b; 如果出现找不到该文件的提示&…

【优先算法】专题——位运算

在讲解位运算之前我们来总结一下常见的位运算 一、常见的位运算 1.基础为运算 << &&#xff1a;有0就是0 >> |&#xff1a;有1就是1 ~ ^&#xff1a;相同为0&#xff0c;相异位1 /无进位相加 2.给一个数 n&#xff0c;确定它的二进制表示…

【Cadence仿真技巧学习笔记】求解65nm库晶体管参数un, e0, Cox

在设计放大器的第一步就是确定好晶体管参数和直流工作点的选取。通过阅读文献&#xff0c;我了解到L波段低噪声放大器的mos器件最优宽度计算公式为 W o p t . p 3 2 1 ω L C o x R s Q s p W_{opt.p}\frac{3}{2}\frac{1}{\omega LC_{ox}R_{s}Q_{sp}} Wopt.p​23​ωLCox​Rs…

Docker入门篇(Docker基础概念与Linux安装教程)

目录 一、什么是Docker、有什么作用 二、Docker与虚拟机(对比) 三、Docker基础概念 四、CentOS安装Docker 一、从零认识Docker、有什么作用 1.项目部署可能的问题&#xff1a; 大型项目组件较多&#xff0c;运行环境也较为复杂&#xff0c;部署时会碰到一些问题&#xff1…

开源智慧园区管理系统对比其他十种管理软件的优势与应用前景分析

内容概要 在当今数字化快速发展的时代&#xff0c;园区管理软件的选择显得尤为重要。而开源智慧园区管理系统凭借其独特的优势&#xff0c;逐渐成为用户的新宠。与传统管理软件相比&#xff0c;它不仅灵活性高&#xff0c;而且具有更强的可定制性&#xff0c;让各类园区&#…

【C++】P5734 【深基6.例6】文字处理软件

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目描述&#x1f4af;题目描述输入格式输出格式示例输入与输出输入&#xff1a;输出&#xff1a; &#x1f4af;我的做法操作1&#xff1a;在文档末尾插入字符串操作2&…

CSS核心

CSS的引入方式 内部样式表是在 html 页面内部写一个 style 标签&#xff0c;在标签内部编写 CSS 代码控制整个 HTML 页面的样式。<style> 标签理论上可以放在 HTML 文档的任何地方&#xff0c;但一般会放在文档的 <head> 标签中。 <style> div { color: r…

013-51单片机红外遥控器模拟控制空调,自动制冷制热定时开关

主要功能是通过红外遥控器模拟控制空调&#xff0c;可以实现根据环境温度制冷和制热&#xff0c;能够通过遥控器设定温度&#xff0c;可以定时开关空调。 1.硬件介绍 硬件是我自己设计的一个通用的51单片机开发平台&#xff0c;可以根据需要自行焊接模块&#xff0c;这是用立创…

CMake项目编译与开源项目目录结构

Cmake 使用简单方便&#xff0c;可以跨平台构建项目编译环境&#xff0c;尤其比直接写makefile简单&#xff0c;可以通过简单的Cmake生成负责的Makefile文件。 如果没有使用cmake进行编译&#xff0c;需要如下命令&#xff1a;&#xff08;以muduo库echo服务器为例&#xff09;…

OPENPPP2 —— VMUX_NET 多路复用原理剖析

在阅读本文之前&#xff0c;必先了解以下几个概念&#xff1a; 1、MUX&#xff08;Multiplexer&#xff09;&#xff1a;合并多个信号到单一通道。 2、DEMUX&#xff08;Demultiplexer&#xff09;&#xff1a;从单一通道分离出多个信号。 3、单一通道&#xff0c;可汇聚多个…

语言月赛 202412【正在联系教练退赛】题解(AC)

》》》点我查看「视频」详解》》》 [语言月赛 202412] 正在联系教练退赛 题目背景 在本题中&#xff0c;我们称一个字符串 y y y 是一个字符串 x x x 的子串&#xff0c;当且仅当从 x x x 的开头和结尾删去若干个&#xff08;可以为 0 0 0 个&#xff09;字符后剩余的字…

【数据结构】_链表经典算法OJ:复杂链表的复制

目录 1. 题目链接及描述 2. 解题思路 3. 程序 1. 题目链接及描述 题目链接&#xff1a;138. 随机链表的复制 - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;…

python的pre-commit库的使用

在软件开发过程中&#xff0c;保持代码的一致性和高质量是非常重要的。pre-commit 是一个强大的工具&#xff0c;它可以帮助我们在提交代码到版本控制系统&#xff08;如 Git&#xff09;之前自动运行一系列的代码检查和格式化操作。通过这种方式&#xff0c;我们可以确保每次提…

【C语言入门】解锁核心关键字的终极奥秘与实战应用(三)

目录 一、auto 1.1. 作用 1.2. 特性 1.3. 代码示例 二、register 2.1. 作用 2.2. 特性 2.3. 代码示例 三、static 3.1. 修饰局部变量 3.2. 修饰全局变量 3.3. 修饰函数 四、extern 4.1. 作用 4.2. 特性 4.3. 代码示例 五、volatile 5.1. 作用 5.2. 代码示例…

音标-- 02-- 重音 音节 变音

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 国际音标1.重音2.音节3.变音 国际音标 1.重音 2.音节 3.变音

[STM32 标准库]EXTI应用场景 功能框图 寄存器

一、EXTI 外部中断在嵌入式系统中有广泛的应用场景&#xff0c;如按钮开关控制&#xff0c;传感器触发&#xff0c;通信接口中断等。其原理都差不多&#xff0c;STM32会对外部中断引脚的边沿进行检测&#xff0c;若检测到相应的边沿会触发中断&#xff0c;在中断中做出相应的处…

C语言练习【互斥锁、信号量线程同步、条件变量实现生产者消费者模型】

练习1 请使用互斥锁 和 信号量分别实现5个线程之间的同步 互斥锁实现同步 #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>…

w190工作流程管理系统设计与实现

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;原创团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339;赠送计算机毕业设计600个选题excel文…

linux下ollama更换模型路径

Linux下更换Ollama模型下载路径指南   在使用Ollama进行AI模型管理时&#xff0c;有时需要根据实际需求更改模型文件的存储路径。本文将详细介绍如何在Linux系统中更改Ollama模型的下载路径。 一、关闭Ollama服务   在更改模型路径之前&#xff0c;需要先停止Ollama服务。…

编程题-电话号码的字母组合(中等)

题目&#xff1a; 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 解法一&#xff08;哈希表动态添加&#xff09;&#x…