

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à.

# Schemi GraphQL
<a name="schema-components"></a>

Lo schema GraphQL è alla base di un'API GraphQL. Serve come modello che definisce la forma dei dati. È anche un contratto tra il client e il server che definisce come i dati verranno recuperati and/or e modificati.

Gli schemi GraphQL sono scritti nello *Schema Definition Language* (SDL). SDL è composto da tipi e campi con una struttura consolidata:
+ **Tipi**: I tipi sono il modo in cui GraphQL definisce la forma e il comportamento dei dati. GraphQL supporta una moltitudine di tipi che verranno spiegati più avanti in questa sezione. Ogni tipo definito nello schema conterrà il proprio ambito. All'interno dell'ambito ci saranno uno o più campi che possono contenere un valore o una logica che verrà utilizzata nel servizio GraphQL. I tipi ricoprono molti ruoli diversi, i più comuni sono gli oggetti o gli scalari (tipi di valori primitivi).
+ **Campi**: i campi esistono nell'ambito di un tipo e contengono il valore richiesto dal servizio GraphQL. Sono molto simili alle variabili di altri linguaggi di programmazione. La forma dei dati definiti nei campi determinerà il modo in cui i dati sono strutturati in un' request/response operazione. Ciò consente agli sviluppatori di prevedere cosa verrà restituito senza sapere come viene implementato il backend del servizio.

Per visualizzare l'aspetto di uno schema, esaminiamo il contenuto di un semplice schema GraphQL. Nel codice di produzione, lo schema si trova in genere in un file chiamato `schema.graphql` o. `schema.json` Supponiamo che stiamo esaminando un progetto che implementa un servizio GraphQL. Questo progetto archivia i dati del personale dell'azienda e il `schema.graphql` file viene utilizzato per recuperare i dati sul personale e aggiungere nuovo personale a un database. Il codice potrebbe essere simile al seguente:

------
#### [ schema.graphql ]

```
type Person {                                  
   id: ID!
   name: String                                  
   age: Int
}
type Query {                                   
  people: [Person]
}
type Mutation {
  addPerson(id: ID!, name: String, age: Int): Person
}
```

------

Possiamo vedere che ci sono tre tipi definiti nello schema:`Person`,`Query`, e`Mutation`. Guardando`Person`, possiamo immaginare che questo sia il modello per un esempio di un dipendente dell'azienda, il che renderebbe questo tipo un oggetto. All'interno del suo ambito `id``name`, vediamo e`age`. Questi sono i campi che definiscono le proprietà di a`Person`. Ciò significa che la nostra fonte `Person` di dati memorizza ciascuno `name` come tipo `String` scalare (primitivo) e `age` come tipo `Int` scalare (primitivo). `id`Funziona come un identificatore speciale e univoco per ciascuno. `Person` È anche un valore obbligatorio, come indicato dal `!` simbolo.

I due tipi di oggetti successivi si comportano in modo diverso. GraphQL riserva alcune parole chiave per tipi di oggetti speciali che definiscono il modo in cui i dati verranno popolati nello schema. Un `Query` tipo recupererà i dati dalla fonte. Nel nostro esempio, la nostra query potrebbe recuperare `Person` oggetti da un database. Questo potrebbe ricordarvi le `GET` operazioni RESTful terminologiche. A `Mutation` modificherà i dati. Nel nostro esempio, la nostra mutazione può aggiungere altri `Person` oggetti al database. Questo potrebbe ricordarti di operazioni che cambiano lo stato come o`PUT`. `POST` I comportamenti di tutti i tipi di oggetti speciali verranno spiegati più avanti in questa sezione.

Supponiamo che `Query` nel nostro esempio recuperi qualcosa dal database. Se osserviamo i campi di`Query`, vediamo un campo chiamato`people`. Il suo valore di campo è`[Person]`. Ciò significa che vogliamo recuperare alcune istanze `Person` del database. Tuttavia, l'aggiunta di parentesi indica che vogliamo restituire un elenco di tutte le `Person` istanze e non solo uno specifico.

Il `Mutation` tipo è responsabile dell'esecuzione di operazioni di modifica dello stato come la modifica dei dati. Una mutazione è responsabile dell'esecuzione di alcune operazioni di modifica dello stato sulla fonte di dati. Nel nostro esempio, la nostra mutazione contiene un'operazione chiamata `addPerson` che aggiunge un nuovo `Person` oggetto al database. La mutazione utilizza a `Person` e prevede un input per i campi `id``name`, e. `age`

