koa2從搭建項目到實現API

koa2,之前沒有接觸過,只知道是express的原班人馬開發的,在一些方面優於express,又經歷了一次從koa到koa2的升級,應該說是比較成熟的了。
根據如今的技術實現方案,如今大部分的web服務基本都是先後端分離模式的,因此koa2的讓web應用開發和api的使用更加簡便優點,更值得咱們去學習。javascript

本文只簡單介紹將環境搭建起來,可讓初次學習koa或者web應用的同窗可以更快的看到學習成果,增長學習的自信心,其中涉及到的不少的知識和技術點,咱們後續補充,不在本文作過多的闡述
本文的目的就是作知識的普及,文中可能會有些代碼是從網絡中複製的,可是都是親手調試可運行,保證代碼的正常運行的

搭建環境

  1. 安裝node

這個不用想也不用考慮,koa項目是基於node的,上來什麼都別說,先安裝node。但這裏有個細節須要注意,node須要最低版本爲7.6.0,主要是爲了一些es6的語法支持。前端

brew install node
我這裏是在mac環境上安裝的node,因爲本人習慣使用homebrew安裝,若是不是mac環境的同窗,也能夠直接到官網下載安裝包安裝。這個步驟比較簡單,通常狀況下看下官網的文檔介紹,能夠直接搞定。
node安裝完成後,要查看下node的版本,有兩個目的,一是查看node是否安裝成功,再就是檢查是否知足koa的版本需求。
node -v
npm -v
npm集成到node中了,只要成功的安裝了node,npm也會被成功安裝。
  1. 安裝koa

咱們學習和應用的是koa項目,就先安裝上koa吧。
npm install koa --savejava

  1. 安裝koa2項目生成器並建立項目
npm install koa-generator -g
koa2 bbs

這裏的koa-generator,並非官方的項目生成器,而是狼叔-桑世龍爲咱們貢獻的財富,在這裏,咱們感謝狼叔。
koa2 bbs,這行代碼建立了基於koa2的項目,並生成基本的項目架構。基本的項目架構以下:
koa2項目基本架構圖node

  1. 安裝依賴

項目也建立完了,可是隻是完成了一個基本的骨架,尚未血肉,接下來就須要安裝項目的依賴了mysql

cd bbs
npm install

這個步驟可能消耗的時間有點長,這個和網絡環境有關,因爲網絡的緣由,還有可能某些依賴會安裝失敗,這個時候,咱們能夠經過修改npm鏡像來減小因爲網絡環境致使安裝依賴失敗的問題。
具體可參考淘寶NPM鏡像git

  1. 啓動服務
npm start

npm能夠啓動服務,但不支持熱更新,咱們這裏只是測試項目可否正常啓動,執行,熱更新的內容,咱們後續再講。
服務正常啓動以後,瀏覽器輸入:localhost:3000,若是頁面中展現瞭如"Hello Koa 2"的內容,說明項目搭建成功。es6

搭建項目

這裏的搭建項目,不是前面的使用koa2初始化一個項目,而是把前面經過koa2初始化的項目補充養分,讓它豐滿起來。github

  1. 安裝sequelize

暫且不要關心sequelize是什麼,之後會有專題細講,只須要了解一點就能夠了:Sequelize是一個基於promise的nodejs ORM,目前支持Postgres、mysql、SQLite和Microsoft SQL Server。它具備強大的事務支持,關聯關係,讀取和複製等功能。web

npm install sequelize --save
  1. 安裝mysql、mysql2

項目須要mysql的數據庫支持sql

npm install mysql mysql2 --save
  1. 配置Sequelize的數據庫連接

在項目的根目錄下建立一個config目錄,config目錄中建立db.js,該文件主要用來建立mysql的數據庫連接的。

const Sequelize = require('sequelize');
const sequelize = new Sequelize('dbname','dbusername','password',{
    host:'localhost',
    dialect:'mysql',
    operatorsAliases:false,
    dialectOptions:{
        //字符集
        charset:'utf8mb4',
        collate:'utf8mb4_unicode_ci',
        supportBigNumbers: true,
        bigNumberStrings: true
    },
    pool:{
        max: 5,
        min: 0,
        acquire: 30000,
        idle: 10000
    },
    timezone: '+08:00'  //東八時區
});

module.exports = {
    sequelize
};

這些代碼能夠直接使用,只須要將代碼中實例化Sequelie對象語句中的dbname更改成你的數據庫名,dbusername更改成你的數據庫用戶名,passoword更改成你的數據庫密碼,其中數據庫名和數據庫用戶名不能爲空,密碼能夠爲空,爲空時則爲空的字符串就能夠了。

