AppSync 마스터하기: Unions 및 Interfaces
I’m happy to translate the article for you, but I’ll need the full text you’d like translated. Could you please paste the content (excluding the source line you already provided) here? Once I have it, I’ll translate it into Korean while preserving the original formatting, markdown, and code blocks.
팀에 AppSync 소개하기
팀에 AppSync를 도입하는 데는 어려움이 따릅니다—특히 팀이 GraphQL (GQL)에 익숙하지 않은 경우에는 더욱 그렇습니다. AppSync APPSYNC_JS 리졸버 전문가로서 여러분은 다음을 설명해야 할 것입니다:
- 병합된 API
- 변경 사항을 테스트하는 방법
- GQL 타입, 스키마, 그리고 쿼리의 기본 개념
제 경험에 따르면 대부분의 팀은 GQL 기본을 빠르게 습득하지만, Union 및 Interface 타입에서는 곤란을 겪는 경우가 많습니다.
언제 하나를 선택해야 할까요? 두 타입의 차이점은 무엇인가요? 팀이 이들을 전혀 필요로 하지 않을까요?
인터페이스나 유니온이 정말 필요할까?
짧은 답변: 아니요, 사용하지 않아도 됩니다.
하지만 인터페이스와 유니온을 사용하면 다른 방법으로는 표현하기 어려운 스키마 제약을 나타낼 수 있습니다. 아래 예시는 왜 이것들이 유용할 수 있는지를 보여줍니다.
Source: …
예시: 오류 유형
사용자에게 입력이 유효하지 않다고 알리는 오류 유형을 상상해 보세요. 기본 형태는 다음과 같은 속성을 가집니다:
| Field | Type | Description |
|---|---|---|
code | String! | 기계가 읽을 수 있는 오류 코드 |
message | String! | 사람이 읽을 수 있는 오류 메시지 |
GQL에서는 이를 다음과 같이 표현할 수 있습니다:
type ValidationError {
code: String!
message: String!
}
기본 오류 확장하기
특정 오류 변형은 추가 필드를 가질 수 있습니다. 두 가지 구체적인 오류를 고려해 보세요:
- MissingPropertiesError – 누락된 필수 필드를 알려줍니다
- ImproperAgeError – 허용되는 최소 연령을 알려줍니다
두 오류 모두 code와 message를 공유하지만, 각각 고유한 선택적 필드를 추가합니다:
type MissingPropertiesError {
code: String!
message: String!
missingProperties: [String!] # 예: ["firstName", "email"]
}
type ImproperAgeError {
code: String!
message: String!
minimumAge: Int # 예: 18
}
클라이언트는 오류 유형을 검사하고 추가 속성을 읽어 더 자세한 정보를 얻을 수 있습니다.
단순 스키마가 표현할 수 없는 것
위 스키마는 missingProperties와 minimumAge가 상호 배타적이라는 사실을 전달하지 못합니다—두 오류 중 하나만 받을 것이며, 두 개가 동시에 나타나지는 않습니다.
다른 API 기술 언어(예: OpenAPI)에서는 이를 위해 oneOf 구문을 제공합니다. GraphQL에서는 인터페이스 또는 유니온을 사용해 동일한 배타성을 구현합니다.
Source: …
GraphQL 인터페이스
인터페이스란?
- 객체지향 언어에서 인터페이스는 클래스의 추상화이며, 구현 클래스가 반드시 지원해야 하는 메서드와 속성을 정의합니다.
- GraphQL에서 인터페이스는 훨씬 단순합니다: 구현 타입이 반드시 노출해야 하는 필드 집합을 정의합니다. 메서드는 없고, 필드만 있습니다.
오류를 위한 인터페이스 정의
interface ValidationError {
code: String!
message: String!
}
이제 구체적인 오류 타입들이 이 인터페이스를 구현합니다:
type MissingPropertiesError implements ValidationError {
code: String!
message: String!
missingProperties: [String!]!
}
type ImproperAgeError implements ValidationError {
code: String!
message: String!
minimumAge: Int!
}
뮤테이션에서 인터페이스 사용
type Mutation {
saveInput(input: Input!): ValidationError
}
인라인 프래그먼트를 이용한 쿼리
mutation Save($input: Input!) {
saveInput(input: $input) {
__typename # 어떤 구체 타입이 반환됐는지 알려줍니다
... on ValidationError {
code
message
}
... on MissingPropertiesError {
missingProperties
}
... on ImproperAgeError {
minimumAge
}
}
}
__typename 필드는 GraphQL이 자동으로 추가해 주며, 클라이언트가 가능한 구체 타입들을 구분할 수 있게 해 줍니다.
프래그먼트를 통해 minimumAge와 missingProperties가 서로 배타적인 관계임을 명시적으로 표현합니다.
GraphQL Union
Union이란 무엇인가?
- Union은 서로 별개의, 관련 없는 타입들을 하나로 묶습니다.
- 인터페이스와 달리, Union은 공통 필드를 정의하지 않습니다.
Union을 언제 사용해야 할까?
- 결과 집합이 이질적일 때 (예: 전체 텍스트 검색 결과가 기사, 사용자, 태그를 모두 반환하는 경우).
- 일반적으로 하나의 필드에서 관련 없는 타입들을 반환하는 것은 API 설계가 좋지 않은 경우이며, 신발, 배, 밀랍 등 전혀 다른 데이터를 반환하는 REST 엔드포인트를 생각해 보세요.
오류를 위한 Union 정의
type MissingPropertiesError {
code: String!
message: String!
missingProperties: [String!]!
}
type ImproperAgeError {
code: String!
message: String!
minimumAge: Int!
}
union ValidationError = MissingPropertiesError | ImproperAgeError
Mutation에서 Union 사용하기
type Mutation {
saveInput(input: Input!): ValidationError
}
Union 조회하기
Union은 공통 필드가 없기 때문에 프래그먼트 안에서 모든 필드를 요청해야 합니다:
mutation Save($input: Input!) {
saveInput(input: $input) {
__typename
... on MissingPropertiesError {
code
message
missingProperties
}
... on ImproperAgeError {
code
message
minimumAge
}
}
}
여전히 상호 배타성을 유지하지만, 공통 필드가 제공하는 편리함은 잃게 됩니다.
Source: …
인터페이스와 유니온 중 선택하기
| 결정 요인 | Interface | Union |
|---|---|---|
| 공통 필드가 존재합니까? | ✅ 인터페이스 사용 | ❌ 부적합 |
| 타입들이 개념적으로 연관되어 있습니까? | ✅ 인터페이스 사용 | ❌ 비추천 |
| 결과 집합이 이질적입니까? (예: 검색 결과) | ❌ 유니온 사용 선호 | ✅ 유니온 사용 |
| 단일 필드가 여러, 무관한 타입을 반환합니까? | ❌ | ✅ 유니온 사용 (드물게) |
경험 법칙:
공통 필드가 하나라도 있다면 인터페이스를 우선 사용하세요. 타입들이 완전히 무관하다면 유니온이 적절할 수 있습니다.
GraphQL “Code Smells” for Interfaces & Unions
- Optional mutually exclusive fields – Good candidate for an interface (e.g., the overloaded
Errortype shown earlier). - Sharing only trivial fields (e.g., just
id) – Avoid creating an interface; the cognitive overhead outweighs the benefit. - Interfaces on full‑text search results – Suspicious; unions usually shine here because search can return many unrelated types.
- Unions on non‑search endpoints – Usually a smell; look for a common interface instead, unless you’re forced by an upstream API.
요약
- Interfaces = 공유 필드 + 구체적인 구현 → 공통점이 있을 때 사용합니다.
- Unions = 완전히 별개의 타입 → 이질적인 결과(예: 검색)에서 사용합니다.
- 두 경우 모두
__typename을 노출하여 클라이언트가 런타임에 구분할 수 있습니다. - 과도한 설계는 피하세요: 실제 문제(상호 배타성, 공유 필드, 이질적인 결과)를 해결할 때만 인터페이스/유니온을 추가합니다.
이러한 이해를 바탕으로 GraphQL 타입 시스템의 미묘한 차이를 팀에 안내하고 AppSync의 강력한 리졸버 모델을 도입할 수 있습니다. 스키마 설계 즐겁게 하세요!
AWS AppSync GraphQL 개발자 가이드: GraphQL의 인터페이스와 유니온
스키마와 타입
그들은 당신에게 답변과 조언을 기대합니다. 예시와 몇 가지 경험 법칙을 제공하면 의사결정을 돕는 데 큰 도움이 되어 팀이 성공하도록 할 수 있습니다.
행복한 개발 되세요!