A questo punto, forse vi starete chiedendo come `addPerson` funzionano operazioni come quelle senza un'implementazione di codice, dato che presumibilmente esegue un certo comportamento e assomiglia molto a una funzione con un nome di funzione e parametri. Attualmente non funzionerà perché uno schema funge solo da dichiarazione. Per implementare il comportamento di`addPerson`, dovremmo aggiungervi un resolver. Un resolver è un'unità di codice che viene eseguita ogni volta che viene chiamato il campo associato (in questo caso, l'`addPerson`operazione). Se desideri utilizzare un'operazione, a un certo punto dovrai aggiungere l'implementazione del resolver. In un certo senso, puoi pensare all'operazione dello schema come alla dichiarazione di funzione e al resolver come alla definizione. I resolver verranno spiegati in una sezione diversa.

Questo esempio mostra solo i modi più semplici in cui uno schema può manipolare i dati. Puoi creare applicazioni complesse, robuste e scalabili sfruttando le funzionalità di GraphQL e. AWS AppSync Nella prossima sezione, definiremo tutti i diversi tipi e comportamenti sul campo che puoi utilizzare nel tuo schema.

# Tipi GraphQL
<a name="graphql-types"></a>

GraphQL supporta molti tipi diversi. Come hai visto nella sezione precedente, i tipi definiscono la forma o il comportamento dei dati. Sono gli elementi costitutivi fondamentali di uno schema GraphQL. 

I tipi possono essere classificati in input e output. Gli input sono tipi che possono essere passati come argomento per i tipi di oggetti speciali (`Query`,, ecc.)`Mutation`, mentre i tipi di output vengono utilizzati strettamente per archiviare e restituire dati. Di seguito è riportato un elenco di tipi e delle relative categorizzazioni:
+ **Oggetti**: un oggetto contiene campi che descrivono un'entità. Ad esempio, un oggetto potrebbe essere qualcosa come un oggetto `book` con campi che ne descrivono le caratteristiche come `authorName``publishingYear`, ecc. Sono strettamente tipi di output.
+ **Scalari**: sono tipi primitivi come int, string, ecc. In genere vengono assegnati ai campi. Usando il `authorName` campo come esempio, potrebbe essere assegnato lo `String` scalare per memorizzare un nome come «John Smith». Gli scalari possono essere sia di tipo di input che di output.
+ **Ingressi**: gli input consentono di passare un gruppo di campi come argomento. Sono strutturati in modo molto simile agli oggetti, ma possono essere passati come argomenti a oggetti speciali. Gli input consentono di definire scalari, enumerazioni e altri input nel relativo ambito. Gli input possono essere solo tipi di input.
+ **Oggetti speciali**: gli oggetti speciali eseguono operazioni di modifica dello stato e svolgono la maggior parte del lavoro pesante del servizio. Esistono tre tipi di oggetti speciali: interrogazione, mutazione e sottoscrizione. Le query in genere recuperano i dati; le mutazioni manipolano i dati; le sottoscrizioni si aprono e mantengono una connessione bidirezionale tra client e server per una comunicazione costante. Gli oggetti speciali non vengono né input né output date le loro funzionalità.
+ Enumerazioni: **le enumerazioni** sono elenchi predefiniti di valori legali. Se chiami un enum, i suoi valori possono essere solo quelli definiti nel suo ambito. Ad esempio, se aveste un enum chiamato che `trafficLights` rappresenta un elenco di segnali stradali, potrebbe avere valori come `redLight` e `greenLight` ma no. `purpleLight` Un vero semaforo avrà solo un certo numero di segnali, quindi puoi usare l'enum per definirli e forzarli a essere gli unici valori legali durante il riferimento. `trafficLight` Gli enum possono essere sia di tipo di input che di output.
+ **Unioni/interfacce**: le unioni consentono di restituire uno o più elementi in una richiesta a seconda dei dati richiesti dal client. Ad esempio, se si dispone `Book` di un tipo con un `title` campo e un `Author` tipo con un `name` campo, è possibile creare un'unione tra entrambi i tipi. *Se il cliente volesse cercare in un database la frase «Giulio Cesare», il sindacato potrebbe restituire *Giulio Cesare* (l'opera di William Shakespeare) tratto da `Book` `title` e *Giulio Cesare* (l'autore di Commentarii de Bello Gallico) dal.* `Author` `name` Le unioni possono essere solo tipi di output.

  Le interfacce sono insiemi di campi che gli oggetti devono implementare. È un po' simile alle interfacce nei linguaggi di programmazione come Java, in cui è necessario implementare i campi definiti nell'interfaccia. Ad esempio, supponiamo che tu abbia creato un'interfaccia chiamata `Book` che contenesse un `title` campo. Supponiamo che in seguito tu `Novel` abbia creato un tipo chiamato implementato`Book`. `Novel`Dovresti includere un `title` campo. Tuttavia, `Novel` potresti includere anche altri campi non presenti nell'interfaccia come `pageCount` o`ISBN`. Le interfacce possono essere solo tipi di output.

Le sezioni seguenti spiegheranno come funziona ogni tipo in GraphQL.

## Oggetti
<a name="object-components"></a>

Gli oggetti GraphQL sono il tipo principale che vedrai nel codice di produzione. In GraphQL, puoi pensare a un oggetto come a un raggruppamento di campi diversi (simili alle variabili in altri linguaggi), con ogni campo definito da un tipo (tipicamente uno scalare o un altro oggetto) che può contenere un valore. Gli oggetti rappresentano un'unità di dati che può retrieved/manipulated provenire dall'implementazione del servizio.

I tipi di oggetti vengono dichiarati utilizzando la `Type` parola chiave. Modifichiamo leggermente il nostro esempio di schema:

```
type Person {
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}
```

I tipi di oggetti qui sono `Person` e`Occupation`. Ogni oggetto ha i propri campi con i propri tipi. Una caratteristica di GraphQL è la possibilità di impostare campi su altri tipi. Puoi vedere che il `occupation` campo `Person` contiene un tipo di `Occupation` oggetto. Possiamo fare questa associazione perché GraphQL descrive solo i dati e non l'implementazione del servizio.

## Scalari
<a name="scalar-components"></a>

Gli scalari sono essenzialmente tipi primitivi che contengono valori. Nel AWS AppSync, esistono due tipi di scalari: gli scalari e gli AWS AppSync scalari GraphQL predefiniti. Gli scalari vengono in genere utilizzati per memorizzare i valori dei campi all'interno dei tipi di oggetti. I tipi GraphQL predefiniti includono`Int`,`Float`, `String``Boolean`, e. `ID` Usiamo nuovamente l'esempio precedente:

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}
```

Individuando i `title` campi `name` e, entrambi contengono uno `String` scalare. `Name`potrebbe restituire un valore di stringa come "`John Smith`" e il titolo potrebbe restituire qualcosa come "»`firefighter`. Alcune implementazioni GraphQL supportano anche scalari personalizzati che utilizzano la `Scalar` parola chiave e implementano il comportamento del tipo. Tuttavia, AWS AppSync attualmente **non supporta** scalari personalizzati. Per un elenco di scalari, vedi Tipi [scalari](https://docs.aws.amazon.com//appsync/latest/devguide/scalars.html) in. AWS AppSync

## Input
<a name="input-components"></a>

A causa del concetto di tipi di input e output, esistono alcune restrizioni quando si passano argomenti. I tipi che di solito devono essere passati, in particolare gli oggetti, sono limitati. È possibile utilizzare il tipo di input per aggirare questa regola. Gli input sono tipi che contengono scalari, enumerazioni e altri tipi di input.

Gli input sono definiti utilizzando la parola chiave: `input`

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}

input personInput { 
  id: ID!
  name: String
  age: Int
  occupation: occupationInput
}

input occupationInput {
  title: String
}
```

