API 매개변수는 종종 복잡한 구조를 가지며, 단일 엔드포인트가 여러 가지 다른 매개변수 조합을 지원합니다. 예를 들어, 로그인 엔드포인트는 사용자 이름-비밀번호 인증, 이메일-비밀번호 인증 또는 전화번호 인증 코드를 지원할 수 있습니다. 결제 엔드포인트는 신용카드, 위챗 페이(WeChat Pay), 알리페이(Alipay)와 같이 다양한 방법을 제공할 수 있으며, 각 방법은 다른 필드를 요구합니다.

기존 API 문서화 방식은 종종 모든 가능한 필드를 단순히 나열하고 "시나리오에 따라 다른 필드를 선택하세요"와 같은 텍스트 설명을 사용합니다. 이러한 접근 방식은 정확하지도 않고 개발자 친화적이지도 않아 혼란을 초래하는 경우가 많습니다. Apidog은 JSON 스키마의 oneOf, anyOf, allOf 기능을 지원하여 이러한 복잡한 복합 데이터 구조를 API 문서에 정확하게 설명할 수 있도록 합니다.
세 가지 조합 모드 이해하기
JSON 스키마에서 oneOf, anyOf, allOf는 여러 하위 스키마를 결합하는 데 사용되지만, 각각 다른 논리적 의미를 가집니다.
- allOf: 여러 규칙을 결합하며, 모든 규칙이 일치해야 합니다.
- anyOf: 최소 하나가 일치해야 하며, 여러 개가 일치해도 허용됩니다.
- oneOf: 정확히 하나의 스키마와 일치해야 하며, 0개 또는 여러 개가 일치하면 실패합니다.
Apidog에서 조합 모드 설정하기
Apidog은 이러한 조합 모드를 사용하는 두 가지 방법을 제공합니다.
시각 편집기 방식
첫 번째 방법은 시각 편집 패널을 사용하는 것입니다. 프로젝트에서 "데이터 모델(Data Models)"을 클릭하여 새 모델을 생성한 다음, 유형 선택에서 "조합 모드(Combination Modes)"를 찾습니다. 필요한 oneOf, anyOf 또는 allOf 모드를 선택한 다음, 각 하위 스키마에 대한 특정 데이터 구조를 정의합니다.

JSON 스키마 코드 편집기
두 번째 접근 방식은 JSON 스키마 코드를 직접 편집하는 것입니다. 데이터 모델 편집 패널에서 코드 모드로 전환하여 이러한 논리적 조합 패턴을 정의하기 위해 JSON 스키마를 직접 작성할 수 있습니다. 이 방법은 JSON 스키마에 익숙한 개발자에게 더 직접적입니다.

API 엔드포인트에 이러한 패턴 적용하기
데이터 모델을 정의한 후에는 API 문서에서 이를 사용할 수 있습니다. 인터페이스 요청 매개변수를 편집할 때 본문 유형을 JSON으로 선택한 다음, 데이터 구조 섹션에서 방금 생성한 "데이터 모델(Data Models)"을 참조하거나 "조합 모드(Combination Modes)"를 직접 선택하여 복잡한 매개변수 구조를 정의할 수 있습니다.

