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:CpuTimeoutError | CPU 시간 한도 초과 |
| 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는 게시 함수가 사용하는 쿼리를 명시합니다. 구조화된 오류를 소비 앱에 그대로 전달할지, 사용자에게 보여 줄 오류로 바꿀지는 해당 호출 경계에서 결정합니다.