Come puoi vedere, possiamo avere input separati che imitano il tipo originale. Questi input verranno spesso utilizzati nelle operazioni sul campo in questo modo:

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}

input occupationInput {
  title: String
}

type Mutation {
  addPerson(id: ID!, name: String, age: Int, occupation: occupationInput): Person
}
```

Nota come stiamo ancora passando `occupationInput` al posto di `Occupation` creare un`Person`. 

Questo è solo uno scenario per gli input. Non hanno necessariamente bisogno di copiare gli oggetti in scala 1:1e, nel codice di produzione, molto probabilmente non lo userete in questo modo. È buona norma sfruttare gli schemi GraphQL definendo solo ciò che è necessario inserire come argomenti.

Inoltre, gli stessi input possono essere utilizzati in più operazioni, ma non è consigliabile farlo. Ogni operazione dovrebbe idealmente contenere una propria copia unica degli input nel caso in cui i requisiti dello schema cambino.

## Oggetti speciali
<a name="special-object-components"></a>

GraphQL riserva alcune parole chiave per oggetti speciali che definiscono alcune delle logiche aziendali relative al modo in cui lo schema utilizzerà retrieve/manipulate i dati. Al massimo, può esserci una di queste parole chiave in uno schema. Fungono da punti di ingresso per tutti i dati richiesti che i tuoi clienti eseguono sul tuo servizio GraphQL. 

Gli oggetti speciali vengono definiti anche utilizzando la `type` parola chiave. Sebbene vengano utilizzati in modo diverso dai normali tipi di oggetti, la loro implementazione è molto simile.

------
#### [ Queries ]

Le query sono molto simili alle `GET` operazioni in quanto eseguono un recupero di sola lettura per ottenere dati dalla fonte. In GraphQL, `Query` definisce tutti i punti di ingresso per i client che effettuano richieste verso il tuo server. Ci sarà sempre un'implementazione GraphQL `Query` nella tua implementazione GraphQL.

Ecco i `Query` tipi di oggetti modificati che abbiamo usato nel nostro precedente esempio di schema:

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}
type Occupation {
  title: String
}
type Query {                                   
  people: [Person]
}
```