동일한 원칙이 응답 데이터 정의에도 적용됩니다. 반환 응답 섹션에 응답 예시를 추가할 때 조합 모드를 사용하여 다양한 시나리오에 대한 응답 형식을 설명할 수 있습니다. 이러한 방식으로 개발자는 다양한 상황에서 어떤 데이터 구조가 반환될지 명확하게 이해할 수 있습니다.
실제 사용 사례
allOf: 여러 구조 결합하기
allOf는 여러 구조를 함께 결합합니다. 이는 선택이 아니라 쌓는 것에 가깝습니다. allOf는 필드 계층을 변경하지 않으며, 모든 필드는 동일한 객체에 포함됩니다. 단순히 동일한 데이터에 여러 규칙을 쌓는 것입니다. 이를 "논리적 AND"로 생각할 수 있습니다. 즉, 모든 하위 구조 제약 조건이 충족되어야 합니다.
예를 들어, 다음 JSON 스키마:
{
"allOf": [
{
"description": "Basic user information",
"type": "object",
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" }
},
"required": ["id", "name"]
},
{
"description": "Contact information",
"type": "object",
"properties": {
"email": { "type": "string", "format": "email" },
"phone": { "type": "string" }
},
"required": ["email"]
}
]
}
이 스키마는 최종 데이터가 "기본 사용자 정보"와 "연락처 정보" 구조를 동시에 만족해야 함을 의미합니다.
다시 말해, 요청 본문에는 id, name, email이 포함되어야 하며, phone은 선택 사항입니다.
유효한 데이터:
{
"id": 1001,
"name": "John Doe",
"email": "john@example.com",
"phone": "1-800-000-0000"
}
유효하지 않은 데이터:
{
"id": 1001,
"name": "John Doe"
}
이는 필수 이메일 필드가 누락되어 두 번째 구조를 만족하지 않습니다.
이 접근 방식은 복잡한 객체를 분할하는 데 적합합니다. 사용자 정보, 주문 세부 정보, 구성 항목 등은 모두 기능 모듈별로 독립적인 구조로 나눈 다음 allOf를 사용하여 결합할 수 있습니다. 이러한 구조의 일부가 필요한 다른 인터페이스는 중복 정의 없이 직접 참조할 수 있습니다.
anyOf: 최소 하나의 조건 만족하기
anyOf는 여러 가능한 구조를 나열하며, 데이터가 그 중 최소 하나를 준수하는 한 유효한 것으로 간주됩니다. 여러 조건이 충족되는지 여부나 고유한 일치를 요구하지 않습니다.
예를 들어, 식별자 필드는 이메일 또는 전화번호일 수 있습니다. 이 두 형식은 분명히 다르지만, 둘 다 "사용자 로그인 자격 증명" 범주에 속합니다.
"A 또는 B가 될 수 있다"는 의도를 명확하게 표현하기 위해 anyOf를 사용할 수 있습니다.
{
"type": "object",
"properties": {
"identifier": {
"description": "User identifier: can be email or phone number",
"anyOf": [
{
"title": "Email format",
"description": "Must be a valid email address",
"type": "string",
"format": "email"
},
{
"title": "Phone format",
"description": "Must be a valid international phone number",
"type": "string",
"pattern": "^\\+?[1-9]\\d{1,14}$"
}
]
},
"password": {
"type": "string",
"minLength": 6,
"description": "Login password, at least 6 characters"
}
},
"required": ["identifier", "password"],
"description": "User login request parameters"
}
이 구조는 식별자가 이메일 형식 또는 전화번호 형식 중 하나를 만족하는 한 유효한 것으로 간주되는 문자열임을 의미합니다.
유효한 데이터:
{
"identifier": "test@example.com",
"password": "123456"
}
{
"identifier": "+1-800-000-0000",
"password": "123456"
}
유효하지 않은 데이터:
{
"identifier": "abc",
"password": "123456"
}
"abc"는 이메일도 유효한 전화번호 형식도 아니므로, 어떤 조건도 만족하지 않습니다.
oneOf: 정확히 하나의 옵션 선택하기
oneOf는 여러 가능한 구조를 나열하며, 데이터는 그 중 정확히 하나를 준수해야 합니다. 이는 배타성을 강조합니다. 즉, 하나만 선택할 수 있으며, 그 이상도 이하도 안 됩니다.
예를 들어, 결제 방법의 경우: 결제를 완료하려면 사용자는 신용카드, 위챗 페이(WeChat Pay), 알리페이(Alipay) 중 하나를 선택해야 하지만, 동시에 두 가지 방법을 사용할 수 없으며, 아무것도 선택하지 않을 수도 없습니다. 이러한 "단일 선택" 논리를 oneOf를 사용하여 정의할 수 있습니다.
{
"properties": {
"paymentMethod": {
"description": "Payment method, must choose exactly one",
"oneOf": [
{
"title": "Credit Card Payment",
"description": "Pay with credit card, requires card number and expiry date",
"type": "object",
"properties": {
"type": { "const": "credit_card" },
"cardNumber": { "type": "string" },
"expiryDate": { "type": "string" }
},
"required": ["type", "cardNumber", "expiryDate"],
"additionalProperties": false
},
{
"title": "WeChat Pay",
"description": "Pay through WeChat, requires user's openid",
"type": "object",
"properties": {
"type": { "const": "wechat" },
"openid": { "type": "string" }
},
"required": ["type", "openid"],
"additionalProperties": false
},
{
"title": "Alipay Payment",
"description": "Pay through Alipay, requires account ID",
"type": "object",
"properties": {
"type": { "const": "alipay" },
"accountId": { "type": "string" }
},
"required": ["type", "accountId"],
"additionalProperties": false
}
]
}
}
}
이 정의는 paymentMethod가 세 가지 하위 구조 중 하나만 일치할 수 있는 객체임을 의미합니다.
유효한 예시:
{
"paymentMethod": {
"type": "wechat",
"openid": "wx_123456"
}
}
{
"paymentMethod": {
"type": "credit_card",
"cardNumber": "4111111111111111",
"expiryDate": "12/25"
}
}
유효하지 않은 예시:
{
"paymentMethod": {
"type": "wechat",
"openid": "wx_123",
"accountId": "2088102"
}
}
type이 "wechat"임에도 불구하고, accountId의 존재로 인해 여러 구조와 일치하게 되어 oneOf가 실패할 수 있습니다. `"additionalProperties": false`를 추가하면 이러한 혼란을 방지하고(즉, 추가 필드가 허용되지 않음), 각 구조가 자체적으로 정의된 필드만 허용하도록 보장합니다. Apidog은 additionalProperties에 대한 시각적 구성을 지원합니다.
여러 개의 고유한 유형 중에서 배타적인 선택을 해야 할 때, oneOf는 이를 표현하는 가장 직접적이고 신뢰할 수 있는 방법입니다.
올바른 조합 모드 선택하기
조합 모드의 선택은 주로 비즈니스 로직에 따라 달라집니다.
- 여러 패턴을 결합하고 상속해야 할 때 allOf를 사용하세요.
- 유연한 선택적 조합이 필요할 때 anyOf를 사용하세요.
- 엄격한 배타적 선택이 필요할 때 oneOf를 사용하세요.
각각의 역할을 이해하면 API 문서가 복잡한 데이터 구조를 정확하게 설명할 수 있으며, 인터페이스 사용자에게 매개변수를 전달하는 방법을 즉시 명확하게 보여줄 수 있습니다.
결론
Apidog의 포괄적인 JSON 스키마 지원은 개발자가 가장 복잡한 매개변수 구조에 대해서도 정밀하고 명확한 API 문서를 생성할 수 있도록 합니다. oneOf, anyOf, allOf 조합을 활용하여 모호함을 없애고 API 사용자에게 명확한 지침을 제공할 수 있습니다.
고급 API 문서화의 강력함을 경험할 준비가 되셨나요? 지금 Apidog을 사용해보고 복잡한 API 매개변수를 정밀하고 명확하게 관리하는 것이 얼마나 쉬워지는지 확인해보세요.
