

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

# Interfaces e uniões no GraphQL
<a name="interfaces-and-unions"></a>

O sistema do tipo GraphQL oferece suporte a [interfaces](https://graphql.org/learn/schema/#interfaces). Uma interface expõe um determinado conjunto de campos que um tipo deve incluir para implementar a interface. 

O sistema de tipos GraphQL também oferece suporte a [Uniões](https://graphql.org/learn/schema/#union-types). As uniões são idênticas às interfaces, exceto que não definem um conjunto comum de campos. As uniões geralmente são preferidas em relação às interfaces quando os tipos possíveis não compartilham uma hierarquia lógica.

A seção a seguir é uma referência para digitação de esquema.

## Exemplos de interface
<a name="interfaces"></a>

Podemos representar uma interface `Event` que representa qualquer tipo de atividade ou reunião de pessoas. Alguns tipos de eventos possíveis são `Concert`, `Conference` e `Festival`. Esses tipos possuem características em comum, incluindo um nome, um local onde o evento está acontecendo e datas de início e término. Esses tipos também têm diferenças, uma `Conference` oferece uma lista de palestrantes e seminários enquanto um `Concert` contém uma banda em apresentação.

No SDL (Schema Definition Language), a interface `Event` é definida da seguinte forma:

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

E cada um dos tipos implementa a interface `Event` da seguinte forma:

```
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]
}
```

As interfaces são úteis para representar elementos que podem ser de vários tipos. Por exemplo, podemos pesquisar todos os eventos que acontecem em um local específico. Vamos adicionar um campo `findEventsByVenue` ao esquema da seguinte forma:

```
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]
}
```

O `findEventsByVenue` retorna uma lista de `Event`. Como os campos da interface do GraphQL são comuns a todos os tipos de implementação, é possível selecionar qualquer campo na interface `Event` (`id`, `name`, `startsAt`, `endsAt`, `venue` e `minAgeRestriction`). Além disso, é possível acessar os campos em qualquer tipo de implementação usando [fragmentos](https://graphql.org/learn/queries/#fragments) do GraphQL, desde que o tipo seja especificado.

Vamos examinar um exemplo de uma consulta do GraphQL que usa a interface.

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

    ... on Festival {
      performers
    }

    ... on Concert {
      performingBand
    }

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

A consulta anterior produz uma única lista de resultados e o servidor pode, por padrão, classificar os eventos por data de início.

```
{
  "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"
        ]
      }
    ]
  }
}
```

Como os resultados são retornados como uma única coleção de eventos, o uso de interfaces para representar características comuns é muito útil para classificar os resultados.

## Exemplos de uniões
<a name="unions"></a>

Conforme mencionado anteriormente, as uniões não definem conjuntos comuns de campos. Um resultado de pesquisa pode representar muitos tipos diferentes. Usando o esquema `Event`, defina uma união `SearchResult` da seguinte forma:

```
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
```

Neste caso, para consultar qualquer campo na nossa união `SearchResult`, deve-se usar fragmentos.

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

    ... on Festival {
      id
      name
      performers
    }

    ... on Concert {
      id
      name
      performingBand
    }

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

## Resolução de texto em AWS AppSync
<a name="type-resolution-in-appsynclong"></a>

A resolução de tipo é o mecanismo pelo qual o mecanismo do GraphQL identifica um valor resolvido como um tipo de objeto específico.

Voltando ao exemplo de pesquisa da união, assumindo que a consulta gerou resultados, cada item na lista de resultados deve se apresentar como um dos tipos possíveis definidos pela união `SearchResult` (isto é, `Conference`, `Festival`, `Concert` ou `Venue`).

Como a lógica para identificar um `Festival` de uma `Venue` ou uma `Conference` depende dos requisitos do aplicativo, o mecanismo do GraphQL deve receber uma dica para identificar os tipos possíveis nos resultados brutos.

Com AWS AppSync, essa dica é representada por um metacampo chamado`__typename`, cujo valor corresponde ao nome do tipo de objeto identificado. `__typename`é necessário para tipos de retorno que sejam interfaces ou uniões.

## Exemplo de resolução de tipo
<a name="type-resolution-example"></a>

Vamos reutilizar o esquema anterior. Você pode acompanhar navegando até o console e adicionando o seguinte na página **Esquema**:

```
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
}
```

Vamos anexar um resolvedor ao campo `Query.search`. Na `Resolvers` seção, escolha **Anexar**, crie uma nova **fonte de dados** do tipo *NENHUMA* e, em seguida, nomeie-a *StubDataSource*. Para esse exemplo, vamos imaginar que os resultados foram obtidos de uma fonte externa e codificar os resultados no modelo de mapeamento da solicitação.

No painel do modelo de mapeamento da solicitação, insira o seguinte:

```
{
    "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"]
        }
    ]
}
```

Se o aplicativo retornar o nome do tipo como parte do campo`id`, a lógica de resolução de tipo deverá analisar o campo `id` para extrair o nome do tipo e, em seguida, adicionar o campo `__typename` a cada um dos resultados. Você pode executar essa lógica no modelo de mapeamento da resposta da seguinte forma:

**nota**  
Observação: também é possível executar essa tarefa como parte da função do Lambda se você estiver usando a fonte de dados do 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)
```

Execute a seguinte consulta:

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

    ... on Festival {
        id
      name
      performers
    }

    ... on Concert {
      id
      name
      performingBand
    }

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

A consulta gera os seguintes resultados:

```
{
  "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"
        ]
      }
    ]
  }
}
```

A lógica da resolução de tipo varia dependendo do aplicativo. Por exemplo, você pode ter uma lógica de identificação diferente que verifica a existência de determinados campos ou até mesmo uma combinação de campos. Ou seja, é possível detectar a presença do campo `performers` para identificar um `Festival` ou a combinação dos `speakers` e dos campos `workshops` para identificar uma `Conference`. De forma geral, cabe a você definir a lógica que deseja usar.