Il nostro `Query` contiene un campo chiamato `people` che restituisce un elenco di `Person` istanze dalla fonte di dati. Supponiamo di dover modificare il comportamento della nostra applicazione e ora dobbiamo restituire un elenco delle sole `Occupation` istanze per uno scopo separato. Potremmo semplicemente aggiungerlo alla query:

```
type Query {                                   
  people: [Person]
  occupations: [Occupation]
}
```

In GraphQL, possiamo trattare la nostra query come l'unica fonte di richieste. Come puoi vedere, questo è potenzialmente molto più semplice RESTful delle implementazioni che potrebbero utilizzare endpoint diversi per ottenere lo stesso risultato (e). `.../api/1/people` `.../api/1/occupations`

Supponendo di avere un'implementazione del resolver per questa query, ora possiamo eseguire una query vera e propria. Sebbene il `Query` tipo esista, dobbiamo chiamarlo esplicitamente affinché venga eseguito nel codice dell'applicazione. Questo può essere fatto usando la `query` parola chiave:

```
query getItems {
   people {
      name
   }
   occupations {
      title
   }
}
```

Come puoi vedere, questa query viene chiamata `getItems` e restituisce `people` (un elenco di `Person` oggetti) e `occupations` (un elenco di `Occupation` oggetti). Nel`people`, stiamo restituendo solo il `name` campo di ciascuno`Person`, mentre stiamo restituendo il `title` campo di ciascuno`Occupation`. La risposta potrebbe essere simile a questa:

```
{
  "data": {
    "people": [
      {
        "name": "John Smith"
      },
      {
        "name": "Andrew Miller"
      },
      .
      .
      .
    ],
    "occupations": [
      {
        "title": "Firefighter"
      },
      {
        "title": "Bookkeeper"
      },
      .
      .
      .
    ]
  }
}
```

La risposta di esempio mostra come i dati seguono la forma della query. Ogni voce recuperata viene elencata nell'ambito del campo. `people`e `occupations` stanno restituendo le cose come elenchi separati. Sebbene utile, potrebbe essere più comodo modificare la query per restituire un elenco di nomi e occupazioni delle persone:

```
query getItems {
   people {
      name   
      occupation {
        title
      }
}
```

Questa è una modifica legale perché il nostro `Person` tipo contiene un `occupation` campo di tipo`Occupation`. Se elencati nell'ambito di`people`, restituiamo ciascuno `Person` di essi `name` insieme a quello associato `Occupation` da`title`. La risposta potrebbe essere simile a questa:

```
}
  "data": {
    "people": [
      {
        "name": "John Smith",
        "occupation": {
          "title": "Firefighter"
        }
      },
      {
        "name": "Andrew Miller",
        "occupation": {
          "title": "Bookkeeper"
        }
      },
      .
      .
      .
    ]
  }
}
```

------
#### [ Mutations ]

