Egg.js 搭建開發(fā)環(huán)境 -- 前后端分離 + swagger文檔 搭好就直接開發(fā)API

前言

使用express和koa2開發(fā)api都比較自由沒有一個統(tǒng)一的開發(fā)規(guī)范,并且讓初學(xué)者學(xué)起來感覺有點(diǎn)混亂,使用egg.js開發(fā)api有一種用vue開發(fā)的感覺非常舒服,但是使用egg.js其實(shí)里面還有挺多道道的,搭個開發(fā)環(huán)境順便學(xué)習(xí)一下egg.js不是美滋滋。


1.搭建egg.js腳手架

egg.js 快速入門

mkdir egg-example && cd egg-example
cnpm init egg --type=simple
cnpm i
npm run dev
open http://localhost:7001

2.跨域配置

cnpm i egg-cors --save

// app/config/plugin.js

exports.static = true;

// 跨域
exports.cors = {
  enable: true,
  package: 'egg-cors',
};
// app/config/config.default.js
  // 安全配置
  config.security = {
    csrf: {
      enable: false,
      ignoreJSON: true
    },
    domainWhiteList: ['*']
  };

  // 跨域配置
  config.cors = {
    origin: '*',
    allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH'
  };

3.安裝egg-swagger-doc

cnpm i egg-swagger-doc --save
egg-swagger-ui文檔


// app/config/plugin.js

// swagger文檔
exports.swaggerdoc = {
  enable: true,
  package: 'egg-swagger-doc',
};
// app/config/config.default.js
  // swagger文檔配置
  config.swaggerdoc = {
    dirScanner: './app/controller', //插件掃描的文檔路徑
    apiInfo: {
      title: 'swagger文檔',
      description: 'egg.js swagger-demo文檔',
      version: '1.0.0',
    },
    consumes: ['application/json','multipart/form-data'], // 指定處理請求的提交內(nèi)容類型(Content-Type),例如application/json, text/html
    produces: ['application/json','multipart/form-data'], // 指定返回的內(nèi)容類型,僅當(dāng)request請求頭中的(Accept)類型中包含該指定類型才返回
    schemes: ['http', 'https'],
    routerMap: true, // 是否自動生成route
    enable: true,
  };
// app/router.js
'use strict';

/**
 * @param {Egg.Application} app - egg application
 */

module.exports = app => { 
 //重定向到swagger-ui.html
  app.router.redirect('/', '/swagger-ui.html', 302);
}

1.在app目錄下新建文件夾 contract(必須) 和 service(備用)
1.1在contract目錄下新建目錄response 和 request 目錄
1.2在response目錄下新建base.js

// app/contract/response/base.js
'use strict';

module.exports = {
  // 測試模塊
  testResponse: {
    message: { type: 'string' }
  }
};

設(shè)置一下測試
2.在controller目錄下把home.js改成test.js

'use strict';

const Controller = require('egg').Controller;

/**
 * @Controller 測試
 */

class TestController extends Controller {

    /**
      * @summary 接口測試
      * @description 測試swagger文檔是否可用
      * @router get /api/v1/test
      * @request query string str 隨機(jī)字符串
      * @response 200 testResponse
      */
    async test() {
        const { ctx } = this;

        const str = ctx.query.str

        ctx.body = await {
            message: 'swagger is OK!!! and query is:' + str
        }
    }
}

module.exports = TestController;

休息一下....npm run dev 跑一下看看能跑動不 如能出現(xiàn)swagger界面就繼續(xù)

輸入127.0.0.1:7001

4.設(shè)置調(diào)試

egg.js調(diào)試文檔

// .vscode/launch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Launch Egg",
      "type": "node",
      "request": "launch",
      "cwd": "${workspaceRoot}",
      "runtimeExecutable": "npm",
      "windows": { "runtimeExecutable": "npm.cmd" },
      "runtimeArgs": [ "run", "debug" ],
      "console": "integratedTerminal",
      "protocol": "auto",
      "restart": true,
      "port": 9229,
      "autoAttachChildProcesses": true
    }
  ]
}

6.安裝mysql

mysql安裝方法

7.初始化數(shù)據(jù)庫

初始化三個數(shù)據(jù) 開發(fā)環(huán)境數(shù)據(jù)庫 測試環(huán)境數(shù)據(jù)庫 生產(chǎn)環(huán)境數(shù)據(jù)庫
mysql -u root -p -e 'CREATE DATABASE IF NOT EXISTS dev_db;'
mysql -u root -p -e 'CREATE DATABASE IF NOT EXISTS test_db;'
mysql -u root -p -e 'CREATE DATABASE IF NOT EXISTS pord_db;'
沒有密碼的話可以把 -p 去掉

在vscode里面搞

可以看到數(shù)據(jù)庫初始化了

