Keyboard shortcuts

Press ← or → to navigate between chapters

Press ? to show this help

Press Esc to hide this help

TypeScript v1 구조화된 오류 반환

TSv1은 일반 출력 타입에 더해 오류 이름과 오류 값을 선언할 수 있습니다. 다른 저장소의 쿼리 호출에서 성공과 업무 오류를 구분해 처리할 때 사용합니다.

FunctionsError와 FunctionsResult

FunctionsError는 문자열 이름과 값 타입을 받습니다. 값 타입을 생략하면 빈 객체가 기본이며, 객체와 객체 집합을 포함한 함수의 유효 출력 타입을 오류 값으로 사용할 수 있습니다. 여러 FunctionsError를 합집합으로 묶을 수 있습니다.

FunctionsResult<Output, Error>는 정상 출력과 선언한 오류를 함께 나타냅니다. FunctionsResult.ok(value)는 성공을, FunctionsResult.err(name, value)는 해당 업무 오류를 만듭니다.

아래 가상 Employee에는 검색 가능한 String employeeId와 teammates 링크가 있습니다. employeeId는 업무 식별 속성이며 이 예제에서는 온톨로지 기본 키와 다릅니다. 따라서 같은 값이 여러 객체에 들어 있으면 중복 오류로 다룹니다.

import { FunctionsError, FunctionsResult, Query } from "@foundry/functions-api";
import { Employee, Objects } from "@foundry/ontology-api";

type GetTeammatesError =
    | FunctionsError<"EmployeeNotFoundForId", string>
    | FunctionsError<"MultipleEmployeesFoundForId", { employees: Employee[]; employeeId: string }>;

export class TeammateQueries {
    @Query({ apiName: "getTeammates" })
    public async getTeammates(employeeId: string): Promise<FunctionsResult<Employee[], GetTeammatesError>> {
        const employees = await Objects.search().employee()
            .filter(employee => employee.employeeId.exactMatch(employeeId)).allAsync();
        if (employees.length === 0) {
            return FunctionsResult.err("EmployeeNotFoundForId", employeeId);
        }
        if (employees.length > 1) {
            return FunctionsResult.err("MultipleEmployeesFoundForId", {
                employees: [...employees], employeeId,
            });
        }
        const teammates = await employees[0]!.teammates.allAsync();
        return FunctionsResult.ok([...teammates]);
    }
}

클래스를 index.ts에서 내보내고 쿼리 게시를 완료합니다. Query는 Function과 중복해서 붙이지 않습니다.

런타임 오류

FunctionsResult는 다음 런타임 기반 오류도 기본으로 포함합니다.

오류 이름의미
FunctionsTypeScriptExecutorService:CpuTimeoutErrorCPU 시간 한도 초과
FunctionsTypeScriptExecutorService:WallTimeoutError전체 실행 시간 한도 초과
FunctionsTypeScriptExecutorService:OutOfMemoryError메모리 한도 초과
FunctionsTypeScriptExecutorService:RuntimeError그 밖의 런타임 오류

사용자가 정의한 직원 조회 오류와 실행 기반 오류를 같은 성공값으로 처리하지 않아야 합니다.

다른 저장소에서 오류 처리

게시한 쿼리를 소비 저장소의 Resource imports에서 가져옵니다. 아래는 생성된 @foundry/ontology-api/queries의 named query 바인딩을 사용합니다. isOk 또는 isErr 타입 가드로 결과를 좁힐 수 있으며 성공은 value, 오류는 error.name과 error.value를 읽습니다.

import { Function, isOk, Uses, UserFacingError } from "@foundry/functions-api";
import { getTeammates } from "@foundry/ontology-api/queries";

export class TeammateConsumers {
    @Uses({ queries: [getTeammates] })
    @Function()
    public async teammateSummary(employeeId: string): Promise<string> {
        const result = await getTeammates({ employeeId });
        if (isOk(result)) return `Teammates: ${result.value.length}`;

        switch (result.error.name) {
            case "EmployeeNotFoundForId":
                throw new UserFacingError(`직원을 찾을 수 없습니다: ${result.error.value}`);
            case "MultipleEmployeesFoundForId":
                throw new UserFacingError(`같은 직원 ID에 ${result.error.value.employees.length}개 객체가 있습니다.`);
            case "FunctionsTypeScriptExecutorService:CpuTimeoutError":
                throw new UserFacingError("직원 조회 함수가 CPU 시간 한도를 넘었습니다.");
            case "FunctionsTypeScriptExecutorService:WallTimeoutError":
                throw new UserFacingError("직원 조회 함수의 실행 시간이 초과되었습니다.");
            case "FunctionsTypeScriptExecutorService:OutOfMemoryError":
                throw new UserFacingError("직원 조회 함수의 메모리가 부족합니다.");
            case "FunctionsTypeScriptExecutorService:RuntimeError":
                throw new UserFacingError("직원 조회 함수에서 실행 오류가 발생했습니다.");
            default:
                throw new Error("처리하지 않은 쿼리 오류가 발생했습니다.");
        }
    }
}

@Uses는 게시 함수가 사용하는 쿼리를 명시합니다. 구조화된 오류를 소비 앱에 그대로 전달할지, 사용자에게 보여 줄 오류로 바꿀지는 해당 호출 경계에서 결정합니다.