Le mutazioni sono simili a operazioni che cambiano lo stato come o`PUT`. `POST` Eseguono un'operazione di scrittura per modificare i dati nell'origine, quindi recuperano la risposta. Definiscono i punti di ingresso per le richieste di modifica dei dati. A differenza delle query, una mutazione può essere inclusa o meno nello schema a seconda delle esigenze del progetto. Ecco la mutazione dall'esempio dello schema:

```
type Mutation {
  addPerson(id: ID!, name: String, age: Int): Person
}
```

Il `addPerson` campo rappresenta un punto di ingresso che aggiunge un `Person` all'origine dati. `addPerson`è il nome del campo;`id`,`name`, e `age` sono i parametri; ed `Person` è il tipo restituito. Guardando indietro al `Person` tipo:

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}
```

Abbiamo aggiunto il `occupation` campo. Tuttavia, non possiamo impostare questo campo su `Occupation` direttamente perché gli oggetti non possono essere passati come argomenti; sono strettamente tipi di output. Dovremmo invece passare un input con gli stessi campi di un argomento:

```
input occupationInput {
  title: String
}
```

 Possiamo anche aggiornare facilmente il nostro `addPerson` per includerlo come parametro quando creiamo nuove `Person` istanze:

```
type Mutation {
  addPerson(id: ID!, name: String, age: Int, occupation: occupationInput): Person
}
```

Ecco lo schema aggiornato:

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}

input occupationInput {
  title: String
}

type Mutation {
  addPerson(id: ID!, name: String, age: Int, occupation: occupationInput): Person
}
```

Nota che `occupation` passerà nel `title` campo da `occupationInput` per completare la creazione dell'oggetto `Person` anziché dell'`Occupation`oggetto originale. Supponendo di avere un'implementazione del resolver per`addPerson`, ora possiamo eseguire una mutazione effettiva. Sebbene il `Mutation` tipo esista, dobbiamo chiamarlo esplicitamente affinché venga eseguito nel codice dell'applicazione. Questo può essere fatto usando la `mutation` parola chiave:

```
mutation createPerson {
  addPerson(id: ID!, name: String, age: Int, occupation: occupationInput) {
    name
    age
    occupation {
      title
    }
  }
}
```

Questa mutazione si chiama`createPerson`, ed `addPerson` è l'operazione. Per crearne una nuova`Person`, possiamo inserire gli argomenti per`id`, `name``age`, e`occupation`. Nell'ambito di`addPerson`, possiamo vedere anche altri campi come `name``age`, ecc. Questa è la tua risposta; questi sono i campi che verranno restituiti al termine dell'`addPerson`operazione. Ecco la parte finale dell'esempio:

```
mutation createPerson {
  addPerson(id: "1", name: "Steve Powers", age: "50", occupation: "Miner") {
    id
    name
    age
    occupation {
      title
    }
  }
}
```

Utilizzando questa mutazione, un risultato potrebbe essere simile al seguente:

```
{
  "data": {
    "addPerson": {
      "id": "1",
      "name": "Steve Powers",
      "age": "50",
      "occupation": {
        "title": "Miner"
      }
    }
  }
}
```

Come puoi vedere, la risposta ha restituito i valori richiesti nello stesso formato definito nella nostra mutazione. È buona norma restituire tutti i valori che sono stati modificati per ridurre la confusione e la necessità di ulteriori query in futuro. Le mutazioni consentono di includere più operazioni nel suo ambito. Verranno eseguite in sequenza nell'ordine indicato nella mutazione. Ad esempio, se creiamo un'altra operazione chiamata `addOccupation` che aggiunge titoli di lavoro all'origine dati, possiamo richiamarla nella mutazione successiva. `addPerson` `addPerson`verrà gestito per primo seguito da. `addOccupation`

------
#### [ Subscriptions ]

Gli abbonamenti vengono utilizzati [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications)per aprire una connessione bidirezionale duratura tra il server e i suoi client. In genere, un client si iscrive o ascolta il server. Ogni volta che il server apporta una modifica sul lato server o esegue un evento, il client sottoscritto riceverà gli aggiornamenti. Questo tipo di protocollo è utile quando sono sottoscritti più client e devono essere avvisati delle modifiche che avvengono nel server o in altri client. Ad esempio, gli abbonamenti possono essere utilizzati per aggiornare i feed dei social media. Potrebbero esserci due utenti, l'utente A e l'utente B, entrambi abbonati agli aggiornamenti automatici delle notifiche ogni volta che ricevono messaggi diretti. L'utente A sul client A potrebbe inviare un messaggio diretto all'utente B sul client B. Il client dell'utente A invierebbe il messaggio diretto, che verrebbe elaborato dal server. Il server invierebbe quindi il messaggio diretto all'account dell'utente B inviando una notifica automatica al client B.

