接口设计

一、接口设计规范:RESTful

①参考文档:理解RESTful架构RESTful API 设计指南

HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源

③具体:

  • GET(SELECT):从服务器取出资源(一项或多项)。

  • POST(CREATE):在服务器新建一个资源。

  • PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。

  • PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。

  • DELETE(DELETE):从服务器删除资源。

  • HEAD:获取资源的元数据。

  • OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。

二、案例(基于RESTful接口设计规范来设计接口)

①把SQL语句导入MySQL数据库,生成数据表

--Community management website

CREATE DATABASE IF NOT EXISTS cms;

use cms;

-- 用户表
CREATE TABLE users(
    id INT PRIMARY  KEY auto_increment,
    username VARCHAR(50) NOT NULL, -- 用户名
    password VARCHAR(50) NOT NULL, -- 密码
    email VARCHAR(50) NOT NULL, -- 邮箱
    avater VARCHAR(100) NULL, -- 头像
    gender bit NULL, --性别
    create_time DATETIME NOT NULL, -- 创建时间
    modify_time DATETIME NOT NULL, -- 修改时间
    nickname VARCHAR(50) NOT NULL -- 昵称
);

-- 话题表
CREATE TABLE topics(
    id INT PRIMARY KEY auto_increment, 
    title VARCHAR(100) NOT NULL, -- 文章标题
    content TEXT NOT NULL, -- 文字内容
    user_id INT NOT NULL,  -- 所属用户
    create_time DATETIME NOT NULL, -- 发布时间
    modify_time DATETIME NOT NULL -- 修改时间
); 

-- 评论表
CREATE TABLE comments(
    id INT PRIMARY KEY auto_increment,
    content TEXT NOT NULL, -- 评论内容
    create_time DATETIME NOT NULL, -- 评论时间
    modify_time DATETIME NOT NULL,
    article_id INT NOT NULL, -- 所属文章
    user_id INT NOT NULL, -- 所属用户
    reply_id INT NULL -- 所属回复人
);

②创建目录结构

③设计路由,编写路由代码,编写控制器函数 router.js

const express = require('express');
const router = express.Router() ;
const userController = require('./controllers/user');
const topicsController = require('./controllers/topic');
const commentController = require('./controllers/comment');
const sessionController = require('./controllers/session');

//用户资源
router
    .get('/users',userController.list)
    .post('/users',userController.create)
    .patch('/users/:id',userController.update)
    .delete('/users/:id',userController.destroy)    
//话题资源
router
    .get('/topics',topicsController.list)
    .post('/topics',topicsController.create)
    .patch('/topics/:id',topicsController.update)
    .delete('/topics/:id',topicsController.destroy)

//评论资源
router
    .get('/comments',commentController.list)
    .post('/comments',commentController.create)
    .patch('/comments/:id',commentController.update)
    .delete('/comments/:id',commentController.destroy)

//会话资源
router
    .get('/session',sessionController.get)
    .post('/session',sessionController.create)
    .delete('/session/:id',sessionController.destroy)

//导出router (重要)
module.exports = router;

④封装 Promise版本的db.query方法 db.js

const mysql = require('mysql');
// 使用连接池:效率更高,不需要每次操作数据库都要三步走
const pool =mysql.createPool({
    host:'localhost',
    user:'root',
    password:'123456',
    database:'cms'
});
exports.query = function(sqlStr){
    // 从连接池从拿一个连接,使用promise的方法
    return new Promise((resolve,reject) =>{
        pool.getConnection((err,connection) => {
            if(err){
                return reject(err)
            }
            connection.query(sqlStr,(err,...args) => {
                // 操作完连接,尽早释放连接 
                connection.release()
                if(err){
                    return reject(err)
                }
                resolve(...args)
            })
        })
    })
}

⑤用户管理:创建用户 user.js

const md5 = require('blueimp-md5');
const moment = require('moment');
const db = require('../models/db');


exports.list = (req,res,next) => {
    //待完成
};
exports.create = async (req,res,next) => {
    const body=req.body;
    const sqlStr=`
    INSERT INTO users(username,password,email,avater,gender,create_time,modify_time,nickname)
    VALUES(
        '${body.email}',
        '${md5(md5(body.password))}',
        '${body.email}',
        'default-avater.png',
        0,
        '${moment().format('YYYY-MM-DD hh:mm:ss')}',
        '${moment().format('YYYY-MM-DD hh:mm:ss')}',
        '${body.nickname}'
    )`;
    // 利用try-catch捕获异常:try中的代码一旦出错,立即进入catch代码块
    try{
        const ret = await db.query(sqlStr)
        const users = await db.query(`SELECT * FROM users WHERE id='${ret.insertId}'`)
        body.id = ret.insertId
        res.status(201).json(users[0])
    }catch(err){
        res.status(500).json({
            error:err.message
        })
    }
};
exports.update = (req,res,next) => {
    // 待完成
};
exports.destroy = (req,res,next) => {
    // 待完成
};

⑥会话管理:创建会话,获取会话信息,销毁会话 session.js

const md5 = require('blueimp-md5')
const db = require('../models/db')

// 获取登陆状态
exports.get = (req,res,next) => {
    const {user} = req.session
    if(!req.session.user){
        return res.status(401).json({
            error: 'Unauthorized'
        })
    }
    res.status(200).json(user)
}
// 创建登陆状态
exports.create = async (req,res,next) => {
    try{
        // 接收表单数据
        const body=req.body
        body.password = md5(md5(body.password))
        // 处理数据库登陆请求
        const sqlStr=`
            SELECT * FROM users WHERE email='${body.email}' and password='${body.password}'`
        const [user] = await db.query(sqlStr)
        // 发送响应
        if(!user){
            return res.status(404).json({
                error:'Invalid email or password!'
            })
        }
        req.session.user = user
        res.status(201).json(user)
    }catch(err){
        next(err)
    }
}
// 删除登陆状态
exports.destroy = (req,res,next) => {
    delete req.session.user
    res.status(201).json({})
}

⑦话题管理:创建话题,话题分页列表,删除话题,更新话题 topic.js

const moment = require('moment')
const db = require('../models/db')  

