Effect Integration
이 페이지의 함수들은
effect패키지에 의존합니다.effect가 설치되지 않은 프로젝트에서는 이 페이지의 내용이 필요하지 않습니다.
@asapjs/error는 Effect 라이브러리와의 통합을 위해 에러 변환 유틸리티와 Express 미들웨어를 제공합니다. Effect의 Cause를 JavaScript 에러로 변환하고, Effect 기반 핸들러를 Express 미들웨어 체인에 연결할 수 있습니다.
임포트
import {
causeToError,
runEffectAsPromise,
effectErrorHandler,
wrapWithEffect,
} from '@asapjs/error';이 페이지에서 찾을 수 있는 것
| 심볼 | 타입 | 설명 |
|---|---|---|
causeToError() | Function | Effect Cause를 일반 에러로 변환 |
runEffectAsPromise() | Function | Effect를 Promise로 실행 |
effectErrorHandler | Express Middleware | 에러 로깅 및 응답 생성 미들웨어 |
wrapWithEffect() | Higher-order Function | 핸들러를 Effect 추적으로 감싸는 래퍼 |
causeToError()
import { causeToError } from '@asapjs/error';
function causeToError(cause: Cause.Cause<unknown>): unknownEffect의 Cause에서 원본 에러를 추출합니다. 실패 원인을 다음 순서로 탐색합니다:
Cause.failureOption— 명시적 실패 (Effect.fail)Cause.dieOption— 예기치 않은 종료 (Effect.die)Cause.isInterrupted— 인터럽트 →new Error('Operation interrupted')Cause.failures— 복합 실패의 첫 번째 원인- 위 모두 해당 없음 →
new Error('Unknown error')
| 파라미터 | 타입 | 설명 |
|---|---|---|
cause | Cause.Cause<unknown> | Effect 실패 원인 |
반환값: 추출된 에러 객체.
import { Effect, Cause, Exit } from 'effect';
import { causeToError } from '@asapjs/error';
const exit = await Effect.runPromiseExit(
Effect.fail(new HttpError(404, 'NOT_FOUND', '찾을 수 없습니다'))
);
if (Exit.isFailure(exit)) {
const error = causeToError(exit.cause);
// error === HttpError { status: 404, ... }
}runEffectAsPromise()
import { runEffectAsPromise } from '@asapjs/error';
async function runEffectAsPromise<A, E>(
effect: Effect.Effect<A, E, never>
): Promise<A>Effect를 실행하고 결과를 Promise로 반환합니다. 성공 시 값을 resolve하고, 실패 시 causeToError()로 변환된 에러를 throw합니다.
| 파라미터 | 타입 | 설명 |
|---|---|---|
effect | Effect.Effect<A, E, never> | 실행할 Effect. 환경 의존성이 없어야 함 (never) |
반환값: Promise<A> — Effect의 성공 값.
import { Effect } from 'effect';
import { runEffectAsPromise } from '@asapjs/error';
// 성공
const result = await runEffectAsPromise(Effect.succeed(42));
// result === 42
// 실패 — causeToError()로 변환된 에러가 throw됨
try {
await runEffectAsPromise(
Effect.fail(new HttpError(400, 'BAD_REQUEST', '잘못된 요청'))
);
} catch (err) {
// err === HttpError { status: 400, ... }
}effectErrorHandler
import { effectErrorHandler } from '@asapjs/error';
const effectErrorHandler: (
error: unknown,
req: Request,
res: Response,
next: NextFunction
) => voidExpress 에러 처리 미들웨어입니다. 에러를 구조화된 컨텍스트와 함께 로깅한 후 errorToResponse()를 통해 HTTP 응답을 생성합니다.
로깅 컨텍스트
에러 발생 시 다음 정보를 로그에 포함합니다:
| 필드 | 설명 |
|---|---|
requestId | 요청 식별자 (req.id 또는 'unknown') |
method | HTTP 메서드 |
url | 요청 URL |
ip | 클라이언트 IP |
userAgent | User-Agent 헤더 |
file | 에러 발생 파일 (스택 트레이스에서 추출) |
line | 에러 발생 라인 (스택 트레이스에서 추출) |
function | 에러 발생 함수명 (스택 트레이스에서 추출) |
스택 트레이스 분석
effectErrorHandler는 내부적으로 getStackInfo() 함수를 사용하여 에러의 스택 트레이스에서 파일, 라인, 함수명을 추출합니다. 이 정보는 로그 컨텍스트에 포함되어 디버깅을 돕습니다.
import express from 'express';
import { effectErrorHandler } from '@asapjs/error';
const app = express();
// ... 라우트 등록 후
app.use(effectErrorHandler);wrapWithEffect()
import { wrapWithEffect } from '@asapjs/error';
function wrapWithEffect<T extends (...args: any[]) => any>(
handler: T
): (...args: any[]) => Promise<any>핸들러 함수를 Effect 추적(Effect.withSpan)으로 감싸는 고차 함수입니다. 반환된 함수는 원본 핸들러와 같은 인자를 받지만 Effect 기반 추적과 에러 처리가 추가됩니다.
| 파라미터 | 타입 | 설명 |
|---|---|---|
handler | T | 감쌀 핸들러 함수 |
반환값: Effect 추적이 추가된 새 async 함수.
이중 실행 경로
wrapWithEffect()는 두 가지 호출 패턴을 자동 감지합니다:
경로 1 — Express 미들웨어 (req, res, next):
// args가 3개이고 첫 번째에 req, 세 번째에 next가 있는 경우
app.use(wrapWithEffect(async (req, res, next) => {
// 비즈니스 로직
}));이 경우 에러 발생 시 next(error)로 전달합니다.
경로 2 — ASAPJS Router Wrapper (ExecuteArgs):
// args가 1개이고 { req, res } 형태인 경우 (Wrapper가 cb(args)로 호출)
const handler = wrapWithEffect(async ({ req, res, body, path }: ExecuteArgs) => {
// 비즈니스 로직
});이 경우 에러 발생 시 그대로 throw합니다 (상위 Wrapper의 catch가 처리).
Effect 추적
Effect.withSpan으로 각 요청에 span을 생성합니다:
- Span 이름:
{HTTP메서드} {경로}(예:GET /api/users) - 속성:
http.method— HTTP 메서드http.path— 요청 경로http.request_id— 요청 식별자
에러 처리 흐름
- 핸들러를
Effect.promise()로 래핑 Effect.withSpan()으로 추적 추가Effect.runPromiseExit()로 실행- 실패 시
causeToError(exit.cause)로 원본 에러 추출 - Express 미들웨어 경로 →
next(error), Router 경로 →throw error
import { wrapWithEffect } from '@asapjs/error';
// Express 미들웨어 패턴
const tracedMiddleware = wrapWithEffect(async (req, res, next) => {
const data = await someEffectBasedService();
res.json(data);
});
app.get('/api/data', tracedMiddleware);