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

news/2025/2/4 11:12:01 标签: express, javascript, sqlite

使用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.niftyadmin.cn/n/5841507.html

相关文章

追逐低空经济,无人机研学技术详解

追逐低空经济&#xff0c;无人机研学技术成为了一个备受关注的领域。以下是对无人机研学技术的详细解析&#xff1a; 一、无人机研学技术概述 无人机研学技术是以无人机为核心&#xff0c;结合航空科技、电子技术、机械原理等多领域知识的一种教育实践活动。它旨在通过理论学习…

【leetcode100】路径总和Ⅲ

1、题目描述 给定一个二叉树的根节点 root &#xff0c;和一个整数 targetSum &#xff0c;求该二叉树里节点值之和等于 targetSum 的 路径 的数目。 路径 不需要从根节点开始&#xff0c;也不需要在叶子节点结束&#xff0c;但是路径方向必须是向下的&#xff08;只能从父节点…

利用Vue和javascript分别编写一个“Hello World”的定时更新

目录 一、利用Vue编写一个“Hello World”的定时更新&#xff08;1&#xff09;vue编码在Html文件中&#xff08;2&#xff09;vue编码在js文件中 二、利用javascript编写一个“Hello World”的定时更新 一、利用Vue编写一个“Hello World”的定时更新 &#xff08;1&#xff…

第三章:筑基-React基础篇控制首页大盘搭建

监控和显示: 控制器仪表大盘通常会显示关键的参数、数据和状态信息,帮助操作人员了解系统的运行情况。这些信息可能包括温度、压力、流量、速度等各种传感器数据,以及设备的状态、警报和故障信息等。控制和调节: 通过控制器仪表大盘,操作人员可以对系统进行调节和控制,例…

对比JSON和Hessian2的序列化格式

在分布式系统中&#xff0c;数据的序列化和反序列化是关键环节。不同的序列化格式在性能、可读性和跨语言兼容性上存在显著差异。本文将详细对比JSON和Hessian2这两种序列化格式&#xff0c;以帮助开发者在不同的应用场景中做出更好的选择。 JSON 概述 JSON&#xff08;Java…

自动化软件测试的基本流程

一、自动化测试的准备 1.1 了解测试系统 首先对于需要测试的系统我们需要按照软件需求说明书明确软件功能。这里以智慧养老系统作为案例进行测试&#xff0c;先让我们看看该系统的登录界面和用户管理界面。 登录界面&#xff1a; 登录成功默认界面&#xff1a; 用户管理界面…

记忆化搜索和动态规划 --最长回文子串为例

记忆化搜索 记忆化搜索是一种优化递归算法的方法&#xff0c;通过将已经计算过的子问题的结果存储起来&#xff08;通常使用哈希表或数组&#xff09;&#xff0c;避免重复计算相同的子问题。 本质上是通过缓存中间结果来减少计算的重复性。 动态规划 动态规划是通过将问题分…

Spring Boot 2 快速教程:WebFlux处理流程(五)

WebFlux请求处理流程 下面是spring mvc的请求处理流程 具体步骤&#xff1a; 第一步&#xff1a;发起请求到前端控制器(DispatcherServlet) 第二步&#xff1a;前端控制器请求HandlerMapping查找 Handler &#xff08;可以根据xml配置、注解进行查找&#xff09; 匹配条件包括…