Ecco un esempio di a `Subscription` che potremmo aggiungere all'esempio dello schema:

```
type Subscription {                                   
  personAdded: Person
}
```

Il `personAdded` campo invierà un messaggio ai clienti abbonati ogni volta che ne `Person` viene aggiunto uno nuovo alla fonte di dati. Supponendo di avere un'implementazione del resolver per`personAdded`, ora possiamo usare l'abbonamento. Sebbene il `Subscription` tipo esista, dobbiamo chiamarlo esplicitamente affinché venga eseguito nel codice dell'applicazione. Questo può essere fatto usando la `subscription` parola chiave:

```
subscription personAddedOperation {
  personAdded {
    id
    name
  }
}
```

L'abbonamento viene chiamato `personAddedOperation` e l'operazione è`personAdded`. `personAdded`restituirà i `name` campi `id` e delle nuove `Person` istanze. Guardando l'esempio di mutazione, abbiamo aggiunto un'operazione che `Person` utilizza questa:

```
addPerson(id: "1", name: "Steve Powers", age: "50", occupation: "Miner")
```

Se i nostri clienti erano abbonati agli aggiornamenti di quelli appena aggiunti`Person`, potrebbero vederlo dopo l'`addPerson`esecuzione:

```
{
  "data": {
    "personAdded": {
      "id": "1",
      "name": "Steve Powers"
    }
  }
}
```

Di seguito è riportato un riepilogo di ciò che offrono gli abbonamenti:

Gli abbonamenti sono canali bidirezionali che consentono al client e al server di ricevere aggiornamenti rapidi ma costanti. In genere utilizzano il WebSocket protocollo, che crea connessioni standardizzate e sicure.

Gli abbonamenti sono agili in quanto riducono il sovraccarico di configurazione della connessione. Una volta sottoscritto, un cliente può continuare a utilizzare tale abbonamento per lunghi periodi di tempo. In genere utilizzano le risorse informatiche in modo efficiente, consentendo agli sviluppatori di personalizzare la durata dell'abbonamento e di configurare le informazioni richieste.

In generale, gli abbonamenti consentono al cliente di effettuare più abbonamenti contemporaneamente. Per quanto riguarda AWS AppSync, gli abbonamenti vengono utilizzati solo per ricevere aggiornamenti in tempo reale dal servizio. AWS AppSync Non possono essere utilizzati per eseguire interrogazioni o mutazioni.

L'alternativa principale agli abbonamenti è il polling, che invia interrogazioni a intervalli prestabiliti per richiedere dati. Questo processo è in genere meno efficiente degli abbonamenti e mette a dura prova sia il client che il backend.

------

Una cosa che non è stata menzionata nel nostro esempio di schema è il fatto che anche i tipi di oggetti speciali devono essere definiti in una `schema` radice. Quindi, quando esporti uno schema in AWS AppSync, potrebbe assomigliare a questo:

------
#### [ schema.graphql ]

```
schema {
  query: Query
  mutation: Mutation
  subscription: Subscription
}

.
.
.

type Query {                                   
  # code goes here
}
type Mutation {                                   
  # code goes here
}
type Subscription {                                   
  # code goes here
}
```

------

## Enumerazioni
<a name="enum-components"></a>

Le enumerazioni, o enumerazioni, sono scalari speciali che limitano gli argomenti legali di un tipo o di un campo. Ciò significa che ogni volta che un enum viene definito nello schema, il tipo o il campo associato sarà limitato ai valori nell'enum. Gli enum sono serializzati come stringhe scalari. Nota che diversi linguaggi di programmazione possono gestire le enumerazioni GraphQL in modo diverso. Ad esempio, non JavaScript ha un supporto enum nativo, quindi i valori enum possono essere mappati invece su valori int.

Le enumerazioni vengono definite utilizzando la parola chiave. `enum` Ecco un esempio:

```
enum trafficSignals {
  solidRed
  solidYellow
  solidGreen
  greenArrowLeft
  ...
}
```

