필드 출력 스키마

필드 타입과 출력 형식을 이해하기 위한 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",
      "fieldTypes": ["CHECKBOX", "MULTI_SELECT", "FILE_UPLOAD"],
      "example": ["option1", "option2", "option3"]
    },
    "gridTypes": {
      "description": "중첩 배열을 반환하는 필드 타입 (그리드/테이블 형식)",
      "outputType": "grid",
      "fieldTypes": ["GRID"],
      "example": {
        "rows": [
          ["value1", "value2"],
          ["value3", "value4"]
        ]
      }
    },
    "objectTypes": {
      "description": "구조화된 객체를 반환하는 필드 타입",
      "fields": [
        {
          "fieldType": "ADDRESS",
          "outputType": "object",
          "schema": {
            "type": "object",
            "properties": {
              "street": { "type": "string" },
              "city": { "type": "string" },
              "state": { "type": "string" },
              "zipCode": { "type": "string" }
            }
          }
        },
        {
          "fieldType": "NAME",
          "outputType": "object",
          "schema": {
            "type": "object",
            "properties": {
              "firstName": { "type": "string" },
              "lastName": { "type": "string" }
            }
          }
        }
      ]
    },
    "stringTypes": {
      "description": "단순 문자열을 반환하는 필드 타입",
      "outputType": "string",
      "fieldTypes": [
        "SHORT_TEXT",
        "LONG_TEXT",
        "EMAIL",
        "PHONE",
        "NUMBER",
        "DATE",
        "TIME",
        "URL",
        "RADIO",
        "DROPDOWN"
      ],
      "example": "sample text value"
    },
    "nullTypes": {
      "description": "입력이 필요 없는 필드 타입 (표시 전용)",
      "outputType": "null",
      "fieldTypes": ["HEADING", "DESCRIPTION", "DIVIDER", "IMAGE"]
    }
  }
}

응답 필드

필드타입설명
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.nullTypesobject표시 전용 필드 타입에 대한 정보
data.nullTypes.fieldTypesarray값을 반환하지 않는 필드 타입 목록

에러 응답

  • 403 Forbidden: 인증 실패
    {
      "error": "Authentication failed"
    }

필드 타입 카테고리

문자열 타입 (단순 텍스트 값)

아래 필드 타입은 단일 문자열 값을 반환합니다.

  • SHORT_TEXT: 한 줄 텍스트 입력
  • LONG_TEXT: 여러 줄 텍스트 입력
  • EMAIL: 이메일 주소
  • PHONE: 전화번호
  • NUMBER: 숫자 입력
  • DATE: 날짜 값
  • TIME: 시간 값
  • URL: 웹사이트 URL
  • RADIO: 라디오 버튼에서 단일 선택
  • DROPDOWN: 드롭다운 메뉴에서 단일 선택

응답 예시:

{
  "field_abc123": "홍길동"
}

배열 타입 (복수 값)

아래 필드 타입은 문자열 배열을 반환합니다.

  • CHECKBOX: 복수 선택 체크박스
  • MULTI_SELECT: 복수 선택 드롭다운
  • FILE_UPLOAD: 업로드된 파일 URL 목록

응답 예시:

{
  "field_xyz789": ["옵션 A", "옵션 B", "옵션 C"]
}

객체 타입 (구조화된 데이터)

아래 필드 타입은 여러 속성을 포함한 객체를 반환합니다.

  • ADDRESS: street, city, state, zipCode를 포함한 주소
  • NAME: firstName, lastName을 포함한 이름
  • PHONE_DETAILED: countryCode, number를 포함한 상세 전화번호
  • DATE_RANGE: startDate, endDate를 포함한 날짜 범위

응답 예시:

{
  "field_def456": {
    "firstName": "길동",
    "lastName": "홍"
  },
  "field_ghi789": {
    "street": "테헤란로 123",
    "city": "서울",
    "state": "서울특별시",
    "zipCode": "06234"
  }
}

그리드 타입 (테이블 데이터)

아래 필드 타입은 테이블/그리드 형태의 중첩 배열을 반환합니다.

  • GRID: 행과 열이 있는 테이블

응답 예시:

{
  "field_grid001": {
    "rows": [
      ["행1 열1", "행1 열2", "행1 열3"],
      ["행2 열1", "행2 열2", "행2 열3"]
    ]
  }
}

Null 타입 (표시 전용)

아래 필드 타입은 입력을 받지 않으며 null을 반환합니다.

  • HEADING: 섹션 제목
  • DESCRIPTION: 설명 텍스트
  • DIVIDER: 시각적 구분선
  • IMAGE: 표시되는 이미지

응답 예시:

{
  "field_heading001": 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나 타입 힌트를 활용해 타입 안전하게 파싱하세요.

다음 단계

목차