EggJS接口開發


需求

隨着Nodejs的普及,前端開發的開發場景基本可以貫穿界面交互到數據存儲,無縫實現全棧開發。最近在實現一個內部項目管理工具的時候,就嘗試了一把接口和數據庫開發。

什么是Egg.js

Egg.js是阿里開源的一套Nodejs開發框架。Egg.js官網的介紹是:

Egg.js 為企業級框架和應用而生,我們希望由 Egg.js 孕育出更多上層框架,幫助開發團隊和開發人員降低開發和維護成本。

為什么選擇了Egg.js,而不是Koa,Express呢,其實還是為了快速開發,減少搭建項目的時間,Egg.js已經為開發者設計了幾乎最常用的目錄結構,一切傾向於配置化,隱藏一些業務無關的技術細節。開發者可以更加着重考慮業務邏輯,然后在Egg.js和相關插件的支持下,開發功能即可。

Egg.js還提倡『約定優於配置』,這一點我也是很贊同,一致的約定能夠減少不必要的失誤,同時保證了一致的開發體驗,可以方便的維護不同的項目。

初始化項目

Egg.js提供了腳手架快速初始化項目,但是要求npm >=6.1.0,這基本不是問題。

$ mkdir egg-example && cd egg-example
$ npm init egg --type=simple
$ npm i 

然后啟動項目

$ npm run dev
$ open http://localhost:7001

  

目錄設計

因為Egg.js已經做了太多事情,我只需要關注app和config。

├── app
|   ├── router.js
│   ├── controller
│   |   └── home.js
│   ├── service
│   |   └── user.js     
│   ├── model
│   |   └── user.js     
├── config
|   ├── plugin.js 
|   └── config.default.js

  

app/router.js 用於配置URL路由規則,也就是你訪問的接口地址,對應的是哪個controller的邏輯。

app/controller/** 用於解析用戶的輸入,處理后返回相應的結果,這里其實可以寫service和model的邏輯,但是按照單一職責的原則,我們會在controller主要放置參數解析和返回值,以及非數據庫操作的邏輯。

app/service/** 用於編寫業務邏輯層,可選,建議使用,你可以理解成對數據庫操作的封裝。

app/model/** 用於定義mongodb的schema,這部分很神奇的是Egg.js已經封裝mongodb鏈接數據庫,並將model綁定到了ctx上,方便調用。

config/config.default.js 用於編寫配置文件,可以配置不同的開發環境,不同的變量,但是因為業務比較單一,內部使用,所以只使用了默認設置。我的項目中配置了跨域、mongoose、csrf,等等。

config.mongoose = {
    url: "mongodb://127.0.0.1/*****",
    options: {}
};

config.cors = {
    origin: '*',  
    allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH'
}

config.security = {
    csrf: {
        enable: false,
    },
};

  

config/plugin.js 用於配置需要加載的插件,比如egg-mongoose,egg-cors。

module.exports = { 
    mongoose: {
        enable: true,
        package: "egg-mongoose"
    },
    cors: {
        enable: true,
        package: "egg-cors"
    }
};

  

這里需要注意的是,很多博客提供的代碼都是ES6的代碼,在我初始化的模板中是不可行的,如下:

exports.cors = {
  enable: true,
  package: 'egg-cors',
}

  

開發項目

基礎搭建好了,開發就變得很簡單了,我遵循的邏輯是:Model-->路由-->Contoller-->Service,先設計數據庫Schema,然后增加新的路由,支持對應的Controller,然后在Service中完成數據庫操作。

router.js

router.get("/api/task", controller.task.index);
router.post("/api/task", controller.task.create);
router.put("/api/task/:id", controller.task.update);
router.delete("/api/task/:id", controller.task.destroy );

// 也可以簡寫為 
router.resources('topics', '/api/task', controller.task);

 

controller中實現的方法具體可以參考下面的對應關系

 

Method Path Route Name Controller.Action
GET /posts posts app.controllers.posts.index
GET /posts/new new_post app.controllers.posts.new
GET /posts/:id post app.controllers.posts.show
GET /posts/:id/edit edit_post app.controllers.posts.edit
POST /posts posts app.controllers.posts.create
PUT /posts/:id post app.controllers.posts.update
DELETE /posts/:id post app.controllers.posts.destroy

 

controller/task.js
exports.index = function*() {
    // ...
    const result = yield this.service.task.index(this.params); 
    this.body = result;
};

exports.create = function*() { 
    // ...
    const result = yield this.service.task.create(this.request.body);
    this.body = result;
};

exports.update = function*() { 
    // ...
    const result = yield this.service.task.update(this.params.id, this.request.body); 
    this.body = result; 
};

exports.destroy = function*() {
    // ...
    const result = yield this.service.task.destroy(this.params); 
    this.body = result; 
};

  

service/task.js

module.exports = app => {
    class TaskService extends app.Service {
        *index(params) {
            let tasks = yield this.ctx.model.Task.find(params);
            let result = {};
            result.data = tasks;
            return result;
        }

        *create(request) {  
        }

        *update(id, request) { 
        }

        *destroy(params) { 
        }
    }
    return TaskService;
};

model/task.js

module.exports = app => {
    const mongoose = app.mongoose;
    const Schema = mongoose.Schema;
    const TaskSchema = new Schema({
        id: {type: Number},
        text: {type: String},
        type: {type: String},
        progress: {type: Number},
        open: {type: Boolean},
        start_date: {type: String},
        owner_id: [{type: String}],
        duration: {type: Number},
        parent: {type: Number}
    });
    return mongoose.model("Task", TaskSchema);
};

 

部署

Egg.js 框架內置了 egg-cluster 來啟動 Master 進程,Master 有足夠的穩定性,不再需要使用 pm2 等進程守護模塊。只需要兩個命令即可:

# 啟動服務
npm start
# 關閉服務
npm run stop

 

結語

站在巨人的肩膀上,讓我們的開發效率倍增,但是還是建議大家先從Koa2學起,對然后對比Egg.js,你就會了解它到底封裝了哪些東西,為我們節省了多少工作量,后面還要繼續對Egg.js的插件開發進行了解。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM