前面也用egg写过一些api服务,但都不是ts版的,在默认提示上感觉很不爽,正好这次egg.js已经有了ts的版本,那么我们直接来用ts版的egg来构建我们的api服务。
创建项目
我们按照egg.js文档的步骤来用脚手架创建项目。
首先安装egg-init
,这个是创建项目的工具:
1 | npm i egg-init -g |
当然,如果我们已经存在了项目的文件夹的话,就用渐进式安装就可以了。
这里我们直接用egg-init
来创建:
1 | T:myobj tonyyang$ egg-init my-api |
可以看到,在命令行里面会出现一个选项让我们选择创建的项目的类型,这里我们选择用ts,选择第二个就好了。然后一路回车,这样我们项目就创建好了。
egg-init
只是帮我们创建了项目的骨架以及一些通用配置,我们需要npm i
一下,然后就可以运行起来:
1 | npm run dev |
跑起来后,我们可以访问http://localhost:7001
,可以看到接口的返回:hi, egg
。目前为止,项目创建完毕,也正常运行。
项目目录
我们来看看创建好的项目目录:
- app 应用文件夹
- controller 处理用户请求
- public 放置静态资源文件(可选)
- service 编写业务逻辑(可选)
- model 数据库领域模型(可选)
- middleware 编写中间件(可选
- router.ts 定义路由的文件,可以扩展为路由文件夹,但是要在这个js中引入
- config 配置文件
- config.{env}.ts 不同环境的不同配置文件
- plugin.ts 管理插件
- logs 日志
- run 运行时文件
- test 单元测试文件
- typing ts类型支持
- tslint.json 代码验证规则
通过脚手架创建的时候app
里面是不带model
文件夹的,因为我们需要使用Sequelize
这个ORM框架,所以我们在app
下面手动创建model
文件夹。
在项目中安装Sequelize
Sequelize
是一个ORM框架,我们用它来管理数据层的代码。
需要在机器上安装mysql并让它正常运行,我们需要配置参数,比如数据库的密码和ip等。
- 安装插件
egg-sequelize
和mysql2
1
npm i --save egg-sequelize mysql2
- 在
config/plugin.js
中引入egg-sequelize
插件1
2
3
4
5
6const plugin: EggPlugin = {
sequelize: {
enable: true,
package: 'egg-sequelize',
},
}; - 在
config/config.default.ts
中配置sequelize
注意,确保数据库的配置是正确的并可以访问到数据库,要不然egg会崩掉。如果不知道是什么问题崩掉的,那么重启egg就可以看到报错信息。1
2
3
4
5
6
7
8config.sequelize = {
dialect: 'mysql',
host: 'ip...',
port: 3306,
password: 'password',
database: 'database',
timezone: '+08:00',
};使用model来操作数据库
Sequelize
都配置好了,我们需要建立数据模型来让项目有操作数据库的能力。定义model
首先我们在数据库中创建好表:hero
,然后我们建立hero
的模型:观察1
2
3
4
5
6
7
8
9
10
11
12// app/model/hero.ts
import {Application} from 'egg';
export default (app: Application) => {
const {STRING, INTEGER, DATE} = app.Sequelize;
const model = app.model.define('heroes', {
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
name: STRING(40),
created_at: DATE,
updated_at: DATE,
});
return model;
};typings/app
文件夹可以看到,当我们创建model的时候,会自动生成对应的index.d.ts
文件,这是为了方便支持ts的提示,不要修改这个ts文件。使用model
定义了类型HeroInterface
:定义了请求返回的数据格式1
2
3
4
5
6export interface HeroInterface {
id: number;
name: string;
created_at: string;
updated_at: string;
}Code
:然后在service里面调用model:1
2
3
4
5
6
7
8
9export const Code = {
ERROR: {
code: 1,
msg: 'failed',
},
SUCCESS: {
code: 0,
msg: 'success',
},然后在controller中使用service:1
2
3
4
5
6
7
8
9
10
11
12
13// app/service/hero.ts
import {Service} from 'egg';
import {HeroInterface} from '../interface/hero.interface';
import {Code} from '../util/util';
export default class Hero extends Service {
public async list() {
const {ctx} = this;
const result: any = await ctx.model.Hero.all({});
return Object.assign({}, Code.SUCCESS, {
data: result,
});
}
}最后在路由中添加访问路径:1
2
3
4
5
6
7
8// app/controller/hero.ts
import {Controller} from 'egg';
export default class Hero extends Controller {
public async list() {
const {ctx} = this;
ctx.body = await ctx.service.hero.list();
}
}在浏览器中进行访问(或者调用api)就可以看到我们从数据库中取到的数据:1
2
3
4
5
6// app/router.ts
import { Application } from 'egg';
export default (app: Application) => {
const { controller, router } = app;
router.get('/hero/list', controller.hero.list);
}1
2
3
4
5
6
7
8
9
10
11
12{
"code": 0,
"msg": "success",
"data": [
{
"id": 13,
"name": "Iron Man",
"created_at": "2018-09-28T05:35:46.000Z",
"updated_at": "2018-09-28T05:35:46.000Z"
}
]
}跨域支持
我们创建的项目是用来当api的,那么实际情况下是通过跨域调用的,也就是说,客户端和api是不同的域,这种情况也需要支持,目前来讲,是无法调用成功的,我们需要添加跨域支持。
跨域我们需要用到插件egg-cors
,先在我们的项目中安装:
1 | npm i egg-cors --save |
在plugin.ts
中启用跨域:
1 | import {EggPlugin} from 'egg'; |
然后在app/config/config.default.ts
中添加白名单访问列表:
1 | config.security = { |
同时,需要将config.cors
中的origin
不可设置为*
:
1 | config.cors = { |
最后
ok,大功告成,基本的项目框架完成;数据库访问功能完成;跨域访问完成;然后就可以添加自己的业务了,have fun~ 😊