Skip to content

Commit 65ff08e

Browse files
committed
refactor: upgrade with routing-controller
1 parent ed8a3aa commit 65ff08e

31 files changed

+4646
-3540
lines changed

app.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
import { createServer } from './config/application'
2-
import { Environment } from './config/environments/index'
2+
import { Environment } from './config/environments'
33
import { Server } from 'http'
44

5-
module.exports = (async() => {
5+
module.exports = (async(): Promise<Server> => {
66
try {
77
const app = await createServer()
8-
const server: Server = app.listen(Environment.port, () => {
9-
console.log(`Server listening on ${Environment.port}, in ${Environment.identity} mode.`)
8+
return app.listen(Environment.port, () => {
9+
console.log(`server listening on ${Environment.port}, in ${Environment.identity} mode.`)
1010
})
11-
return server
1211
} catch (e) {
1312
console.log(e)
14-
process.exit(1)
1513
}
1614
})()

app/controllers/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
export * from './session.controller'
1+
export { SessionsController } from './sessions.controller'
22

app/controllers/session.controller.ts

Lines changed: 0 additions & 25 deletions
This file was deleted.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { Sessions } from '../entities'
2+
import { SessionsService } from '../services'
3+
import { Interceptors } from '../helpers'
4+
import { Body, Get, JsonController, Post, QueryParam, UseInterceptor } from 'routing-controllers'
5+
6+
7+
@JsonController()
8+
export class SessionsController {
9+
10+
constructor(
11+
private sessionsService: SessionsService,
12+
) {
13+
}
14+
15+
16+
@Get('/sessions')
17+
@UseInterceptor(Interceptors.MessageInterceptor)
18+
async session(@QueryParam('username') username: string): Promise<any> {
19+
return 'hello'
20+
}
21+
22+
@Post('/sessions')
23+
async create(@Body() session: Sessions): Promise<any> {
24+
const created = await this.sessionsService.create(session)
25+
return { message: 'ok', created }
26+
}
27+
}

app/entities/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './sessions.entity'
2+

app/entities/sessions.entity.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { MinLength, IsNotEmpty } from 'class-validator'
2+
import {
3+
Entity, BaseEntity, ObjectIdColumn, CreateDateColumn, UpdateDateColumn,
4+
} from 'typeorm'
5+
6+
/**
7+
* All validator can be applied to all controllers.
8+
* Reference document: https://github.com/typestack/class-validator
9+
* How to auto validaing? see: https://github.com/typestack/routing-controllers#auto-validating-action-params
10+
*/
11+
12+
@Entity()
13+
export class Sessions extends BaseEntity {
14+
15+
@ObjectIdColumn()
16+
id: string
17+
18+
@MinLength(4, { message: 'username too short' })
19+
@IsNotEmpty({ message: 'must include username' })
20+
username: string
21+
22+
@MinLength(10)
23+
token: string
24+
25+
@CreateDateColumn()
26+
created_at: Date
27+
28+
@UpdateDateColumn()
29+
updated_at: Date
30+
}

app/helpers/.gitkeep

Whitespace-only changes.

app/helpers/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import * as Interceptors from './interceptors'
2+
3+
export {
4+
Interceptors,
5+
}

app/helpers/interceptors/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { MessageInterceptor } from './message'

app/helpers/interceptors/message.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { Action, InterceptorInterface } from 'routing-controllers'
2+
3+
4+
export class MessageInterceptor implements InterceptorInterface {
5+
intercept(action: Action, content: any): any {
6+
if (typeof content === 'object') return content
7+
return { message: content }
8+
}
9+
}
10+

app/models/index.ts

Lines changed: 0 additions & 2 deletions
This file was deleted.

app/models/session.model.ts

Lines changed: 0 additions & 14 deletions
This file was deleted.

app/services/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export * from './session.service'
1+
export * from './sessions.service'

app/services/session.service.ts

Lines changed: 0 additions & 9 deletions
This file was deleted.

app/services/sessions.service.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { EntityManager, getMongoRepository, MongoRepository } from 'typeorm'
2+
import { Service } from 'typedi'
3+
import { Sessions } from '../entities'
4+
5+
@Service()
6+
export class SessionsService {
7+
repository: MongoRepository<Sessions>
8+
9+
constructor() {
10+
this.repository = getMongoRepository(Sessions)
11+
}
12+
13+
async create(session: Sessions): Promise<Sessions> {
14+
return await this.repository.save(session)
15+
}
16+
17+
}

compose.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
version: "2"
2+
services:
3+
koa_ex.mongo:
4+
image: tutum/mongodb:3.0
5+
ports:
6+
- "27017:27017"
7+
- "28017:28017"
8+
restart: always
9+
volumes:
10+
- koa_ex_db:/data/db
11+
env_file:
12+
- ./variables.env
13+
volumes:
14+
koa_ex_db:

config/application.ts

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
1+
import 'reflect-metadata'
12
import * as Koa from 'koa'
2-
import * as kcors from 'kcors'
3-
import * as bodyParser from 'koa-bodyparser'
4-
import * as logger from 'koa-logger'
5-
import { KoaCustomResponse } from 'koa-custom-response'
6-
import { router } from './routers'
7-
import { Environment } from './environments'
8-
// import './connection'
3+
import * as controllers from '../app/controllers'
4+
import * as interceptors from './interceptors'
5+
import { Container } from 'typedi'
6+
import { useKoaServer, useContainer } from 'routing-controllers'
7+
import { useMiddlewares } from './middlewares'
8+
import './connection'
99

10-
export const createServer = async(): Promise<any> => {
11-
const app = new Koa()
12-
13-
app.use(kcors())
14-
15-
Environment.identity !== 'test' && app.use(logger())
16-
17-
app.use(bodyParser())
10+
const objectToArray = (dict: object): Array<any> =>
11+
Object.keys(dict).map(name => dict[name])
12+
13+
export const createServer = async(): Promise<Koa> => {
14+
const koa: Koa = new Koa()
1815

19-
app.use(KoaCustomResponse())
16+
const app: Koa = useKoaServer<Koa>(koa, {
17+
routePrefix: '/apis',
18+
validation: true,
19+
interceptors: objectToArray(interceptors),
20+
controllers: objectToArray(controllers),
21+
})
2022

21-
app.use(router.routes()).use(router.allowedMethods())
23+
useContainer(Container)
2224

23-
return app
25+
return useMiddlewares(app)
2426
}

config/connection.ts

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
1-
import * as mongoose from 'mongoose'
1+
import * as entities from '../app/entities'
22
import { Environment } from './environments'
3+
import { createConnection } from 'typeorm'
4+
const mongo = Environment.mongo
35

4-
;(<any>mongoose).Promise = global.Promise
5-
const { user, password, host, port, database } = Environment.mongo
6-
const path = `mongodb://${user}:${password}@${host}:${port}/${database}`
76

8-
mongoose.connection
9-
.once('error', err => console.log(`mongodb connect error:\n${err}`))
10-
.once('open', () => {
11-
Environment.identity !== 'test' && console.log('mongodb connect success')
7+
createConnection({
8+
type: 'mongodb',
9+
host: mongo.MONGODB_HOST,
10+
port: mongo.MONGODB_PORT,
11+
username: mongo.MONGODB_USER,
12+
database: mongo.MONGODB_DATABASE,
13+
password: mongo.MONGODB_PASS,
14+
useNewUrlParser: true,
15+
entities: Object.keys(entities).map(name => entities[name]),
1216
})
13-
14-
mongoose.connect(path)
15-
.then().catch(e => console.log(e))
16-
17-
export {
18-
mongoose,
19-
}
17+
.then(() => console.log('mongodb connect success'))
18+
.catch(error => console.log(error))

config/environments/development.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
export default {
2-
32
identity: 'development',
43

54
port: 3000,
65

76
mongo: {
8-
adapter: 'test',
9-
host: '127.0.0.1',
10-
port: 27017,
11-
user: 'admin',
12-
password: 'test',
13-
database: 'test',
7+
MONGODB_HOST: '127.0.0.1',
8+
MONGODB_PORT: 27017,
9+
MONGODB_USER: '',
10+
MONGODB_PASS: '',
11+
MONGODB_DATABASE: '',
1412
},
1513

1614
}

config/environments/index.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
1-
21
import development from './development'
32
import production from './production'
43
import test from './test'
4+
const envFile = require('node-env-file')
5+
const path = require('path')
56

67
const isProd = process.env.NODE_ENV === 'production'
78
const isTest = process.env.NODE_ENV === 'test'
89

9-
if (isProd && (!production.mongo.user || !production.mongo.password)) {
10-
console.error('mongo.production need set MONGODB_USER && MONGODB_PASS')
11-
process.exit(1)
12-
}
1310

11+
// use variables.env file first.
1412
const env = isTest ? test : (isProd ? production : development)
13+
const secrets = envFile(path.join(__dirname, '../../variables.env'))
14+
Object.keys(secrets).forEach(name => {
15+
if (!secrets[name]) return
16+
env.mongo[name] = secrets[name]
17+
})
1518

16-
if (process.env.IN_DOCKER) {
17-
env.mongo.host = 'pro.mongo'
18-
}
1919

20+
// must be included mongodb configs in prod mode
21+
if (isProd && (!env.mongo.MONGODB_USER || !env.mongo.MONGODB_PASS)) {
22+
console.error('mongo.production need set MONGODB_USER && MONGODB_PASS')
23+
process.exit(1)
24+
}
2025

2126
export const Environment = env

config/environments/production.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
export default {
2-
32
identity: 'production',
43

54
port: 3000,
65

76
mongo: {
8-
adapter: 'pro',
9-
host: '127.0.0.1',
10-
port: 27017,
11-
user: process.env.MONGODB_USER,
12-
password: process.env.MONGODB_PASS,
13-
database: process.env.MONGODB_DATABASE,
7+
MONGODB_HOST: '127.0.0.1',
8+
MONGODB_PORT: 27017,
9+
MONGODB_USER: '',
10+
MONGODB_PASS: '',
11+
MONGODB_DATABASE: '',
1412
},
15-
1613
}

config/environments/test.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
export default {
2-
32
identity: 'test',
43

54
port: 3000,
65

76
mongo: {
8-
adapter: 'test',
9-
host: '127.0.0.1',
10-
port: 27017,
11-
user: 'test',
12-
password: 'test',
13-
database: 'test',
7+
MONGODB_HOST: '127.0.0.1',
8+
MONGODB_PORT: 27017,
9+
MONGODB_USER: '',
10+
MONGODB_PASS: '',
11+
MONGODB_DATABASE: '',
1412
},
1513

1614
}

config/interceptors.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { InterceptorInterface, Action, Interceptor } from 'routing-controllers'
2+
3+
@Interceptor()
4+
export class AutoAssignJSONInterceptor implements InterceptorInterface {
5+
intercept(action: Action, content: any): any {
6+
if (typeof content === 'object') return JSON.stringify(content)
7+
return JSON.stringify({ message: content })
8+
}
9+
}

0 commit comments

Comments
 (0)