Skip to Content

Effect Integration

이 페이지의 함수들은 effect 패키지에 의존합니다. effect가 설치되지 않은 프로젝트에서는 이 페이지의 내용이 필요하지 않습니다.

@asapjs/error는 Effect 라이브러리와의 통합을 위해 에러 변환 유틸리티와 Express 미들웨어를 제공합니다. Effect의 Cause를 JavaScript 에러로 변환하고, Effect 기반 핸들러를 Express 미들웨어 체인에 연결할 수 있습니다.

임포트

import { causeToError, runEffectAsPromise, effectErrorHandler, wrapWithEffect, } from '@asapjs/error';

이 페이지에서 찾을 수 있는 것

심볼타입설명
causeToError()FunctionEffect Cause를 일반 에러로 변환
runEffectAsPromise()FunctionEffect를 Promise로 실행
effectErrorHandlerExpress Middleware에러 로깅 및 응답 생성 미들웨어
wrapWithEffect()Higher-order Function핸들러를 Effect 추적으로 감싸는 래퍼

causeToError()

import { causeToError } from '@asapjs/error'; function causeToError(cause: Cause.Cause<unknown>): unknown

Effect의 Cause에서 원본 에러를 추출합니다. 실패 원인을 다음 순서로 탐색합니다:

  1. Cause.failureOption — 명시적 실패 (Effect.fail)
  2. Cause.dieOption — 예기치 않은 종료 (Effect.die)
  3. Cause.isInterrupted — 인터럽트 → new Error('Operation interrupted')
  4. Cause.failures — 복합 실패의 첫 번째 원인
  5. 위 모두 해당 없음 → new Error('Unknown error')
파라미터타입설명
causeCause.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합니다.

파라미터타입설명
effectEffect.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 ) => void

Express 에러 처리 미들웨어입니다. 에러를 구조화된 컨텍스트와 함께 로깅한 후 errorToResponse()를 통해 HTTP 응답을 생성합니다.

로깅 컨텍스트

에러 발생 시 다음 정보를 로그에 포함합니다:

필드설명
requestId요청 식별자 (req.id 또는 'unknown')
methodHTTP 메서드
url요청 URL
ip클라이언트 IP
userAgentUser-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 기반 추적과 에러 처리가 추가됩니다.

파라미터타입설명
handlerT감쌀 핸들러 함수

반환값: 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 — 요청 식별자

에러 처리 흐름

  1. 핸들러를 Effect.promise()로 래핑
  2. Effect.withSpan()으로 추적 추가
  3. Effect.runPromiseExit()로 실행
  4. 실패 시 causeToError(exit.cause)로 원본 에러 추출
  5. 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);

관련 항목

  • 에러HttpError, error() 팩토리, errorToResponse() 등 핵심 에러 API
  • 요청 처리Wrapper 함수와 에러 처리 흐름
  • 부트스트랩 — 미들웨어 등록과 플러그인 초기화 순서
Last updated on