필드 출력 스키마
필드 타입과 출력 형식을 이해하기 위한 API 레퍼런스
필드 출력 스키마 API
필드 출력 스키마 API는 각 필드 타입이 어떤 형식의 데이터를 반환하는지 알려줍니다. 폼 응답 데이터를 올바르게 파싱하려면 이 정보가 필요합니다.
언제 사용하나요?
폼 응답 API로 가져온 응답 데이터에는 필드 ID를 키로 한 동적 값이 들어 있습니다. 이 값이 문자열인지, 배열인지, 객체인지 알려면 필드 출력 스키마를 먼저 확인해야 합니다. 응답 파서를 만들거나 데이터를 가공할 때 이 API를 먼저 호출하세요.
참고: API 키당 시간당 6,000건의 속도 제한이 적용됩니다. 스키마는 거의 변경되지 않으므로 캐시해서 사용하는 것을 권장합니다.
개요
폼 응답의 response 객체에는 필드 ID를 키로, 필드 타입에 따른 값이 동적으로 들어갑니다. 필드 출력 스키마 API를 통해 각 필드 타입의 데이터 구조를 확인할 수 있습니다.
필드 출력 스키마 조회
필드 타입별 출력 스키마 매핑 정보를 반환합니다.
GET /open-api/v1/field-output-schemas요청
요청 예시
curl -X GET "https://api.walla.my/open-api/v1/field-output-schemas" \
-H "X-WALLA-API-KEY: your_api_key_here" \
-H "Content-Type: application/json"응답
성공 응답 (200 OK)
{
"success": true,
"data": {
"arrayTypes": {
"description": "배열 형식으로 응답이 저장되는 필드 타입들입니다. 사용자가 하나 이상의 옵션을 선택할 수 있습니다.",
"outputType": "Array<string>",
"fieldTypes": ["RADIO", "DROPDOWN", "CHECKBOX", "PRIVACY_POLICY_INFORMATION", "LINEAR"],
"example": ["옵션1", "옵션2", "옵션3"]
},
"gridTypes": {
"description": "그리드 형식으로 응답이 저장되는 필드 타입들입니다. 행과 열로 구성된 선택형 질문입니다.",
"outputType": "Record<string, Array<string>>",
"fieldTypes": ["CHECKBOX_GRID", "RADIO_GRID"],
"example": {
"행1": ["열1", "열2"],
"행2": ["열2"]
}
},
"objectTypes": {
"description": "구조화된 객체 형식으로 응답이 저장되는 필드 타입들입니다.",
"fields": [
{
"fieldType": "GEOLOCATION",
"outputType": "Object",
"schema": { "latitude": "string", "longitude": "string" },
"example": { "latitude": "37.5665", "longitude": "126.9780" }
},
{
"fieldType": "TABLE",
"outputType": "Record<string, Record<string, string>>",
"schema": { "[행키]": { "[열키]": "string" } },
"example": {
"행1": { "열1": "값1", "열2": "값2" }
}
},
{
"fieldType": "TOSS_PAYMENTS",
"outputType": "Object",
"schema": {
"status": "request_success | request_fail | confirm_fail | confirm_cancel | confirm_cancel_fail",
"orderId": "string",
"amount": "string",
"message": "string (optional, 에러시)",
"code": "string (optional, 에러시)"
},
"example": {
"status": "request_success",
"orderId": "ORDER_12345",
"amount": "10000"
}
}
]
},
"stringTypes": {
"description": "단순 문자열 형식으로 응답이 저장되는 필드 타입들입니다.",
"outputType": "string",
"fieldTypes": [
"NUMBER",
"DATE",
"TIME",
"SHORT_TEXT",
"VIDEO_UPLOAD",
"PHONE_NUMBER",
"IMAGE_UPLOAD",
"EMAIL",
"FILE_UPLOAD",
"LONG_TEXT",
"ADDRESS",
"HIDDEN"
],
"example": "사용자 입력 텍스트"
},
"customTypes": {
"description": "커스텀 필드 타입입니다. 출력 스키마는 필드 버전별로 다르며, custom_field_versions의 outputSchema에 정의됩니다.",
"outputType": "unknown (defined per custom field version)",
"fieldTypes": ["CUSTOM"],
"example": { "score": 85, "comment": "Good performance" }
},
"nullTypes": {
"description": "사용자 입력이 필요없는 필드 타입들입니다. 응답 데이터에 포함되지 않거나 null 값을 가집니다.",
"outputType": "null",
"fieldTypes": [
"DESCRIPTION",
"ENDING_REDIRECT",
"ENDING_DESCRIPTION",
"WEBSITE_LINK",
"REJECT",
"SUBMIT"
],
"example": null
}
}
}참고: 이 엔드포인트가 돌려주는 목록은 요약본이라 일부 타입(
DROPDOWN_MULTI,PICTURE_CHOICE,SECRETS)이 빠져 있습니다. 전체 타입은 아래 필드 타입 카테고리를 참고하고, 특정 폼의 정확한 스키마는 필드 상세 정보 조회의outputSchema값을 기준으로 삼으세요.
응답 필드
| 필드 | 타입 | 설명 |
|---|---|---|
success | boolean | 요청 성공 여부 |
data.arrayTypes | object | 배열을 반환하는 필드 타입에 대한 정보 |
data.arrayTypes.fieldTypes | array | 문자열 배열을 반환하는 필드 타입 목록 |
data.arrayTypes.example | array | 배열 출력 형식 예시 |
data.gridTypes | object | 그리드/테이블 필드 타입에 대한 정보 |
data.gridTypes.fieldTypes | array | 그리드 데이터를 반환하는 필드 타입 목록 |
data.gridTypes.example | object | 그리드 출력 형식 예시 |
data.objectTypes | object | 객체를 반환하는 필드 타입에 대한 정보 |
data.objectTypes.fields | array | 각 객체 필드 타입의 상세 스키마 |
data.stringTypes | object | 문자열을 반환하는 필드 타입에 대한 정보 |
data.stringTypes.fieldTypes | array | 단순 문자열을 반환하는 필드 타입 목록 |
data.stringTypes.example | string | 문자열 출력 형식 예시 |
data.customTypes | object | 커스텀 필드 타입에 대한 정보 (출력 스키마는 필드 버전별로 정의) |
data.nullTypes | object | 표시 전용 필드 타입에 대한 정보 |
data.nullTypes.fieldTypes | array | 값을 반환하지 않는 필드 타입 목록 |
에러 응답
- 401 Unauthorized: API 키 누락 또는 유효하지 않음
{ "error": "Unauthorized" } - 429 Too Many Requests: 속도 제한 초과
{ "error": "Rate limit exceeded" }
필드 타입 카테고리
문자열 타입 (단순 텍스트 값)
아래 필드 타입은 단일 문자열 값을 반환합니다.
- SHORT_TEXT: 단답형
- LONG_TEXT: 장문형
- NUMBER: 숫자
- DATE: 날짜
- TIME: 시간
- EMAIL: 이메일
- PHONE_NUMBER: 전화번호
- ADDRESS: 주소 (한 줄 문자열)
- SECRETS: 비밀 정보 입력
- FILE_UPLOAD: 파일 업로드 (파일 URL 문자열)
- IMAGE_UPLOAD: 사진 촬영 (파일 URL 문자열)
- VIDEO_UPLOAD: 영상 촬영 (파일 URL 문자열)
응답 예시:
{
"field_abc123": "홍길동"
}배열 타입 (복수 값)
아래 필드 타입은 선택 항목 하나만 고르는 경우에도 문자열 배열을 반환합니다.
- RADIO: 객관식
- DROPDOWN: 드롭다운
- DROPDOWN_MULTI: 드롭다운 (다중 선택)
- CHECKBOX: 객관식 (다중 선택)
- PICTURE_CHOICE: 사진 선택
- PRIVACY_POLICY_INFORMATION: 개인정보 수집 동의
- LINEAR: 선형 배율
응답 예시:
{
"field_xyz789": ["옵션 A", "옵션 B", "옵션 C"]
}객체 타입 (구조화된 데이터)
아래 필드 타입은 여러 속성을 포함한 객체를 반환합니다.
- GEOLOCATION: latitude, longitude를 포함한 위치 기록
- TABLE: 행 → 열 → 값 형태의 2중 객체
- TOSS_PAYMENTS: status, orderId, amount(에러 시 message, code)를 포함한 결제 결과
응답 예시:
{
"field_def456": {
"latitude": "37.5665",
"longitude": "126.9780"
},
"field_ghi789": {
"행1": { "열1": "값1", "열2": "값2" },
"행2": { "열1": "값3", "열2": "값4" }
}
}그리드 타입 (표 형식 선택)
아래 필드 타입은 행 이름을 키로, 선택된 열 이름의 배열을 값으로 갖는 객체를 반환합니다.
- RADIO_GRID: 객관식 표
- CHECKBOX_GRID: 객관식 표 (다중 선택)
응답 예시:
{
"field_grid001": {
"행1": ["열1", "열2"],
"행2": ["열2"]
}
}커스텀 타입
- CUSTOM: 커스텀 필드. 출력 형식이 필드 버전마다 다르므로, 해당 필드의
outputSchema를 확인한 뒤 파싱하세요.
응답 예시:
{
"field_custom001": { "score": 85, "comment": "Good performance" }
}Null 타입 (표시 전용)
아래 필드 타입은 입력을 받지 않으며 응답 데이터에 포함되지 않거나 null을 반환합니다.
- DESCRIPTION: 설명
- WEBSITE_LINK: 임베딩
- SUBMIT: 제출 버튼
- REJECT: 응답 거절
- ENDING_REDIRECT: 종료 후 리디렉션
- ENDING_DESCRIPTION: 종료 화면 설명
응답 예시:
{
"field_description001": null
}코드 예제
JavaScript/TypeScript
interface FieldOutputSchemas {
arrayTypes: {
description: string;
outputType: string;
fieldTypes: string[];
example: string[];
};
gridTypes: {
description: string;
outputType: string;
fieldTypes: string[];
example: object;
};
objectTypes: {
description: string;
fields: Array<{
fieldType: string;
outputType: string;
schema: object;
}>;
};
stringTypes: {
description: string;
outputType: string;
fieldTypes: string[];
example: string;
};
nullTypes: {
description: string;
outputType: string;
fieldTypes: string[];
};
}
async function getFieldOutputSchemas(): Promise<FieldOutputSchemas> {
const response = await fetch(
'https://api.walla.my/open-api/v1/field-output-schemas',
{
headers: {
'X-WALLA-API-KEY': process.env.WALLA_API_KEY!,
'Content-Type': 'application/json'
}
}
);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data.data;
}
// 사용 예: 필드 타입에 따라 응답 데이터 파싱
async function parseResponseValue(
fieldType: string,
value: any,
schemas: FieldOutputSchemas
): Promise<any> {
// 배열 타입인지 확인
if (schemas.arrayTypes.fieldTypes.includes(fieldType)) {
return value as string[];
}
// 문자열 타입인지 확인
if (schemas.stringTypes.fieldTypes.includes(fieldType)) {
return value as string;
}
// null 타입인지 확인
if (schemas.nullTypes.fieldTypes.includes(fieldType)) {
return null;
}
// 객체 타입인지 확인
const objectField = schemas.objectTypes.fields.find(
f => f.fieldType === fieldType
);
if (objectField) {
return value as object;
}
// 그리드 타입인지 확인
if (schemas.gridTypes.fieldTypes.includes(fieldType)) {
return value as object;
}
return value;
}
// 예제: 폼 응답 처리
const schemas = await getFieldOutputSchemas();
console.log('배열 필드 타입:', schemas.arrayTypes.fieldTypes);
console.log('문자열 필드 타입:', schemas.stringTypes.fieldTypes);Python
import requests
import os
from typing import Dict, Any, List, Union
class WallaFieldSchemas:
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "https://api.walla.my/open-api/v1"
self.headers = {
"X-WALLA-API-KEY": api_key,
"Content-Type": "application/json"
}
self._schemas = None
def get_field_output_schemas(self) -> Dict[str, Any]:
"""필드 출력 스키마 매핑 조회"""
if self._schemas:
return self._schemas
url = f"{self.base_url}/field-output-schemas"
response = requests.get(url, headers=self.headers)
response.raise_for_status()
self._schemas = response.json()["data"]
return self._schemas
def get_output_type(self, field_type: str) -> str:
"""주어진 필드 타입의 출력 타입 조회"""
schemas = self.get_field_output_schemas()
if field_type in schemas["arrayTypes"]["fieldTypes"]:
return "array"
elif field_type in schemas["stringTypes"]["fieldTypes"]:
return "string"
elif field_type in schemas["nullTypes"]["fieldTypes"]:
return "null"
elif field_type in schemas["gridTypes"]["fieldTypes"]:
return "grid"
else:
# 객체 타입 확인
for field in schemas["objectTypes"]["fields"]:
if field["fieldType"] == field_type:
return "object"
return "unknown"
def parse_response_value(
self,
field_type: str,
value: Any
) -> Union[str, List[str], Dict, None]:
"""필드 타입에 따라 응답 값 파싱"""
output_type = self.get_output_type(field_type)
if output_type == "null":
return None
elif output_type == "array":
return value if isinstance(value, list) else []
elif output_type == "string":
return str(value) if value is not None else ""
else:
return value
# 사용 예
api = WallaFieldSchemas(os.getenv("WALLA_API_KEY"))
# 스키마 조회
schemas = api.get_field_output_schemas()
print(f"문자열 타입: {schemas['stringTypes']['fieldTypes']}")
print(f"배열 타입: {schemas['arrayTypes']['fieldTypes']}")
# 응답 값 파싱
field_type = "CHECKBOX"
value = ["옵션 A", "옵션 B"]
parsed = api.parse_response_value(field_type, value)
print(f"파싱된 값: {parsed}")사용 사례
1. 동적 폼 응답 파서
필드 출력 스키마를 활용해 범용 응답 파서를 만들 수 있습니다.
async function buildResponseParser(formId: string) {
// 필드 스키마 조회
const schemas = await getFieldOutputSchemas();
// 폼 필드를 조회하여 구조 파악
const fields = await getFormFields(formId);
// 파서 맵 생성
const parser = new Map();
fields.forEach(field => {
parser.set(field.id, {
label: field.label,
fieldType: field.fieldType,
outputType: field.outputType,
parser: (value) => parseResponseValue(field.fieldType, value, schemas)
});
});
return parser;
}
// 파서 사용
const parser = await buildResponseParser('form_abc');
const responses = await getFormResponses('form_abc');
responses.forEach(response => {
Object.entries(response.response).forEach(([fieldId, value]) => {
const fieldParser = parser.get(fieldId);
if (fieldParser) {
const parsedValue = fieldParser.parser(value);
console.log(`${fieldParser.label}: ${parsedValue}`);
}
});
});2. 응답 데이터 검증
처리 전에 응답 데이터 타입을 검증합니다.
function validateResponseData(
fieldType: string,
value: any,
schemas: FieldOutputSchemas
): boolean {
if (schemas.arrayTypes.fieldTypes.includes(fieldType)) {
return Array.isArray(value);
}
if (schemas.stringTypes.fieldTypes.includes(fieldType)) {
return typeof value === 'string';
}
if (schemas.nullTypes.fieldTypes.includes(fieldType)) {
return value === null;
}
if (schemas.gridTypes.fieldTypes.includes(fieldType)) {
return typeof value === 'object' && value !== null;
}
// 객체 타입
const objectField = schemas.objectTypes.fields.find(
f => f.fieldType === fieldType
);
if (objectField) {
return typeof value === 'object' && value !== null;
}
return true;
}3. 응답 데이터 내보내기
필드 타입에 맞게 내보내기용 데이터를 포맷팅합니다.
function formatForExport(
fieldType: string,
value: any,
schemas: FieldOutputSchemas
): string {
if (schemas.arrayTypes.fieldTypes.includes(fieldType)) {
return Array.isArray(value) ? value.join(', ') : '';
}
if (schemas.stringTypes.fieldTypes.includes(fieldType)) {
return String(value || '');
}
if (schemas.nullTypes.fieldTypes.includes(fieldType)) {
return '';
}
// 객체 타입 - JSON 문자열로 변환
if (typeof value === 'object' && value !== null) {
return JSON.stringify(value);
}
return String(value || '');
}모범 사례
-
스키마 캐싱: 필드 출력 스키마는 거의 바뀌지 않으므로, 반복 호출을 줄이기 위해 캐시하세요.
-
처리 전 검증: 응답 데이터를 처리하기 전에 타입이 예상과 맞는지 항상 확인하세요.
-
알 수 없는 타입 처리: 모르는 필드 타입이 나오면 로그를 남기되, 전체 파이프라인을 중단하지는 마세요.
-
폼 필드 API와 함께 사용: 폼 구조를 정확히 파악하려면 폼 필드 API도 함께 참조하세요.
-
타입 안전 파싱: TypeScript나 타입 힌트를 활용해 타입 안전하게 파싱하세요.