Node + Egg + TS + Mongodb + Resetful
-
Как программист, прошедший путь от элегантных, объектно-ориентированных, профессиональных: C, C++, C#, JAVA, когда я начал писать JS, я отказался. Где этот пишущий код, явно пишущийconsole.log()Какие! ! !Мне слишком сложно не сказать мне даже несколько параметров и неправильный тип параметров.
-
Мои предки:объектно-ориентированныйа также23 шаблона проектирования, потерял душу в этом коде JS.
-
Кстати:asyncа такжеawaitДействительно ароматный.
-
Онлайн-уроки представляют собой комбинацию небольшой части яйца, и на самом деле они не имеют силы нашей статьи. Без лишних слов, давайте начнем!
Как обычно, адрес местного туториала:GitHub.com/Два 010…
Операционная среда: Node, Yarn/NPM, MongoDB
egg — это фреймворк node.js, он довольно прост в использовании, его увидит каждый.
Узел + яйцо + 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
настроить
Демо настраивается в двух местах:
- база данных
config.mongoose = {
url: process.env.EGG_MONGODB_URL || 'mongodb://127.0.0.1/egg-demo',
options: {},
};
- csrf (сначала закрыть, иначе сообщение сообщит об ошибке)
config.security = {
csrf: {
enable: false,
},
};
router
Для интерфейсов в стиле сброса используйте ключевые слова http для обозначения действий и существительные для обозначения ресурсов. Например, пользователь: Для запросов «/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
Вот класс, который запрашивает соответствующую функцию.
// 这里是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;
}
сервисный уровень
Здесь не о чем говорить, просто положите сюда какие-нибудь деловые штучки и пусть их вызывает контроллер или другие службы.
/**
* sayHi to you
* @param name - your name
*/
public async sayHi(name: string) {
return `hi, ${name}`;
}
Модель (нарисуйте ключевой момент, используйте внимание mongodb)
- Сначала мы создаем схему
/**
* 定义一个User的Schema
*/
const UserSchema: Schema = new Schema({
userNo: {
type: Number,
index: true,
},
userName: String,
},
{
timestamps: true,
},
);
- показатель
// userNo 为索引
UserSchema.index({ userNo: 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;
};
- Создать поле пользовательского интерфейса
/**
* 用户字段接口
*/
export interface IUser {
userNo: number;
userName: string;
}
- Определение метода экземпляра и интерфейса статического метода, примечание: здесь интерфейс должен соответствовать имени и возвращаемому значению функции, определенной в схеме.
export interface IUserDocument extends IUser, Document {
/**
* 实例方法接口(名称需要和Schema的方法名一样)
*/
userInstanceTestMethods: () => IUser;
}
/**
* 静态方法接口
*/
export interface IUserModel extends Model<IUserDocument> {
/**
* 静态方法
*/
userStaticTestMethods: () => IUser;
}
- Просто экспортируйте модель.
export const UserModel = model<IUserDocument, IUserModel>('User', UserSchema);
- Для того, чтобы бояться использовать 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);
};
Использовать модель
Используя режим, можно использовать интерфейс поля 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, деплоймент и т.д.