8.安裝egg-sequelize sequelize-cli mysql2

cnpm install --save egg-sequelize mysql2
cnpm install --save-dev sequelize-cli
egg-sequelize文檔
mysql2文檔
sequelize-cli文檔
egg.js sequelize教程
使用 sequelize-cli 可以創(chuàng)建模型和遷移文件 同步到數(shù)據(jù)庫中 (但是我不這樣做)

// app/config/plugin.js
// sequelize ORM
exports.sequelize = {
  enable: true,
  package: 'egg-sequelize',
};
// app/config/config.default.js
  // 訪問數(shù)據(jù)庫
  config.sequelize = {
    dialect: 'mysql', // 數(shù)據(jù)庫類型,支持 mysql,sqlite,mssql,pgsql,oracle。
    host: '127.0.0.1', // 數(shù)據(jù)庫服務(wù)器地址。
    port: 3306, // 數(shù)據(jù)庫連接端口號。
    database: 'dev_db', // 數(shù)據(jù)庫名稱。
    username: "root", // 數(shù)據(jù)庫登錄用戶名。
    password: "111111", // 數(shù)據(jù)庫登錄密碼。   
    timezone: '+08:00', // 時區(qū) 東八區(qū)
    underscored: true,// 是否自動進(jìn)行下劃線轉(zhuǎn)換(這里是因?yàn)镈B默認(rèn)的命名規(guī)則是下劃線方式,而我們使用的大多數(shù)是駝峰方式)
    define: {
      freezeTableName: true, // Model 對應(yīng)的表名將與model名相同。
      timestamps: false // 默認(rèn)情況下,Sequelize會將createdAt和updatedAt的屬性添加到模型中,以便您可以知道數(shù)據(jù)庫條目何時進(jìn)入數(shù)據(jù)庫以及何時被更新。
    }
  };

8.1 在 egg 項(xiàng)目中,我們希望將所有數(shù)據(jù)庫 Migrations 相關(guān)的內(nèi)容都放在 database 目錄下,所以我們在項(xiàng)目根目錄下新建一個 .sequelizerc 配置文件:

'use strict';

const path = require('path');

module.exports = {
  config: path.join(__dirname, 'database/config.json'),
  'migrations-path': path.join(__dirname, 'database/migrations'),
  'seeders-path': path.join(__dirname, 'database/seeders'),
  'models-path': path.join(__dirname, 'app/model'),
};

8.2 初始化 Migrations 配置文件和目錄

npx sequelize init:config
npx sequelize init:migrations

8.3 如果出現(xiàn)了database目錄 那這一步就操作成功了。
執(zhí)行完后會生成 database/config.json 文件和 database/migrations 目錄,我們修改一下 database/config.json 中的內(nèi)容,將其改成我們項(xiàng)目中使用的數(shù)據(jù)庫配置:
根據(jù)egg.js對數(shù)據(jù)庫的環(huán)境配置

{
  "development": {
    "username": "root",
    "password": 111111,
    "database": "dev_db",
    "host": "127.0.0.1",
    "dialect": "mysql",
    "timezone": "+08:00"
  },
  "test": {
    "username": "root",
    "password": 111111,
    "database": "test_db",
    "host": "127.0.0.1",
    "dialect": "mysql",
    "timezone": "+08:00"
  },
  "production": {
    "username": "root",
    "password": 111111,
    "database": "prod_db",
    "host": "127.0.0.1",
    "dialect": "mysql",
    "timezone": "+08:00"
  }
}

到了這一步就可以建模型(表)了

sequelize-cli操作流程

9.安裝 egg-sequelize-auto

但是我在網(wǎng)上找到了一個叫做 egg-sequelize-auto 的東東,可以自動對照數(shù)據(jù)庫表生成模型
個人感覺在sequelize生成模型操作比較復(fù)雜,一般都是在外面把表設(shè)計(jì)好之后再開始寫模型的
通過表自動生成模型不是美滋滋~~~

cnpm install -g egg-sequelize-auto
egg-sequelize-auto文檔

剛我們安裝過mysql2了 但是是安裝在--save
這里是全局安裝 還需要全局安裝一個mysql2

cnpm install mysql2 -g

-o 表示生成 models 的路徑,-h 表示主機(jī),-p 表示端口,-d 表示數(shù)據(jù)庫, -u 表示用戶名,-x 表示密碼 -e 表示數(shù)據(jù)庫

// package.json
// 在scripts里添加
 "scripts": {
    "dev_db": "egg-sequelize-auto -o ./app/model -h 127.0.0.1 -p 3306 -d dev_db -u root -x 111111 -e mysql",
    "test_db": "egg-sequelize-auto -o ./app/model -h 127.0.0.1 -p 3306 -d dev_db -u root -x 111111 -e mysql",
    "pord_db": "egg-sequelize-auto -o ./app/model -h 127.0.0.1 -p 3306 -d dev_db -u root -x 111111 -e mysql",
  },

