필드 출력 스키마

필드 타입과 출력 형식을 이해하기 위한 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 값을 기준으로 삼으세요.

응답 필드

필드타입설명
successboolean요청 성공 여부
data.arrayTypesobject배열을 반환하는 필드 타입에 대한 정보
data.arrayTypes.fieldTypesarray문자열 배열을 반환하는 필드 타입 목록
data.arrayTypes.examplearray배열 출력 형식 예시
data.gridTypesobject그리드/테이블 필드 타입에 대한 정보
data.gridTypes.fieldTypesarray그리드 데이터를 반환하는 필드 타입 목록
data.gridTypes.exampleobject그리드 출력 형식 예시
data.objectTypesobject객체를 반환하는 필드 타입에 대한 정보
data.objectTypes.fieldsarray각 객체 필드 타입의 상세 스키마
data.stringTypesobject문자열을 반환하는 필드 타입에 대한 정보
data.stringTypes.fieldTypesarray단순 문자열을 반환하는 필드 타입 목록
data.stringTypes.examplestring문자열 출력 형식 예시
data.customTypesobject커스텀 필드 타입에 대한 정보 (출력 스키마는 필드 버전별로 정의)
data.nullTypesobject표시 전용 필드 타입에 대한 정보
data.nullTypes.fieldTypesarray값을 반환하지 않는 필드 타입 목록

에러 응답

  • 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 || '');
}

모범 사례

  1. 스키마 캐싱: 필드 출력 스키마는 거의 바뀌지 않으므로, 반복 호출을 줄이기 위해 캐시하세요.

  2. 처리 전 검증: 응답 데이터를 처리하기 전에 타입이 예상과 맞는지 항상 확인하세요.

  3. 알 수 없는 타입 처리: 모르는 필드 타입이 나오면 로그를 남기되, 전체 파이프라인을 중단하지는 마세요.

  4. 폼 필드 API와 함께 사용: 폼 구조를 정확히 파악하려면 폼 필드 API도 함께 참조하세요.

  5. 타입 안전 파싱: TypeScript나 타입 힌트를 활용해 타입 안전하게 파싱하세요.

다음 단계

목차