

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# GraphQL의 인터페이스 및 공용 구조체
<a name="interfaces-and-unions"></a>

GraphQL 형식 시스템은 [인터페이스](https://graphql.org/learn/schema/#interfaces)를 지원합니다. 인터페이스는 인터페이스 구현을 위해 형식에 포함해야 하는 특정 필드 집합을 노출시킵니다.

GraphQL 형식 시스템은 [공용 구조체](https://graphql.org/learn/schema/#union-types)도 지원합니다. 공용 구조체는 필드의 공통 필드 집합을 정의하지 않는다는 점을 제외하면 인터페이스와 동일합니다. 가능한 형식이 논리적 계층 구조를 공유하지 않는 경우 공용 구조체는 일반적으로 인터페이스보다 우선합니다.

다음 섹션은 스키마 입력에 대한 참조입니다.

## 인터페이스 예시
<a name="interfaces"></a>

어떤 종류의 활동 또는 사람들의 모임을 나타내는 `Event` 인터페이스를 표시할 수 있습니다. 가능한 이벤트 유형으로는`Concert`, `Conference`, `Festival`이 있습니다. 이러한 형식은 모두 동일한 특성을 공유하고, 모두 이름, 이벤트가 발생하는 장소와 시작 날짜 및 종료 날짜를 가지고 있습니다. 하지만 이러한 형식에도 차이가 있는데, `Conference`는 발표자 및 워크숍 목록을 제공하는 반면에 `Concert`에는 공연하는 밴드가 있습니다.

SDL(Schema Definition Language)에서 `Event` 인터페이스는 다음과 같이 정의됩니다.

```
interface Event {
        id: ID!
        name : String!
        startsAt: String
        endsAt: String
        venue: Venue
        minAgeRestriction: Int
}
```

`Event` 인터페이스를 구현하는 각 형식은 다음과 같습니다.

```
type Concert implements Event {
    id: ID!
    name: String!
    startsAt: String
    endsAt: String
    venue: Venue
    minAgeRestriction: Int
    performingBand: String
}

type Festival implements Event {
    id: ID!
    name: String!
    startsAt: String
    endsAt: String
    venue: Venue
    minAgeRestriction: Int
    performers: [String]
}

type Conference implements Event {
    id: ID!
    name: String!
    startsAt: String
    endsAt: String
    venue: Venue
    minAgeRestriction: Int
    speakers: [String]
    workshops: [String]
}
```

인터페이스는 여러 형식일 수 있는 요소를 나타내는 데 유용합니다. 예를 들어, 특정 장소에서 개최되는 모든 이벤트를 검색할 수 있습니다. 스키마에 다음과 같이 `findEventsByVenue` 필드를 추가해 보겠습니다.

```
schema {
    query: Query
}

type Query {
    # Retrieve Events at a specific Venue
    findEventsAtVenue(venueId: ID!): [Event]
}

type Venue {
    id: ID!
    name: String
    address: String
    maxOccupancy: Int
}

type Concert implements Event {
    id: ID!
    name: String!
    startsAt: String
    endsAt: String
    venue: Venue
    minAgeRestriction: Int
    performingBand: String
}

interface Event {
    id: ID!
    name: String!
    startsAt: String
    endsAt: String
    venue: Venue
    minAgeRestriction: Int
}

type Festival implements Event {
    id: ID!
    name: String!
    startsAt: String
    endsAt: String
    venue: Venue
    minAgeRestriction: Int
    performers: [String]
}

type Conference implements Event {
    id: ID!
    name: String!
    startsAt: String
    endsAt: String
    venue: Venue
    minAgeRestriction: Int
    speakers: [String]
    workshops: [String]
}
```

`findEventsByVenue`는 `Event` 목록을 반환합니다. GraphQL 인터페이스 필드는 구현하는 모든 형식에 공통적이기 때문에 `Event` 인터페이스에 대해 모든 필드를 선택할 수 있습니다(`id`, `name`, `startsAt`, `endsAt`, `venue` 및 `minAgeRestriction`). 또한 GraphQL [조각](https://graphql.org/learn/queries/#fragments)을 사용하여 형식을 지정하는 한 구현하는 모든 형식에 대한 필드에 액세스할 수 있습니다.

인터페이스를 사용하는 GraphQL 쿼리의 예를 살펴보겠습니다.

```
query {
  findEventsAtVenue(venueId: "Madison Square Garden") {
    id
    name
    minAgeRestriction
    startsAt

    ... on Festival {
      performers
    }

    ... on Concert {
      performingBand
    }

    ... on Conference {
      speakers
      workshops
    }
  }
}
```

이전 쿼리에서는 결과 목록 하나가 생성되었는데 기본적으로 서버에서는 시작 날짜를 기준으로 이벤트를 정렬합니다.

```
{
  "data": {
    "findEventsAtVenue": [
      {
        "id": "Festival-2",
        "name": "Festival 2",
        "minAgeRestriction": 21,
        "startsAt": "2018-10-05T14:48:00.000Z",
        "performers": [
          "The Singers",
          "The Screamers"
        ]
      },
      {
        "id": "Concert-3",
        "name": "Concert 3",
        "minAgeRestriction": 18,
        "startsAt": "2018-10-07T14:48:00.000Z",
        "performingBand": "The Jumpers"
      },
      {
        "id": "Conference-4",
        "name": "Conference 4",
        "minAgeRestriction": null,
        "startsAt": "2018-10-09T14:48:00.000Z",
        "speakers": [
          "The Storytellers"
        ],
        "workshops": [
          "Writing",
          "Reading"
        ]
      }
    ]
  }
}
```

결과는 단일 이벤트 컬렉션으로 반환되므로 공통 특성을 나타내는 데 인터페이스를 사용하면 결과를 정렬하는 데 매우 유용합니다.

## 공용 구조체 예시
<a name="unions"></a>

앞서 설명했듯이 공용 구조체는 공통 필드 집합을 정의하지 않습니다. 검색 결과에 여러 가지 다양한 형식이 나타날 수 있습니다. `Event` 스키마를 사용하면 `SearchResult` 공용 구조체를 다음과 같이 정의할 수 있습니다.

```
type Query {
    # Retrieve Events at a specific Venue
    findEventsAtVenue(venueId: ID!): [Event]
    # Search across all content
    search(query: String!): [SearchResult]
}

union SearchResult = Conference | Festival | Concert | Venue
```

이 경우 `SearchResult` 공용 구조체에 대한 필드를 쿼리하려면 조각을 사용해야 합니다.

```
query {
  search(query: "Madison") {
    ... on Venue {
      id
      name
      address
    }

    ... on Festival {
      id
      name
      performers
    }

    ... on Concert {
      id
      name
      performingBand
    }

    ... on Conference {
      speakers
      workshops
    }
  }
}
```

## AWS AppSync의 유형 해상도
<a name="type-resolution-in-appsynclong"></a>

형식 확인은 GraphQL 엔진이 확인된 값을 특정 객체 형식으로 식별하는 메커니즘입니다.

공용 구조체 검색의 예로 돌아가 보겠습니다. 쿼리 결과가 생성되면 결과 목록의 각 항목에는 `SearchResult` 공용 구조체에서 정의한 가능한 형식 중 하나(예: `Conference`, `Festival`, `Concert` 또는 `Venue`)로 자신이 표시되어 있어야 합니다.

`Festival`을 `Venue` 또는 `Conference`와 식별하는 로직은 애플리케이션 요구 사항을 따르기 때문에 GraphQL 엔진에 원시 결과로부터 가능한 형식을 식별하기 위한 힌트를 제공해야 합니다.

 AWS AppSync를 사용하면이 힌트는 이름이 인 메타 필드로 표현되며`__typename`,이 필드의 값은 식별된 객체 유형 이름에 해당합니다. `__typename`는 인터페이스 또는 조합인 반환 유형에 필요합니다.

## 형식 확인의 예
<a name="type-resolution-example"></a>

이전 스키마를 다시 사용하겠습니다. 콘솔로 이동해 **스키마** 페이지에서 다음을 추가하여 수행합니다.

```
schema {
    query: Query
}

type Query {
    # Retrieve Events at a specific Venue
    findEventsAtVenue(venueId: ID!): [Event]
    # Search across all content
    search(query: String!): [SearchResult]
}

union SearchResult = Conference | Festival | Concert | Venue

type Venue {
    id: ID!
    name: String!
    address: String
    maxOccupancy: Int
}

interface Event {
    id: ID!
    name: String!
    startsAt: String
    endsAt: String
    venue: Venue
    minAgeRestriction: Int
}

type Festival implements Event {
    id: ID!
    name: String!
    startsAt: String
    endsAt: String
    venue: Venue
    minAgeRestriction: Int
    performers: [String]
}

type Conference implements Event {
    id: ID!
    name: String!
    startsAt: String
    endsAt: String
    venue: Venue
    minAgeRestriction: Int
    speakers: [String]
    workshops: [String]
}

type Concert implements Event {
    id: ID!
    name: String!
    startsAt: String
    endsAt: String
    venue: Venue
    minAgeRestriction: Int
    performingBand: String
}
```

`Query.search` 필드에 해석기를 연결해 보십시오. `Resolvers` 섹션에서 **연결**을 선택하고 *없음* 형식의 새 **데이터 원본**을 만든 다음 이름을 *StubDataSource*로 지정합니다. 이 예에서는 외부 소스에서 결과를 가져와 요청 매핑 템플릿에서 가져온 결과를 하드코딩한다고 가정합니다.

요청 매핑 템플릿 창에서 다음을 입력합니다.

```
{
    "version" : "2018-05-29",
    "payload":
    ## We are effectively mocking our search results for this example
    [
        {
            "id": "Venue-1",
            "name": "Venue 1",
            "address": "2121 7th Ave, Seattle, WA 98121",
            "maxOccupancy": 1000
        },
        {
            "id": "Festival-2",
            "name": "Festival 2",
            "performers": ["The Singers", "The Screamers"]
        },
        {
            "id": "Concert-3",
            "name": "Concert 3",
            "performingBand": "The Jumpers"
        },
        {
            "id": "Conference-4",
            "name": "Conference 4",
            "speakers": ["The Storytellers"],
            "workshops": ["Writing", "Reading"]
        }
    ]
}
```

애플리케이션이 형식 이름을 `id` 필드의 일부로 반환하는 경우 형식 확인 로직은 `id` 필드를 구문 분석하여 형식 이름을 추출한 다음 `__typename` 필드를 각 결과에 추가해야 합니다. 다음과 같이 응답 매핑 템플릿에서 이러한 로직을 수행할 수 있습니다.

**참고**  
Lambda 데이터 원본을 사용하는 경우 Lambda 함수의 일부분으로 이 작업을 수행할 수 있습니다.

```
#foreach ($result in $context.result)
    ## Extract type name from the id field.
    #set( $typeName = $result.id.split("-")[0] )
    #set( $ignore = $result.put("__typename", $typeName))
#end
$util.toJson($context.result)
```

다음 쿼리를 실행합니다.

```
query {
  search(query: "Madison") {
    ... on Venue {
      id
      name
      address
    }

    ... on Festival {
        id
      name
      performers
    }

    ... on Concert {
      id
      name
      performingBand
    }

    ... on Conference {
      speakers
      workshops
    }
  }
}
```

위 쿼리는 다음과 같은 결과를 반환합니다.

```
{
  "data": {
    "search": [
      {
        "id": "Venue-1",
        "name": "Venue 1",
        "address": "2121 7th Ave, Seattle, WA 98121"
      },
      {
        "id": "Festival-2",
        "name": "Festival 2",
        "performers": [
          "The Singers",
          "The Screamers"
        ]
      },
      {
        "id": "Concert-3",
        "name": "Concert 3",
        "performingBand": "The Jumpers"
      },
      {
        "speakers": [
          "The Storytellers"
        ],
        "workshops": [
          "Writing",
          "Reading"
        ]
      }
    ]
  }
}
```

형식 확인 로직은 애플리케이션에 따라 다릅니다. 예를 들어, 특정 필드 또는 필드 조합이 있는지 검사하는 다른 식별 로직이 있을 수 있습니다. 즉, `Festival`을 식별하기 위해 `performers` 필드가 있는지 감지하거나 `Conference`를 식별하기 위해 `speakers` 및 `workshops` 필드의 조합이 있는지 감지할 수 있습니다. 궁극적으로 사용하려는 로직은 사용자가 정의하는 것입니다.