nestjs 를 사용해보면서 엔터프라이즈에는 적합하다고 생각하지만, 기본 패키지가 무겁다는 것은 부정할 수 없었습니다.
그에 비하면 express, koa, fasfity 는 경량의 프레임워크 입니다. 10줄 안팎으로 서버를 구축할 수 있습니다.
express 는 가장 큰 커뮤니티가 있다는 장점이있지만, koa 와 fasfity 와는 비교적 오래되었기 때문에 후자가 사용경험이 꽤나 괜찮았습니다.
한번쯤 공식문서를 정독해보고 싶어서, 학습하면서 글을 남겨봅니다.
Koa 란
koa 는 express 와 동일하게 요청에 대해서 미들웨어를 배열과 같이 순차적으로 적용시켜 처리합니다.
express 는 기본적인 미들웨어를 번들로 가지고있지만, koa 는 어떤 미들웨어도 번들로 제공하지 않기 때문에 훨씬 더 경량입니다.
express 의 경우에는 미들웨어를 콜백으로 구현하였지만, koa 는 비동기를 사용해 미들웨어를 구현하면서,
하나의 return 이 이루어지면 제어흐름이 끝나는 것 과 달리 downstream 의 호출이 끝나면 upstream 으로 다시 제어할 수 있습니다.
아래 코드는 요청마다 응답 시간을 측정해 응답 헤더에 추가하고, 다른 미들웨어에서는 그것을 받아 로그를 남기는 예시입니다.
import Koa from 'koa';
const app = new Koa();
// logger
app.use(async (ctx,next)=>{
await next();
const time = ctx.response.get('RESPONSE-TIME')
console.log(`${ctx.request.method} ${ctx.url} - ${time}`)
})
// response time
app.use(async (ctx,next)=>{
const start = Date.now();
await next()
ctx.set('RESPONSE-TIME',`${Date.now() - start}ms`)
})
app.use(async (ctx,next)=>{
ctx.body = 'hello world';
})
app.listen(3000);
Settings
Koa App 에 대한 세팅은 app 인스턴스에 내장되어있고, 생성자 혹은 property로 접근, 수정할 수 있습니다.
자주 쓰일 두개만 예시로,
app.env 는 default 값으로 development 이고, NODE_ENV 값이 있다면 반영합니다.
app.keys 는 signed cookie 의 키들의 배열입니다.
console.log(app.env)
console.log(app.keys)
Signed Cookie 예시
https://github.com/pillarjs/cookies
const app = new Koa();
app.keys = ['hi']
app.use(async (ctx,next)=>{
await next()
ctx.cookies.set('nn','1234',{signed:true})
console.log(ctx.cookies.get('nn'))
})
app.context
app.context 프로퍼티는 ctx 의 prototype 입니다.
전체 앱에서 접근할 수 있는 전역 프로퍼티인 샘이고, 안티패턴이라고들 하지만 아래와 같이 사용할 수 있습니다.
app.context.db = 'db'
app.use(async (ctx,next)=>{
console.log(app.context.db)
ctx.body = 'hello world';
})
ctx 의 대부분의 프로퍼티는 getter, setter 로 정의되어 있기 때문에, 수정하려면 app.context 에다가 Object.definedproperty() 를 사용해야합니다.
Error Handling
app.slient = true
err.status == 404
인 경우를 제외하고는 error 이벤트 핸들러에 전달되게 됩니다.
ctx 또한 두번째 인자로 전달 합니다.
app.on('error',(error,ctx)=>{
console.log(error,ctx)
})
node 가 죽지않고 응답할 수 있는 경우 클라이언트에게는 500 응답을 전달하고, node 앱에서는 error 이벤트를 emit 합니다.
ctx
ctx 는 요청마다 생성되기 때문에 미들웨어간에 데이터 전달 용도로 사용될 수 도 있습니다.
예를들면 아래처럼 다른 미들웨어에서 어떤 상태값을 저장하고 다음 미들웨어로 넘기고, 그 미들웨어에서는 그 상태값을 참조할 수 있습니다.
app.use(async(ctx,next)=>{
await next()
console.log(ctx.state)
})
app.use(async (ctx,next)=>{
ctx.state = 'hi'
ctx.body = 'hello world';
})
미들웨어의 순서는 후 순위 일 수록 먼저 실행 됩니다
ctx.app.emit
내장된 EventEmitter 를 사용할 수 있습니다.
app.use(async (ctx,next)=>{
ctx.app.emit('logger','HI')
})
app.on('logger',(d)=>{
console.log(d)
})
의도적 error trhow
일반 Error 객체에 status 프로퍼티만 있다면 koa 에서 제공하는 에러 응답과 같아 집니다.
app.use(async (ctx,next)=>{
// 1
ctx.throw(404, 'not found')
// 2
const err = new Error('BAD')
err.status = 400;
err.expose = {
user:'kong'
};
throw err
})
alias
request
- ctx.header
- ctx.headers
- ctx.method
- ctx.method=
- ctx.url
- ctx.url=
- ctx.originalUrl
- ctx.origin
- ctx.href
- ctx.path
- ctx.path=
- ctx.query
- ctx.query=
- ctx.querystring
- ctx.querystring=
- ctx.host
- ctx.hostname
- ctx.fresh
- ctx.stale
- ctx.socket
- ctx.protocol
- ctx.secure
- ctx.ip
- ctx.ips
- ctx.subdomains
- ctx.is()
- ctx.accepts()
- ctx.acceptsEncodings()
- ctx.acceptsCharsets()
- ctx.acceptsLanguages()
- ctx.get()
response
- ctx.body
- ctx.body=
- ctx.status
- ctx.status=
- ctx.message
- ctx.message=
- ctx.length=
- ctx.length
- ctx.type=
- ctx.type
- ctx.headerSent
- ctx.redirect()
- ctx.attachment()
- ctx.set()
- ctx.append()
- ctx.remove()
- ctx.lastModified=
- ctx.etag=
@koa/router
express 에서 기본적으로 제공해주는 router 조차 제공해주지 않기 때문에, 해당 모듈을 설치해야 라우터를 편하게 구성할 수 있습니다.
body 파싱을 위해 koa-body 모듈도 미들웨어로 추가해줍니다
router/userRouter.js
import Router from "@koa/router";
const userRouter = new Router()
const user = [];
userRouter.get('/',async (ctx,next)=>{
ctx.body = user;
})
userRouter.post('/',async ctx =>{
user.push(ctx.request.body)
ctx.body = 'ok'
})
export default userRouter;
index.js
import Router from "@koa/router";
import {koaBody} from 'koa-body'
app.use(koaBody())
router.use('/users',auth,userRouter.routes())
koa 를 express 개발자분들이 만들었기 때문에 95퍼센트 동일한 느낌을 받았습니다.
다반 비동기 기반이라는 koa 만의 장점과 번들 소스가 작아 필요한 대로 가져다 쓰는 점 등이 사용성은 훨 씬 좋았습니다.
미들웨어라는 개념만 이해한다면 크게 어려움 없이 접근할 수 있는 가벼운 프레임워크라 생각이 듭니다.
할 말이 없을 정도로.. 아주 가볍고 좋네요! :)
2023.02.23
- koa 가 번들 미들웨어를 포함하지 않음으로써, 이것저것 필요한걸 추가로 설치하는데.. 이러다가 express 되겠다는 생각?.. 미들웨어 비동기 제어말고는 경량이라는 것이 장점이 될 수 있을까? 싶은생각이 든다..!