Quando si chiama l'`trafficLights`enum, gli argomenti possono essere solo`solidRed`, `solidYellow``solidGreen`, ecc. È comune usare le enumerazioni per rappresentare cose che hanno un numero distinto ma limitato di scelte.

## Unioni/interfacce
<a name="union-interface-components"></a>

Vedi [Interfacce e unioni in GraphQL](https://docs.aws.amazon.com/appsync/latest/devguide/interfaces-and-unions.html).

# Campi GraphQL
<a name="graphql-fields"></a>

I campi rientrano nell'ambito di un tipo e contengono il valore richiesto dal servizio GraphQL. Sono molto simili alle variabili di altri linguaggi di programmazione. Ad esempio, ecco un tipo di `Person` oggetto:

```
type Person {                                  
   name: String                                  
   age: Int
}
```

I campi in questo caso sono `name` e `age` e contengono rispettivamente un `String` e un `Int` valore. I campi oggetto come quelli mostrati sopra possono essere usati come input nei campi (operazioni) delle query e delle mutazioni. Ad esempio, vedi quanto segue: `Query`

```
type Query {                                   
  people: [Person]
}
```

Il `people` campo richiede tutte le istanze di `Person` dalla fonte di dati. Quando aggiungi o recuperi un file `Person` nel tuo server GraphQL, puoi aspettarti che i dati seguano il formato dei tuoi tipi e campi, ovvero la struttura dei tuoi dati nello schema determina come saranno strutturati nella tua risposta:

```
}
  "data": {
    "people": [
      {
        "name": "John Smith",
        "age": "50"
      },
      {
        "name": "Andrew Miller",
        "age": "60"
      },
      .
      .
      .
    ]
  }
}
```

I campi svolgono un ruolo importante nella strutturazione dei dati. Di seguito sono illustrate un paio di proprietà aggiuntive che possono essere applicate ai campi per una maggiore personalizzazione.

## Elenchi
<a name="list-components"></a>

Gli elenchi restituiscono tutti gli elementi di un tipo specificato. È possibile aggiungere un elenco al tipo di campo utilizzando le parentesi`[]`: 

```
type Person { 
  name: String
  age: Int
}
type Query {                                   
  people: [Person]
}
```

In`Query`, le parentesi che lo circondano `Person` indicano che si desidera restituire tutte le istanze di `Person` dalla fonte di dati come matrice. Nella risposta, i `age` valori `name` e di ciascuno `Person` verranno restituiti come un unico elenco delimitato:

```
}
  "data": {
    "people": [
      {
        "name": "John Smith",         # Data of Person 1
        "age": "50"
      },
      {
        "name": "Andrew Miller",      # Data of Person 2
        "age": "60"
      },
      .                               # Data of Person N
      .
      .
    ]
  }
}
```

Non sei limitato a tipi di oggetti speciali. È inoltre possibile utilizzare elenchi nei campi dei tipi di oggetti normali.

## Non-null
<a name="non-null-components"></a>

I valori non nulli indicano un campo che non può essere nullo nella risposta. È possibile impostare un campo su un valore diverso da nullo utilizzando il simbolo: `!`

```
type Person { 
  name: String!
  age: Int
}
type Query {                                   
  people: [Person]
}
```

Il `name` campo non può essere esplicitamente nullo. Se dovessi interrogare l'origine dati e fornissi un input nullo per questo campo, verrebbe generato un errore.

È possibile combinare elenchi e valori non nulli. Confronta queste domande:

```
type Query {                                   
  people: [Person!]      # Use case 1
}

.
.
.

type Query {                                   
  people: [Person]!      # Use case 2
}

.
.
.

type Query {                                   
  people: [Person!]!     # Use case 3
}
```

Nel caso d'uso 1, l'elenco non può contenere elementi nulli. Nel caso d'uso 2, l'elenco stesso non può essere impostato su null. Nel caso d'uso 3, l'elenco e i relativi elementi non possono essere nulli. Tuttavia, in ogni caso, è comunque possibile restituire elenchi vuoti.

Come puoi vedere, ci sono molti componenti mobili in GraphQL. In questa sezione, abbiamo mostrato la struttura di uno schema semplice e i diversi tipi e campi supportati da uno schema. Nella sezione seguente, scoprirai gli altri componenti di un'API GraphQL e come funzionano con lo schema.