

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

# Componenti di un'API GraphQL
<a name="api-components"></a>

Un'API GraphQL standard è composta da un unico schema che gestisce la forma dei dati che verranno interrogati. Lo schema è collegato a una o più fonti di dati come un database o una funzione Lambda. Tra i due si trovano uno o più resolver che gestiscono la logica aziendale per le tue richieste. Ogni componente svolge un ruolo importante nell'implementazione di GraphQL. Le sezioni seguenti introdurranno questi tre componenti e il ruolo che svolgono nel servizio GraphQL.

![\[GraphQL API components: schema, resolvers, and data sources interconnected with AppSync.\]](http://docs.aws.amazon.com/it_it/appsync/latest/devguide/images/appsync-architecture-graphql-api.png)


**Topics**
+ [Schemi GraphQL](schema-components.md)
+ [Fonti di dati](data-source-components.md)
+ [Risolutori](resolver-components.md)

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

# Fonti di dati
<a name="data-source-components"></a>

Nella sezione precedente, abbiamo appreso che uno schema definisce la forma dei dati. Tuttavia, non abbiamo mai spiegato da dove provenissero quei dati. Nei progetti reali, lo schema è come un gateway che gestisce tutte le richieste fatte al server. Quando viene effettuata una richiesta, lo schema funge da singolo endpoint che si interfaccia con il client. Lo schema accederà, elaborerà e inoltrerà i dati dalla fonte dati al client. Guarda l'infografica qui sotto:

![\[GraphQL schema integrating multiple Servizi AWS for a single endpoint API architecture.\]](http://docs.aws.amazon.com/it_it/appsync/latest/devguide/images/aws-flow-infographic.png)


AWS AppSync e GraphQL implementano in modo eccellente le soluzioni Backend For Frontend (BFF). Lavorano in tandem per ridurre la complessità su larga scala astraendo il backend. Se il tuo servizio utilizza diverse fonti di dati e/o microservizi, puoi essenzialmente eliminare parte della complessità definendo la forma dei dati di ciascuna fonte (sottografo) in un unico schema (supergrafo). Ciò significa che l'API GraphQL non si limita a utilizzare un'unica fonte di dati. Puoi associare un numero qualsiasi di fonti di dati all'API GraphQL e specificare nel codice come interagiranno con il servizio.

Come puoi vedere nell'infografica, lo schema GraphQL contiene tutte le informazioni di cui i client hanno bisogno per richiedere dati. Ciò significa che tutto può essere elaborato in un'unica richiesta anziché in più richieste come nel caso di REST. Queste richieste passano attraverso lo schema, che è l'unico endpoint del servizio. Quando le richieste vengono elaborate, un resolver (spiegato nella sezione successiva) esegue il proprio codice per elaborare i dati dalla fonte di dati pertinente. Quando viene restituita la risposta, il sottografo collegato all'origine dati verrà popolato con i dati dello schema. 

AWS AppSync supporta molti tipi di fonti di dati diversi. Nella tabella seguente, descriveremo ogni tipo, elencheremo alcuni dei vantaggi di ciascuno e forniremo link utili per un contesto aggiuntivo.


| Origine dati | Description | Vantaggi | Informazioni supplementari | 
| --- | --- | --- | --- | 
| Amazon DynamoDB | «Amazon DynamoDB è un servizio di database NoSQL completamente gestito che offre prestazioni veloci e prevedibili con una scalabilità perfetta. DynamoDB consente di scaricare gli oneri di gestione e dimensionamento di un database distribuito in modo da non doversi più preoccupare di provisioning dell'hardware, installazione e configurazione, replica, applicazione di patch al software e dimensionamento del cluster. DynamoDB offre anche la crittografia a riposo, che elimina l'onere operativo e la complessità associati alla protezione dei dati sensibili». |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/appsync/latest/devguide/data-source-components.html)  | 
| AWS Lambda | "AWS Lambda è un servizio di elaborazione che consente di eseguire codice senza effettuare il provisioning o la gestione di server.Lambda esegue il codice su un'infrastruttura di elaborazione ad alta disponibilità e gestisce tutta l'amministrazione delle risorse di elaborazione, compresa la manutenzione del server e del sistema operativo, il provisioning e la scalabilità automatica della capacità e la registrazione. Con Lambda, tutto ciò che devi fare è fornire il codice in uno dei runtime linguistici supportati da Lambda». |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/appsync/latest/devguide/data-source-components.html)  | 
| OpenSearch | «Amazon OpenSearch Service è un servizio gestito che semplifica l'implementazione, il funzionamento e la scalabilità OpenSearch dei cluster nel AWS cloud. Amazon OpenSearch Service supporta un sistema operativo OpenSearch Elasticsearch legacy (fino alla versione 7.10, l'ultima versione open source del software). Quando si crea un cluster, è possibile scegliere il motore di ricerca da usare.**OpenSearch**è un motore di ricerca e analisi completamente open source per casi d'uso come l'analisi dei log, il monitoraggio delle applicazioni in tempo reale e l'analisi dei clickstream. Per ulteriori informazioni, consulta la [documentazione relativa ad OpenSearch](https://opensearch.org/docs/).**Amazon OpenSearch Service fornisce** tutte le risorse per il OpenSearch cluster e lo avvia. Inoltre, rileva e sostituisce automaticamente i nodi di OpenSearch servizio guasti, riducendo il sovraccarico associato alle infrastrutture autogestite. Puoi scalare il tuo cluster con una singola chiamata API o pochi clic nella console». |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/appsync/latest/devguide/data-source-components.html)  | 
| Endpoint HTTP | Puoi utilizzare gli endpoint HTTP come fonti di dati. AWS AppSync può inviare richieste agli endpoint con le informazioni pertinenti come parametri e payload. La risposta HTTP verrà esposta al resolver, che restituirà la risposta finale al termine delle sue operazioni. |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/appsync/latest/devguide/data-source-components.html)  | 
| Amazon EventBridge | "EventBridge è un servizio serverless che utilizza gli eventi per connettere tra loro i componenti delle applicazioni, semplificando la creazione di applicazioni scalabili basate sugli eventi. Utilizzatelo per indirizzare gli eventi da fonti quali applicazioni, AWS servizi e software di terze parti sviluppati internamente alle applicazioni destinate ai consumatori all'interno dell'organizzazione. EventBridge offre un modo semplice e coerente per importare, filtrare, trasformare e fornire eventi in modo da poter creare nuove applicazioni rapidamente». |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/appsync/latest/devguide/data-source-components.html)  | 
| Database relazionali | «Amazon Relational Database Service (Amazon RDS) è un servizio Web che semplifica la configurazione, il funzionamento e la scalabilità di un database relazionale nel cloud. AWS Fornisce una capacità ridimensionabile e conveniente per un database relazionale standard del settore e gestisce le attività comuni di amministrazione dei database». |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/appsync/latest/devguide/data-source-components.html)  | 
| Nessuna fonte di dati | Se non hai intenzione di utilizzare un servizio di origine dati, puoi impostarlo sunone. Una fonte di none dati, sebbene sia ancora esplicitamente classificata come fonte di dati, non è un supporto di archiviazione. Nonostante ciò, è ancora utile in alcuni casi per la manipolazione e il trasferimento dei dati. |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/appsync/latest/devguide/data-source-components.html)  | 

