git: 1ad8a8c34359cba105d76d40ddafa55b6a4aac46
AsyncLocalStorage는 Node.js의 API로, 비동기 작업 간에 컨텍스트(예: 사용자 정보)를 공유하기 위해 사용됨. NestJS에서는 이를 기반으로 요청 단위 사용자 컨텍스트를 유지하려고 사용함.
요청 → Express Middleware → Controller → Service → 응답
RequestContext.run(user, () => next())로 감싸면,요청 → Express Middleware → Apollo Server → GraphQL Resolver
↑
(비동기 Task Queue로 분리)
next() 이후 Apollo GraphQL 내부에서 resolver 실행이 비동기 Task로 새로 시작됨AsyncLocalStorage context가 끊어지고, getStore() 호출 시 undefined가 반환됨next() 이후 비동기 환경에서 실행되므로, context가 전파되지 않음사실상 전역
NestMiddleware는 REST 요청에 대해서만 ALS 컨텍스트 유지가 가능
| 요청 종류 | Middleware에서 ALS 가능 여부 | 설명 |
|---|---|---|
| REST | ✅ 가능 | Express 기반 처리 구조라 next 이후에도 context 유지 |
| GraphQL | ❌ 불가 | Apollo Server가 next 이후 비동기 task로 resolver 실행 |
GraphQL의 context()는 모든 resolver로 전파되므로, 여기에 유저 정보를 직접 넣는 방식이 더 적합함.
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
context: ({ req }) => {
return {
req,
user: req.user, // Passport에서 주입된 user
};
},
});
@Query(() => [Item])
async getItems(@Context('user') user: TpUser) {
console.log('Current user:', user.id);
...
}
// gql-user.decorator.ts
export const GqlUser = createParamDecorator(
(data: keyof TpUser | undefined, context: ExecutionContext) => {
const gqlCtx = GqlExecutionContext.create(context);
const user = gqlCtx.getContext().user;
return data ? user?.[data] : user;
}
);
// 사용 예시
@Query(() => [Item])
async getItems(@GqlUser('id') userId: string) {
...
}
RequestMiddleware 안에서 RequestContext.run() 사용 가능RequestContext.run()이 끊어지므로 ALS 사용 부적합context() 함수 안에서 user를 넘기고, resolver에서는 @Context()나 커스텀 데코레이터로 꺼내는 방식 추천