Node 使用 Egg 框架 之 上TS 的教程(一)

Node + Egg + TS + Mongodb + Resetful

  1. 做爲一個從優美的、面向對象的、專業的:C、C++、C#、JAVA一路過來的程序員,開始讓我寫JS,我是拒絕的。這哪裏是在寫代碼,明明是在寫 console.log() 啊!!! 連少個參數、參數類型不對都不告訴我,我太難了。前端

  2. 我那祖傳的:面向對象23種設計模式,在這JS的代碼中失去了靈魂。node

  3. 順便說句: asyncawait 真香。git

  4. 網上的教程都是egg少部分的結合,沒有真正的作到俺們這篇的強。廢話很少說,開始!程序員

老規矩,本地教程的地址爲:github.com/liangwei010…github

運行環境: Node ,Yarn/NPM,MongoDB

egg爲node.js的一個框架,用起來仍是挺簡單的,大夥看看就會了。redis

Node + egg + ts + Mongodb 示例

數據庫保存
接口返回字段

目錄結構

項目結構

egg-demo
├── app
│   ├── controller (前端的請求會到這裏來!)
│   │   └── home.ts
│   ├── model(數據庫表結構抽象出來的模型)
│   │   └── User.ts
│   ├── service(controller 層不建議承載過多的業務,業務重時放在service層)
│   │   └── user.ts
│   └── router.ts (Url的相關映射)
├── config (框架的配置文件)
│   ├── config.default.ts
│   ├── config.local.ts
│   ├── config.prod.ts
│   └── plugin.ts
├── test (測試文件夾)
│   └── **/*.test.ts
├── typings (目錄用於放置 d.ts 文件)
│   └── **/*.d.ts
├── README.md
├── package.json
├── tsconfig.json
└── tslint.json
複製代碼

配置

demo配置了兩處地方:mongodb

  • 數據庫
config.mongoose = {
    url: process.env.EGG_MONGODB_URL || 'mongodb://127.0.0.1/egg-demo',
    options: {},
  };
複製代碼
  • csrf(先關閉,要否則post報錯)
config.security = {
    csrf: {
      enable: false,
    },
  };
複製代碼

router

對於resetful風格的接口來講,用http的關鍵字來標識動做,用名詞來標識資源。已user爲例子: 對於請求 '/user'的請求,在下方代碼的指定映射到對應的函數中。數據庫

router.get('/user', controller.home.getUser);
  router.post('/user', controller.home.addUser);
  router.put('/user', controller.home.updateUser);
  router.delete('/user', controller.home.deleteUser);
複製代碼

controller

這裏是請求對應的函數的類。json

// 這裏是get('/user')的處理函數
  public async getUser() {
    const { ctx } = this;
    
    // 這裏就是隨你怎麼來。能夠數據庫查,或者別的。
    const user = { ... };
    // 返回的值
    ctx.body = user;
  }

  // 下面相似,再也不解釋了啊
  public async addUser() {
    const { ctx } = this;

    // 模擬前端傳遞過來的數據(方便測試)
    const user = new UserModel();
    user.userName = 'add user';
    user.userNo = 99;

    const res = await ctx.model.User.create(user);
    ctx.body = res;
  }

  public async deleteUser() {
    const { ctx } = this;

    const user = new UserModel();
    user.userNo = 99;

    const res = await UserModel.findOneAndRemove({ userNo: user.userNo });

    ctx.body = res;
  }
複製代碼

service層

這裏沒有啥講的,就是一些業務性的東西放這裏,讓被controller或者其餘service調用。設計模式

/**
  * sayHi to you
  * @param name - your name
  */
  public async sayHi(name: string) {
    return `hi, ${name}`;
  }
複製代碼

Model (畫重點,用mongodb的注意啦)

  1. 首先咱們建立一個Schema
/**
  * 定義一個User的Schema
*/
const UserSchema: Schema = new Schema({
  userNo: {
    type: Number,
    index: true,
  },

  userName: String,
},
  {
    timestamps: true,
  },
);
複製代碼
  1. 索引
// userNo 爲索引
UserSchema.index({ userNo: 1, });
複製代碼
  1. 實例方法和靜態方法
// UserSchema的實例方法
UserSchema.methods.userInstanceTestMethods = function () {

  const user: IUser = new UserModel();
  user.userName = '我是實例化方法測試';
  user.userNo = 9527;

  return user;
};

// UserSchema的實例方法
UserSchema.statics.userStaticTestMethods = function () {

  const user: IUser = new UserModel();
  user.userName = '我是靜態方法測試';
  user.userNo = 9528;

  return user;
};
複製代碼
  1. 建立User接口字段
/**
  * 用戶字段接口
*/
export interface IUser {

  userNo: number;

  userName: string;
}
複製代碼
  1. 實例方法和靜態方法接口的定義,注意:這裏的接口要和Schema中定義的函數的名稱和返回值一致。
export interface IUserDocument extends IUser, Document {
  /**
  * 實例方法接口(名稱須要和Schema的方法名同樣)
  */
 userInstanceTestMethods: () => IUser;
}
/**
  * 靜態方法接口
*/
export interface IUserModel extends Model<IUserDocument> {

  /**
   * 靜態方法
   */
  userStaticTestMethods: () => IUser;
}
複製代碼
  1. 導出model便可。
export const UserModel = model<IUserDocument, IUserModel>('User', UserSchema);
複製代碼
  1. 爲了怕有需求使用到ctx.model.User,咱們須要將UserSchema掛載到ctx中
// egg-mongoose注入
export default (app: Application) => {

  const mongoose = app.mongoose;
  // 這裏爲了掛載到ctx中,讓正常ctx.model.User也能使用
  mongoose.model<IUserDocument, IUserModel>('User', UserSchema);
};
複製代碼

使用Model

使用mode能使用IUser字段接口,實例方法,靜態方法。

// 這裏的user是: IUser的類型。而後就能盡情的點點點啦!
  const user = await UserModel.findOne();
  // 等價於
  const users = await this.ctx.model.User.find();
  // 實例方法
  const newUser = new UserModel();
  newUser.userInstanceTestMethods();
  // 靜態方法
  UserModel.userStaticTestMethods();
複製代碼

最後,單元測試!!!

可能不少人以爲單元測試不寫就不寫,寫了浪費時間。可是等你發現你要重構的時候,沒有足夠的單元測試的時候,你會以爲,什麼鬼,不敢動啊!!!因此,我以爲仍是要寫單元測試,這個東西是費點時間,可是後期好啊。

test/app/controller/home.test.ts
    √ should GET / (49ms)
    √ addUser (39ms)
    √ getUser
    √ getUsers
    √ updateUser
    √ deleteUser
    √ testStaticMethods
    √ testInstanceFunction

  test/app/service/Test.test.js
    √ sayHi
    √ testUserInstanceServiceMethods
    √ testUserInstanceServiceMethods

  11 passing (4s)
複製代碼

看見他打綠色的 √ √ 我就很開心。

今天有點晚了,後面給你們寫:定時任務,GraphQL,redis,部署等內容。

相關文章
相關標籤/搜索