**Suggerimento**  
Per ulteriori informazioni su come interagiscono le sorgenti di dati AWS AppSync, consulta [Allegare un'](https://docs.aws.amazon.com//appsync/latest/devguide/attaching-a-data-source.html)origine dati.

# Risolutori
<a name="resolver-components"></a>

Nelle sezioni precedenti, hai appreso i componenti dello schema e dell'origine dati. Ora, dobbiamo affrontare il modo in cui lo schema e le fonti di dati interagiscono. Tutto inizia con il resolver.

Un resolver è un'unità di codice che gestisce il modo in cui i dati di quel campo verranno risolti quando viene effettuata una richiesta al servizio. I resolver sono associati a campi specifici all'interno dei tipi dello schema. Sono più comunemente usati per implementare le operazioni di modifica dello stato per le operazioni sui campi di interrogazione, mutazione e sottoscrizione. Il resolver elaborerà la richiesta del client, quindi restituirà il risultato, che può essere un gruppo di tipi di output come oggetti o scalari:

![\[GraphQL schema with resolvers connecting to various AWS data sources for a single endpoint.\]](http://docs.aws.amazon.com/it_it/appsync/latest/devguide/images/aws-flow-infographic.png)


## Runtime del resolver
<a name="resolver-components-runtime"></a>

In AWS AppSync, devi prima specificare un runtime per il tuo resolver. Un runtime del resolver indica l'ambiente in cui viene eseguito un resolver. Determina anche la lingua in cui verranno scritti i resolver. AWS AppSync attualmente supporta APPSYNC\$1JS for JavaScript e Velocity Template Language (VTL). [Vedi le [funzionalità JavaScript di runtime per i resolver e le funzioni per o il riferimento all'utilità dei modelli di mappatura Resolver](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference-js.html) per JavaScript VTL.](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference.html)