在package.json的scripts里創(chuàng)建3條命令,分別對應(yīng)剛剛初始化的3個環(huán)境的數(shù)據(jù)庫。
生產(chǎn)環(huán)境 : dev_db
測試環(huán)境 : test_db
生產(chǎn)環(huán)境 : pord_db
接著我們使用可視化數(shù)據(jù)庫創(chuàng)個user表(萬金油表)這樣比較直觀


user表

然后我們跑一下
npm run dev_db
如果在app目錄下出現(xiàn)model文件夾下有個user.js那就是模型創(chuàng)建成功啦!

10.寫一個新增用戶的控制器來對swagger和sequelize熟悉一下

10.1 --- 在controller目錄下新建user.js 寫一個新增user的方法

// vscode可以設(shè)置api快速代碼片段 @@直接提示
{
    "swaggerApi": {
        "scope": "javascript,typescript",
        "prefix": "@@",
        "body": [
            "/**",
            "* @summary 接口詳情",
            "* @router get|post /api/v1/$1",
            "* @Request body|query 請求體",
            "* @response 200 baseResponse",
            "*/",
            "async 方法名() {",
            "   const { ctx, service } = this;",
            "   ctx.validate(ctx.rule.請求體, ctx.request.body|ctx.query);",
            "   ctx.body = await service.模塊.方法名()",
            "}"
        ],
        "description": "swaggerApi快速創(chuàng)建"
    }
}
// app/controller/user.js
'use strict';

const Controller = require('egg').Controller;

/**
 * @Controller 用戶模塊
 */
class UserController extends Controller {

    /**
    * @summary 創(chuàng)建用戶
    * @router post /api/v1/create-user
    * @Request body createUserReq
    * @response 200 baseResponse
    */
    async create() {
        const { ctx, service } = this;
        // 參數(shù)驗(yàn)證
        ctx.validate(ctx.rule.createUserReq, ctx.request.body);
        ctx.body = await service.user.createUser()
    }
}

module.exports = UserController;

然后在app/contract/request目錄下新建一個user.js
用作swagger獲取參數(shù)后的對參數(shù)的驗(yàn)證
根據(jù)app/model/user.js的模型創(chuàng)建驗(yàn)證參數(shù)模型

// app/contract/request/user.js
'use strict';

module.exports = {
    // 創(chuàng)建用戶參數(shù)
    createUserReq: {
        phone: {
            type: 'string',
            example: '13723456789',
            format: /^1[34578]\d{9}$/,
            description: '電話',
            required: true
        },
        password: {
            type: 'string',
            example: '密碼',
            maxLength:'36',
            required: true
        },
        name: {
            type: 'string',
            example: '姓名',
            maxLength:'10',
            required: true
        },
        sex: {
            type: 'string',
            enum: ['M', 'F'],
            description: '性別 M:男 F:女'
        },
        balance: {
            type: 'number',
            example: 666.66,
            description: '金額'
        }
    }
};

安裝egg-validate

cnpm i egg-validate --save
雞蛋驗(yàn)證文檔

// app/config/plugin.js
// 驗(yàn)證方案
exports.validate = {
  enable: true,
  package: 'egg-validate',
};

安裝 moment.js(處理時間的工具)+ uuid (自動生成id)

cnpm i moment uuid --save
momentjs中文網(wǎng)
在app目錄下新建擴(kuò)展文件夾extend 取名為helper.js
通過 ctx.helper 訪問到 helper 對象

// app/extend/helper.js
const moment = require('moment');
moment.locale('zh-cn')
exports.Date = v => moment()
exports.zhDate = v => moment().format('lll')

編寫user服務(wù)

// app/service/user.js
'use strict';

const Service = require('egg').Service;
const UUID = require('uuid');

class UserService extends Service {

  /**
   * @創(chuàng)建用戶
   */
  async createUser() {
    const { ctx } = this
    try {

      const id = UUID.v1()
      const class_id = null
      return await ctx.model.User.create({ id, class_id, ...ctx.request.body });

    } catch (error) {

      // 記錄錯誤日志
      this.logger.error(`${ctx.helper.zhDate()} : user服務(wù)創(chuàng)建時發(fā)生錯誤 --- ${error}`)
      const errorBody = {
        code: 5000,
        data: null,
        message: '參數(shù)有毒:' + error
      }
      return errorBody
    }
  }
}

module.exports = UserService;

此時創(chuàng)建用戶的服務(wù)就寫好了
可以使用swagger里的try it out測試接口


測試

如果出現(xiàn)錯誤日志也會自動打印
在logs文件夾下可以找到錯誤的日志

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容