EggJS接口開發

需求

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

什麼是Egg.js

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

Egg.js 爲企業級框架和應用而生,咱們但願由 Egg.js 孕育出更多上層框架,幫助開發團隊和開發人員下降開發和維護成本。java

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

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

初始化項目

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

$ mkdir egg-example && cd egg-example
$ npm init egg --type=simple
$ npm i
複製代碼

而後啓動項目api

$ 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的邏輯。bash

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

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的插件開發進行了解。

相關文章
相關標籤/搜索