// 分页查询获取所有话题
exports.list = async(req, res, next) => {
    let {_page=1,_limit=20} =req.query //req.query用于获取get请求url ? 后面的参数
    if(_page < 1){_page = 1}
    if(_limit < 1){ _limit = 1}
    if(_limit > 20){_limit = 20}
    const start = (_page-1)*_limit
    try {
        /* 
        第1页  0 20
        第2页  20 20 
        第3页  40 20
        第n页  (_page-1)*_limit _limit  
        */
        const sqlStr = `SELECT * FROM topics LIMIT ${start},${_limit}`
        const topics = await db.query(sqlStr)
        res.status(200).json(topics)
    } catch (error) {
        next(error)
    }
}
// 创建话题
exports.create = async (req, res, next) => {
    try{
        // 登陆校验
        const {user} = req.session
        if(!user){
            return res.status(401).json({
                error:'Unauthorized'
            })
        }
        const body = req.body
        body.create_time = moment().format('YYYY-MM-DD hh:mm:ss')
        body.modify_time = moment().format('YYYY-MM-DD hh:mm:ss')
        body.user_id = user.id
        const sqlStr = `
            INSERT INTO topics(title,content,user_id,create_time,modify_time)
            VALUES('${body.title}','${body.content}','${body.user_id}','${body.create_time}','${body.modify_time}')`
        // 注意:query方法查询返回的是一个数组,增删改返回的是对象
        const ret = await db.query(sqlStr)
        const [topic] = await db.query(`SELECT * FROM topics WHERE id=${ret.insertId}`)
        res.status(201).json(topic)
    }catch(error){
        next(error)
    }
}
// 更新话题
exports.update = async (req, res, next) => {
    try {
        // 登陆校验
        const {user} = req.session
        if(!user){
            return res.status(401).json({
                error:'Unauthorized'
            })
        }
        // id一致校验
        const {id} = req.params
        const [topic] = await db.query(`SELECT * FROM topics WHERE id=${id}`)
        if(!topic){
            return res,status(404).json({
                error: 'this Topic Not Found'
            })
        }
        if(topic.user_id !== req.session.user.id){
            return res.status(400).json({
                error: 'dupdate Invalid'
            })
        }
        const body = req.body
        const sqlStr = `
            UPDATE topics SET title='${body.title}',content='${body.content}',modify_time='${moment().format('YYYY-MM-DD hh:mm:ss')}'
            WHERE id=${id}
        `
        await db.query(sqlStr)
        const [updatedTopic] = await db.query(`SELECT * FROM topics WHERE id=${id}`)
        res.status(201).json(updatedTopic)
    } catch (error) {
        next(error)
    }
}
// 删除话题
exports.destroy = async (req, res, next) => {
    try {
        // 登陆校验
        const {user} = req.session
        if(!user){
            return res.status(401).json({
                error:'Unauthorized'
            })
        }
        // url 中的:id叫做动态路由参数,
        //总结:查询字符串req.query,post请求体req.body,动态路由参数req.params
        const {id} = req.params
        // 判断话题是否存在或者话题的ID是否和删除话题的ID一致
        const [topic] = await db.query(`SELECT * FROM topics WHERE id=${id}`)
        if(!topic){
            return res,status(404).json({
                error: 'this Topic Not Found'
            })
        }
        if(topic.user_id !== req.session.user.id){
            return res.status(400).json({
                error: 'DELETE Invalid'
            })
        }
        const sqlStr = `DELETE FROM topics WHERE id=${id}`
        await db.query(sqlStr)
        res.status(201).json({})
    } catch (error) {
        next(error)
    }
}

⑧评论管理:创建评论

const db = require('../models/db')
const moment = require('moment')

exports.list = (req,res,next) => {
    // 待补
}
exports.create = async (req,res,next) => {
    try {
        // 登陆校验
        const {user} = req.session
        if(!user){
            return res.status(401).json({
                error:'Unauthorized'
            })
        }
        // 获取表单数据-->操作数据库-->发送响应数据
        const body = req.body
        body.create_time = moment().format('YYYY-MM-DD hh:mm:ss')
        body.modify_time = moment().format('YYYY-MM-DD hh:mm:ss')
        const sqlStr = `
        INSERT INTO comments(content,create_time,modify_time,article_id,user_id)
        VALUES(
            '${body.content}',
            '${body.create_time}',
            '${body.modify_time}',
            '${body.article_id}',
            '${req.session.user.id}'
        )`
        const {insertId} = await db.query(sqlStr)
        const [comment] = await db.query(`SELECT *FROM comments WHERE id=${insertId}`)
        res.status(201).json(comment)
    } catch (error) {
        next(error)
    }
}
exports.update = (req,res,next) => {
    // 待补
}
exports.destroy = (req,res,next) => {
    // 待补
}

⑨启动文件 app.js

const express = require('express');
const router = require('./router');
const bodyParser = require('body-parser');
const session = require('express-session')

const app=express();

// 配置body-parser
app.use(bodyParser.urlencoded({extended:false}));
app.use(bodyParser.json());

// 配置使用express-session
app.use(session({
    secret:'loaduser',
    resave:false,
    saveUninitialized:false
}));

// 把路由应用到app中
app.use(router);

app.listen(3000,() => {
    console.log('App is running at port 3000, please visit http://127.0.0.1:3000/')
});

⑩使用postman配合MySQL数据库进行接口调试

项目未完成....

原文地址:https://www.cnblogs.com/EricZLin/p/9427582.html