## Struttura del resolver
<a name="resolver-components-structure"></a>

Dal punto di vista del codice, i resolver possono essere strutturati in un paio di modi. ****Esistono resolver di unità e pipeline.****

### Risolver di unità
<a name="resolver-components-unit"></a>

Un resolver di unità è composto da codice che definisce un singolo gestore di richieste e risposte che vengono eseguiti su un'origine dati. Il gestore di richieste accetta un oggetto di contesto come argomento e restituisce il payload della richiesta utilizzato per chiamare l'origine dei dati. Il gestore della risposta riceve un payload dall'origine dati con il risultato della richiesta eseguita. Il gestore di risposte trasforma il payload in una risposta GraphQL per risolvere il campo GraphQL.

![\[GraphQL request flow showing request and response handlers interacting with a data source.\]](http://docs.aws.amazon.com/it_it/appsync/latest/devguide/images/unit-resolver-js.png)


### Resolver per pipeline
<a name="resolver-components-pipeline"></a>

Quando si implementano i risolutori di pipeline, esiste una struttura generale che seguono:
+ **Prima della fase**: quando viene effettuata una richiesta dal client, ai resolver per i campi dello schema utilizzati (in genere le query, le mutazioni, le sottoscrizioni) vengono trasmessi i dati della richiesta. Il resolver inizierà a elaborare i dati della richiesta con un gestore del passaggio precedente, che consente di eseguire alcune operazioni di preelaborazione prima che i dati passino attraverso il resolver.
+ **Funzione/i**: dopo l'esecuzione del passaggio precedente, la richiesta viene passata all'elenco delle funzioni. La prima funzione dell'elenco verrà eseguita sulla fonte di dati. Una funzione è un sottoinsieme del codice del resolver contenente il proprio gestore di richieste e risposte. Un gestore di richieste raccoglierà i dati della richiesta ed eseguirà operazioni sulla fonte dei dati. Il gestore della risposta elaborerà la risposta dell'origine dati prima di restituirla all'elenco. Se è presente più di una funzione, i dati della richiesta verranno inviati alla funzione successiva nell'elenco da eseguire. Le funzioni nell'elenco verranno eseguite in serie nell'ordine definito dallo sviluppatore. Una volta eseguite tutte le funzioni, il risultato finale viene passato alla fase successiva.
+ **Dopo la fase**: la fase successiva è una funzione di gestione che consente di eseguire alcune operazioni finali sulla risposta finale della funzione prima di passarla alla risposta GraphQL.

![\[GraphQL request flow diagram showing interactions between request, data sources, and response components.\]](http://docs.aws.amazon.com/it_it/appsync/latest/devguide/images/appsync-js-resolver-logic.png)


## Struttura del gestore Resolver
<a name="resolver-components-handlers"></a>

I gestori sono in genere funzioni chiamate e: `Request` `Response`

```
export function request(ctx) {
    // Code goes here
}

export function response(ctx) {
    // Code goes here
}
```

In un risolutore di unità, ci sarà solo un set di queste funzioni. In un resolver a pipeline, ci sarà un set di queste per la fase prima e dopo e un set aggiuntivo per funzione. Per vedere come potrebbe apparire, esaminiamo un tipo semplice: `Query`

```
type Query {
	helloWorld: String!
}
```

Questa è una semplice interrogazione con un campo chiamato `helloWorld` of type`String`. Supponiamo di voler sempre che questo campo restituisca la stringa «Hello World». Per implementare questo comportamento, dobbiamo aggiungere il resolver a questo campo. In un risolutore di unità, potremmo aggiungere qualcosa del genere:

```
export function request(ctx) {
    return {}
}

export function response(ctx) {
    return "Hello World"
}
```

`request`Può semplicemente essere lasciato vuoto perché non stiamo richiedendo o elaborando dati. Possiamo anche supporre che la nostra fonte di dati sia`None`, indicando che questo codice non deve eseguire alcuna chiamata. La risposta restituisce semplicemente «Hello World». Per testare questo resolver, dobbiamo fare una richiesta utilizzando il tipo di query:

```
query helloWorldTest {
  helloWorld
}
```

Questa è una query chiamata `helloWorldTest` che restituisce il `helloWorld` campo. Quando viene eseguito, il `helloWorld` field resolver esegue e restituisce anche la risposta:

```
{
  "data": {
    "helloWorld": "Hello World"
  }
}
```

Restituire costanti come questa è la cosa più semplice che si possa fare. In realtà, restituirai input, elenchi e altro. Ecco un esempio più complicato:

```
type Book {
  id: ID!
  title: String
}

type Query {
  getBooks: [Book]
}
```

Qui stiamo restituendo un elenco di`Books`. Supponiamo di utilizzare una tabella DynamoDB per archiviare i dati dei libri. I nostri gestori potrebbero avere il seguente aspetto:

```
/**
 * Performs a scan on the dynamodb data source
 */
export function request(ctx) {
  return { operation: 'Scan' };
}

/**
 * return a list of scanned post items
 */
export function response(ctx) {
  return ctx.result.items;
}
```

La nostra richiesta ha utilizzato un'operazione di scansione integrata per cercare tutte le voci della tabella, memorizzato i risultati nel contesto e quindi li ha passati alla risposta. La risposta ha preso gli elementi del risultato e li ha restituiti nella risposta:

```
{
  "data": {
    "getBooks": {
      "items": [
        {
          "id": "abcdefgh-1234-1234-1234-abcdefghijkl",
          "title": "book1"
        },
        {
          "id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
          "title": "book2"
        },

        ...

      ]
    }
  }
}
```

## Contesto del risolutore
<a name="resolver-components-context"></a>

In un resolver, ogni fase della catena di gestori deve essere a conoscenza dello stato dei dati dei passaggi precedenti. Il risultato di un gestore può essere memorizzato e passato a un altro come argomento. GraphQL definisce quattro argomenti di base del resolver:


****  

| Argomenti di base del resolver | Description | 
| --- | --- | 
| obj, root, parent e così via. | Il risultato del genitore. | 
| args | Gli argomenti forniti al campo nella query GraphQL. | 
| context | Un valore che viene fornito a ogni resolver e contiene importanti informazioni contestuali come l'utente attualmente connesso o l'accesso a un database. | 
| info | Un valore che contiene informazioni specifiche sul campo relative alla query corrente e i dettagli dello schema. | 

Nel AWS AppSync, l'argomento `[context](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html)` (ctx) può contenere tutti i dati sopra menzionati. È un oggetto creato su richiesta e contiene dati come credenziali di autorizzazione, dati sui risultati, errori, metadati di richiesta, ecc. Il contesto è un modo semplice per i programmatori di manipolare i dati provenienti da altre parti della richiesta. Riprendi questo frammento:

```
/**
 * Performs a scan on the dynamodb data source
 */
export function request(ctx) {
  return { operation: 'Scan' };
}

/**
 * return a list of scanned post items
 */
export function response(ctx) {
  return ctx.result.items;
}
```

Alla richiesta viene fornito il contesto (ctx) come argomento; questo è lo stato della richiesta. Esegue una scansione di tutti gli elementi di una tabella, quindi memorizza il risultato nel contesto in`result`. Il contesto viene quindi passato all'argomento response, che accede a `result` e ne restituisce il contenuto.

## Richieste e analisi
<a name="resolver-ast"></a>

Quando si effettua una query sul servizio GraphQL, questa deve essere sottoposta a un processo di analisi e convalida prima di essere eseguita. La tua richiesta verrà analizzata e tradotta in un albero di sintassi astratto. Il contenuto dell'albero viene convalidato eseguendo diversi algoritmi di convalida rispetto allo schema. Dopo la fase di convalida, i nodi dell'albero vengono attraversati ed elaborati. I resolver vengono richiamati, i risultati vengono archiviati nel contesto e viene restituita la risposta. Ad esempio, prendiamo questa query:

```
query {
  Person {  //object type
    name  //scalar
    age   //scalar
  } 
}
```

Stiamo tornando `Person` con i campi a e. `name` `age` Quando si esegue questa query, l'albero avrà un aspetto simile a questo:

![\[Hierarchical diagram showing query, Person, name, and age nodes connected by arrows.\]](http://docs.aws.amazon.com/it_it/appsync/latest/devguide/images/ast-1.png)


Dall'albero, sembra che questa richiesta cercherà la radice di `Query` nello schema. All'interno della query, il `Person` campo verrà risolto. Dagli esempi precedenti, sappiamo che questo potrebbe essere un input dell'utente, un elenco di valori, ecc. `Person` è molto probabilmente legato a un tipo di oggetto che contiene i campi di cui abbiamo bisogno (`name`e`age`). Una volta trovati, questi due campi secondari vengono risolti nell'ordine indicato (`name`seguiti da`age`). Una volta che l'albero è stato completamente risolto, la richiesta viene completata e verrà rispedita al client.