zoukankan      html  css  js  c++  java
  • 接口设计

    一、接口设计规范: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数据库进行接口调试

    项目未完成....

  • 相关阅读:
    bootstrap-table对前台页面表格的支持
    解决拦截器对ajax请求的的拦截
    jQuery获取鼠标事件源(万能)
    HtmlAgilityPack 处理通配的contains
    【转】XPath的学习
    在IIS服务器上部署svg/woff/woff2字体
    【转】万网域名查询接口(API)的说明
    html5和css3的常用参考网
    【转】Xml序列化
    C#序列化s实体类成Xml,去除空格、换行符以及命名空间
  • 原文地址:https://www.cnblogs.com/EricZLin/p/9427582.html
Copyright © 2011-2022 走看看