const sequelize = new Sequelize('bbs','root','',{
……
  1. 建立schema、modules、controllers

schema:數據表模型實例
modules:實體模型
controllers:控制器
3個目錄下分別建立article.js。目錄結構

  1. schema數據表模型

在schema目錄下新建一個article.js文件,該文件的主要做用就是創建與數據表的對應關係,也能夠理解爲代碼的建表。
首先來分析表結構:

字段 說明 是否必填
id 文章自增ID,主鍵 否,自動填的
title 文章標題
author 做者
content 文章內容
category 文章分類

分析表結構,主要是爲了用來建表的,表結構,是咱們根據實體的關係抽象出來的實體關係,根據這些關係創建表,將實體的關係存儲到表中。建表有兩種方式:一是使用mysql數據庫的命令行工具或者UI工具建表,再就是使用咱們前面介紹的Sequelize,讓程序去建立表。
使用mysql工具建表方式:

DROP TABLE IF EXISTS `article`;
CREATE TABLE `article` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL,
  `author` varchar(255) NOT NULL,
  `content` varchar(255) NOT NULL,
  `category` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
SET FOREIGN_KEY_CHECKS = 1;

這是使用sql語句建立表的方式,咱們看另外一種藉助Sequelize建表方式(Sequelize不光是能建表,還能作數據庫的管理);
咱們剛纔在schema目錄下的article.js用來建立數據表模型的,也能夠理解爲建立一張數據表,代碼以下:

const moment = require("moment");
module.exports = function(sequelize,DataTypes){
    return sequelize.define('article',{
        id:{
            type: DataTypes.INTEGER,
            primaryKey: true,
            allowNull: true,
            autoIncrement: true
        },
        //文章標題
        title:{
            type: DataTypes.STRING,
            allowNull: false,
            field: 'title'
        },
        //做者
        author:{
            type: DataTypes.STRING,
            allowNull: false,
            field: 'author'
        },
        //內容
        content:{
            type: DataTypes.STRING,
            allowNull: false,
            field:'content'
        },
        //文章分類
        category:{
            type: DataTypes.STRING,
            allowNull: false,
            field: 'category'
        },
        // 建立時間
        createdAt:{
            type: DataTypes.DATE
        },
        // 更新時間
        updatedAt:{
            type: DataTypes.DATE
            }
        }
    },{
        /**
         * 若是爲true,則表示名稱和model相同,即user
         * 若是爲fasle,mysql建立的表名稱會是複數,即users
         * 若是指定的表名稱自己就是複數,則形式不變
         */
        freezeTableName: true
    });
}
  1. 模型應用、使用

在項目中modules目錄下建立article.js文件,爲文章表,該文件爲文章的實例。

// 引入mysql的配置文件
const db = require('../config/db');

// 引入sequelize對象
const Sequelize = db.sequelize;

// 引入數據表模型
const Article = Sequelize.import('../schema/article');
Article.sync({force: false}); //自動建立表

class ArticleModel {
    /**
     * 建立文章模型
     * @param data
     * @returns {Promise<*>}
     */
    static async createArticle(data){
        return await Article.create({
            title: data.title, //標題
            author: data.author,  //做者
            content: data.content,  //文章內容
            category: data.category //文章分類
        });
    }

    /**
     * 查詢文章的詳情
     * @param id 文章ID
     * @returns {Promise<Model>}
     */
    static async getArticleDetail(id){
        return await Article.findOne({
            where:{
                id
            }
        });
    }
}

module.exports = ArticleModel;
  1. controller 控制器

控制器的主要做用爲功能的處理,項目中controller目錄下建立article.js,代碼以下:

const ArticleModel = require("../modules/article");

class articleController {
    /**
     * 建立文章
     * @param ctx
     * @returns {Promise.<void>}
     */
    static async create(ctx){
        //接收客服端
        let req = ctx.request.body;
        if(req.title && req.author && req.content && req.category){
            try{
                //建立文章模型
                const ret = await ArticleModel.createArticle(req);
                //使用剛剛建立的文章ID查詢文章詳情,且返回文章詳情信息
                const data = await ArticleModel.getArticleDetail(ret.id);

                ctx.response.status = 200;
                ctx.body = {
                    code: 200,
                    msg: '建立文章成功',
                    data
                }
            }catch(err){
                ctx.response.status = 412;
                ctx.body = {
                    code: 412,
                    msg: '建立文章失敗',
                    data: err
                }
            }
        }else {
            ctx.response.status = 416;
            ctx.body = {
                code: 200,
                msg: '參數不齊全'
            }
        }
    }

    /**
     * 獲取文章詳情
     * @param ctx
     * @returns {Promise.<void>}
     */
    static async detail(ctx){
        let id = ctx.params.id;
        if(id){
            try{
                // 查詢文章詳情模型
                let data = await ArticleModel.getArticleDetail(id);
                ctx.response.status = 200;
                ctx.body = {
                    code: 200,
                    msg: '查詢成功',
                    data
                }
            }catch(err){
                ctx.response.status = 412;
                ctx.body = {
                    code: 412,
                    msg: '查詢失敗',
                    data
                }
            }
        }else {
            ctx.response.status = 416;
            ctx.body = {
                code: 416,
                msg: '文章ID必須傳'
            }
        }
    }
}

module.exports = articleController;
  1. 路由

路由,也能夠簡單理解爲路徑,主要是做爲請求的url,請求的路徑來處理一些請求,返回數據。通常狀況下,基於node的項目,路由都是在一個叫作routes的目錄下面。

const Router = require('koa-router');
const ArtileController = require('../controllers/article');

const router = new Router({
  prefix: '/api/v1'
});

/**
 * 文章接口
 */
//建立文章
router.post('/article/create',ArtileController.create);

//獲取文章詳情
router.get('/article/:id',ArtileController.detail)

module.exports = router
  1. 啓動服務

這裏主要測試服務可否正常啓動,可否正常運行。

npm start

若是啓動過程當中出現下面的結果,說明服務啓動成功

➜  bbs npm start

> bbs@0.1.0 start /usr/local/var/www/koa/bbs
> node bin/www

koa deprecated Support for generators will be removed in v3. See the documentation for examples of how to convert old middleware https://github.com/koajs/koa/blob/master/docs/migration.md app.js:20:5
Ignoring invalid configuration option passed to Connection: collate. This is currently a warning, but in future versions of MySQL2, an error will be thrown if you pass an invalid configuration options to a Connection
Ignoring invalid configuration option passed to Connection: collate. This is currently a warning, but in future versions of MySQL2, an error will be thrown if you pass an invalid configuration options to a Connection
Executing (default): CREATE TABLE IF NOT EXISTS `article` (`id` INTEGER auto_increment , `title` VARCHAR(255) NOT NULL, `author` VARCHAR(255) NOT NULL, `content` VARCHAR(255) NOT NULL, `category` VARCHAR(255) NOT NULL, `createdAt` DATETIME, `updatedAt` DATETIME, PRIMARY KEY (`id`)) ENGINE=InnoDB;
Executing (default): SHOW INDEX FROM `article`

接下來,就能夠測試接口了。
我使用的測試接口工具爲postman,之前postman好像是做爲瀏覽器的一個插件存在的,如今不做爲瀏覽器的插件了,直接作成了應用了,能夠直接從postmna官網下載。 官網地址https://www.getpostman.com/,而後咱們根據咱們的系統平臺來選擇合適的版本下載就能夠了。

  1. 解決跨域

跨域是web開發中不可避免的一個必需要解決的問題了。跨域問題,主要是要解決服務器端的通訊問題。在node的開發中,只須要實現一個CORS標準就能夠了。

npm install koa-cors --save

而後在根目錄下的app.js加入koa-cors的引用:

const cors = require('koa-cors')
app.use(cors()) //使用cors

而後從新啓動服務。到這裏爲止,還不能支持熱更新,如今主要測試功能,暫且先這麼手動重啓吧,後面會有專題描述熱更新服務。

  1. 測試接口

前面我下載而且安裝好了postman,工具備了,代碼層面也準備就緒,解決了跨域問題,下面就能夠測試接口是否可用了。
測試接口,咱們先看下咱們的路由管理文件routes目錄下的index.js文件。

//建立文章
router.post('/article/create',ArtileController.create);

//獲取文章詳情
router.get('/article/:id',ArtileController.detail)

這裏有2個文章相關的接口,一個是建立新文章,一個是獲取文章詳情。咱們先來測試建立新的文章。
看路由,建立新文章須要的請求方式爲post,url爲/article/create,那咱們就根據這些信息使用postman進行測試吧。
建立新文章
這是我建立新文章的接口測試,而後看測試結果:
接口測試成功
運行結果告訴咱們建立新文章的接口已經測試成功了,說明這個接口能夠走通了。若是咱們如今是先後端分離的開發模式,咱們須要提供api的話,那麼這個api就能夠提供給前端同窗使用了。
咱們也能夠從數據庫中驗證一下執行結果的正確性:
數據添加成功
數據也成功插入到數據庫中了,咱們也更加驗證了咱們接口的正確性和可執行性了,這個接口到此結束。
而後看下一個獲取文章詳情的接口。須要使用get的請求方式,請求的URL爲/article/:id。
獲取文章詳情
成功獲取文章詳情

總結

到如今爲止,咱們基本已經完成了從0開始搭建一個koa項目,並完成一些簡單的api接口的實現,固然了,只是最基本的實現,裏面還有不少可優化的空間,對於一個做爲入門案例來講,已經夠了。對於有深刻了解或學習的朋友,但願咱們功能學習,共同提升。

相關文章
相關標籤/搜索