

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

# Interfacce e unioni in GraphQL
<a name="interfaces-and-unions"></a>

[Il sistema di tipo GraphQL supporta le interfacce.](https://graphql.org/learn/schema/#interfaces) Un'interfaccia espone un determinato set di campi che deve essere incluso in un tipo per implementare l'interfaccia. 

[Il sistema di tipo GraphQL supporta anche Unions.](https://graphql.org/learn/schema/#union-types) Le unioni sono identiche alle interfacce, ad eccezione del fatto che non definiscono un set comune di campi. Le unioni sono in genere preferibili rispetto alle interfacce quando i tipi possibili non condividono una gerarchia logica.

La sezione seguente è un riferimento per la digitazione dello schema.

## Esempi di interfacce
<a name="interfaces"></a>

Potremmo rappresentare un'`Event`interfaccia che rappresenta qualsiasi tipo di attività o incontro di persone. Alcuni tipi di eventi possibili sono `Concert``Conference`, e`Festival`. Questi tipi condividono tutti caratteristiche comuni, in quanto hanno tutti un nome, un luogo in cui avviene l'evento e una data di inizio e una di fine. Anche questi tipi presentano delle differenze; a `Conference` offre un elenco di relatori e workshop, mentre a `Concert` presenta una band che si esibisce.

In Schema Definition Language (SDL), l'`Event`interfaccia è definita come segue:

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

E ciascuno dei tipi implementa l'`Event`interfaccia come segue:

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

Le interfacce sono utili per rappresentare elementi che possono essere di diversi tipi. Ad esempio, possiamo cercare tutti gli eventi che avvengono in un luogo specifico. Aggiungiamo un campo `findEventsByVenue` allo schema come segue:

```
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`Restituisce un elenco di. `Event` Poiché i campi dell'interfaccia GraphQL sono comuni a tutti i tipi di implementazione, è possibile selezionare qualsiasi campo nell'interfaccia `Event` (`id`, `name`, `startsAt`, `endsAt`, `venue` e `minAgeRestriction`). Inoltre, puoi accedere ai campi in qualsiasi tipo di implementazione utilizzando [frammenti](https://graphql.org/learn/queries/#fragments) GraphQL, purché specifichi il tipo.

Esaminiamo un esempio di query GraphQL che utilizza l'interfaccia.

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

    ... on Festival {
      performers
    }

    ... on Concert {
      performingBand
    }

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

La query precedente produce un singolo elenco di risultati e il server può, per impostazione predefinita, ordinare gli eventi in base alla data di inizio.

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

Poiché i risultati vengono restituiti come una singola raccolta di eventi, l'utilizzo di interfacce per rappresentare caratteristiche comuni è molto utile per l'ordinamento dei risultati.

## Esempi di unione
<a name="unions"></a>

Come affermato in precedenza, i sindacati non definiscono insiemi di campi comuni. Un risultato di ricerca potrebbe rappresentare molti tipi diversi. Utilizzando lo schema `Event`, è possibile definire un'unione `SearchResult` come segue:

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

In questo caso, per interrogare qualsiasi campo sulla nostra `SearchResult` unione, devi usare i frammenti:

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

    ... on Festival {
      id
      name
      performers
    }

    ... on Concert {
      id
      name
      performingBand
    }

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

## Digita la risoluzione in AWS AppSync
<a name="type-resolution-in-appsynclong"></a>

La risoluzione dei tipi è il meccanismo attraverso il quale il motore GraphQL identifica un valore risolto come tipo di oggetto specifico.

Tornando all'esempio della ricerca sindacale, a condizione che la nostra query abbia prodotto risultati, ogni elemento nell'elenco dei risultati deve presentarsi come uno dei possibili tipi definiti dall'`SearchResult`unione (ovvero,, `Conference` `Festival``Concert`, o`Venue`).

Poiché la logica per identificare un tipo `Festival` rispetto a un tipo `Venue` o `Conference` dipende dai requisiti dell'applicazione, il motore GraphQL deve ricevere un suggerimento per identificare i possibili tipi dai risultati non elaborati.

Con AWS AppSync, questo suggerimento è rappresentato da un metacampo denominato`__typename`, il cui valore corrisponde al nome del tipo di oggetto identificato. `__typename`è obbligatorio per i tipi restituiti che sono interfacce o unioni.

## Esempio di risoluzione dei tipi
<a name="type-resolution-example"></a>

Ora, riutilizzeremo lo schema precedente. Puoi continuare passando alla console e aggiungendo il codice seguente nella pagina **Schema**:

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

Colleghiamo un resolver al campo `Query.search`. Nella `Resolvers` sezione, scegliete **Allega**, create una nuova **origine dati** di tipo *NONE*, quindi assegnatele un nome *StubDataSource*. Ai fini di questo esempio, fingeremo di aver recuperato i risultati da un'origine esterna e di aver codificato tali risultati nel modello di mappatura della richiesta.

Nel riquadro del modello di mappatura della richiesta immetti i seguenti dati:

```
{
    "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 l'applicazione restituisce il nome del tipo come parte del `id` campo, la logica di risoluzione dei tipi deve analizzare il `id` campo per estrarre il nome del tipo e quindi aggiungere il `__typename` campo a ciascuno dei risultati. È possibile eseguire la logica nel modello di mappatura della risposta come segue:

**Nota**  
Puoi eseguire questa attività anche come parte della tua funzione Lambda, se utilizzi l'origine dati 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)
```

Eseguire la seguente query:

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

    ... on Festival {
        id
      name
      performers
    }

    ... on Concert {
      id
      name
      performingBand
    }

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

La query restituisce i seguenti risultati:

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

La logica di risoluzione dei tipi varia a seconda dell'applicazione. Ad esempio, puoi definire una logica di identificazione diversa che controlla l'esistenza di determinati campi o addirittura una combinazione di campi. Ovvero, puoi rilevare la presenza del campo `performers` per identificare un tipo `Festival` o la combinazione dei campi `speakers` e `workshops` per identificare un tipo `Conference`. In definitiva, sta a te definire la logica che desideri utilizzare.