GraphQL — è un linguaggio di query per API e un runtime per eseguire tali query, sviluppato da Facebook nel 2012 e reso open source nel 2015. A differenza di REST, dove il server determina la struttura della risposta, GraphQL consente al client di specificare esattamente i dati di cui ha bisogno, eliminando completamente i problemi di overfetching e underfetching. Secondo il State of JavaScript Survey (2025), il 35% degli sviluppatori intervistati utilizza GraphQL, e tra le grandi aziende lo hanno adottato GitHub, Shopify, Airbnb e The New York Times. GraphQL supporta tre tipi di operazioni: query (lettura), mutation (scrittura) e subscription (aggiornamenti in tempo reale via WebSocket).
Punti chiave
GraphQL — è una specifica e un runtime per API che dà al client il controllo completo sui dati ricevuti. Sviluppata dagli ingegneri di Facebook per risolvere i problemi dell'applicazione mobile News Feed, la specifica è stata pubblicata come standard aperto nel 2015. Dal 2018, GraphQL è gestito dalla GraphQL Foundation con il supporto della Linux Foundation e di aziende come Apollo, AWS, GitHub, SAP e altre.
A differenza di REST, dove ogni endpoint restituisce una struttura dati fissa, GraphQL utilizza un unico endpoint che accetta una stringa di query. Il client descrive nella query quali campi gli servono e il server restituisce esattamente quelli. Ad esempio, la query { user(id: "1") { name email } } restituirà solo il nome e l'email dell'utente, senza campi aggiuntivi come address, phone o createdAt che sarebbero stati necessari in REST.
GraphQL non è legato a nessun database o linguaggio specifico. La specifica definisce solo il formato delle query e delle risposte. Esistono implementazioni server su Node.js (graphql-js, Apollo Server), Kotlin (graphql-kotlin, Netflix DGS Framework), Python (Graphene, Strawberry), Ruby (graphql-ruby) e altri linguaggi. Le librerie client sono disponibili per tutte le principali piattaforme, incluso Apollo Client per iOS, Android e web.
L'architettura di GraphQL è composta da tre componenti chiave: Schema, Resolver e il Motore GraphQL (GraphQL Engine). Lo schema definisce quali tipi di dati sono disponibili, quali query possono essere eseguite e quali argomenti accettano. I resolver sono funzioni lato server che restituiscono dati per ogni campo dello schema. Il motore riceve la query in ingresso, la valida rispetto allo schema, chiama i resolver appropriati e assembla la risposta.
Il processo di elaborazione della query è il seguente:
Il vantaggio chiave dell'architettura GraphQL è la risoluzione a livello di campo. In REST, lo sviluppatore ottiene tutti i campi di una risorsa (possibilmente con dati superflui) o ricorre a estensioni come ?fields=name,email. In GraphQL, questo filtraggio è integrato nel linguaggio: ogni query specifica esplicitamente quali campi sono necessari e il server restituisce esattamente quelli. Ciò è particolarmente importante per le applicazioni mobili, dove la quantità di dati trasferiti influisce direttamente sulla velocità di caricamento e sul consumo di dati.
GraphQL definisce tre tipi di operazioni, ciascuno corrispondente a uno scenario di interazione specifico. Query — per la lettura dei dati, analogo a GET in REST. Mutation — per modificare i dati (creazione, aggiornamento, eliminazione), analogo a POST/PUT/DELETE. Subscription — per aggiornamenti in tempo reale via WebSocket, che non ha un analogo diretto nel REST classico (richiede soluzioni aggiuntive come WebSocket o Server-Sent Events).
La sintassi di base delle query è intuitiva:
// Query semplice con argomento
query {
user(id: "42") {
name
email
avatarUrl
}
}
// Mutation che restituisce dati modificati
mutation {
updateProfile(name: "Ivan") {
id
name
updatedAt
}
}
// Subscription — ascolta gli aggiornamenti in tempo reale
subscription {
newMessage(chatId: "chat_1") {
id
text
sender { name }
}
}
Query viene eseguita in parallelo — tutti i campi allo stesso livello vengono caricati simultaneamente. Ciò consente di caricare dati correlati (utente e i suoi post) in un'unica richiesta senza più round-trip. Mutation viene eseguita sequenzialmente — le mutazioni in una richiesta vengono eseguite una dopo l'altra nell'ordine di dichiarazione. Subscription stabilisce una connessione persistente via WebSocket, attraverso la quale il server invia dati al verificarsi di un evento.
Le operazioni possono accettare variabili per separare i dati dalla query, direttive (@include, @skip) per l'inclusione condizionale di campi e frammenti per riutilizzare insiemi di campi. Queste capacità rendono le query GraphQL flessibili e riutilizzabili, il che è particolarmente importante nei grandi progetti con molti schermi e componenti.
Al centro di GraphQL c'è un sistema di tipi che descrive tutti i dati e le operazioni API possibili. Lo schema è una descrizione dei tipi che il server può restituire e delle query che accetta. Lo schema è scritto in Schema Definition Language (SDL) e funge da contratto tra client e server. Il client può ottenere lo schema tramite introspezione — una query speciale __schema che restituisce una descrizione completa dell'API.
Esempio di schema per un blog:
// SDL — Schema Definition Language
type User {
id: ID!
name: String!
email: String
posts: [Post!]!
}
type Post {
id: ID!
title: String!
content: String
author: User!
}
type Query {
user(id: ID!): User
posts(page: Int): [Post!]!
}
Il punto esclamativo (!) indica un campo non nullo — sarà garantitamente presente nella risposta. Le parentesi quadre [ ] denotano un elenco. GraphQL supporta tipi scalari (Int, Float, String, Boolean, ID), tipi oggetto, enum, union, interface e tipi di input (per gli argomenti delle mutazioni). La tipizzazione rigorosa auto-documenta l'API e consente agli strumenti client di generare codice: tipi TypeScript, classi dati Kotlin, strutture Swift.
L'introspezione è una funzionalità unica di GraphQL assente in REST. Il client può inviare una query allo schema e ottenere una descrizione completa di tutti i tipi, campi, argomenti e direttive. Questa è la base di strumenti come GraphiQL e Apollo Studio, che generano automaticamente documentazione e completamento automatico per gli sviluppatori. L'introspezione consente anche di scrivere test automatici che verificano la conformità dello schema alla struttura prevista.
La scelta tra GraphQL e REST è una delle decisioni architetturali chiave nella progettazione di un'API. Entrambi gli approcci hanno i loro punti di forza e di debolezza, e la scelta dipende dai requisiti specifici del progetto. REST vince in semplicità e universalità, GraphQL in flessibilità ed efficienza delle query. Diamo un'occhiata alla tabella comparativa.
| Criterio | REST | GraphQL |
|---|---|---|
| Struttura della risposta | Fissa, definita dal server | Flessibile, definita dal client |
| Overfetching | Spesso — il server restituisce tutti i campi | No — il client richiede solo i campi necessari |
| Numero di richieste | Più round-trip | Un'unica richiesta per tutti i dati |
| Cache | Cache HTTP nativa | Richiede configurazione manuale |
| Tipizzazione | Non integrata (dipende dal formato) | Rigorosa, tramite schema SDL |
| Strumenti | curl, Postman, Swagger | GraphiQL, Apollo Studio, Introspezione |
| Caricamento file | Nativo tramite multipart | Richiede protocolli aggiuntivi |
| Prestazioni | Prevedibili, più facili da ottimizzare | Dipende dalla complessità delle query annidate |
Il principale svantaggio di GraphQL è la complessità della cache. In REST, la cache HTTP funziona a livello di URL: una richiesta a /api/users/42 restituisce sempre la stessa struttura e la risposta può essere memorizzata nella cache per URL. In GraphQL, tutte le richieste vanno a un unico endpoint e la struttura della risposta dipende dal corpo della richiesta. Per risolvere questo problema, Apollo Client utilizza una cache normalizzata lato client, che suddivide le risposte in entità individuali per id e le aggiorna automaticamente al ricevimento di nuovi dati.
Un altro aspetto importante è il problema N+1. Quando si richiedono dati annidati (ad esempio, i post di un utente e i commenti per ogni post), GraphQL può eseguire una query SQL separata per ogni elemento dell'elenco. Viene risolto utilizzando DataLoader — un'utilità per raggruppare e memorizzare nella cache le query del database, che raggruppa le richieste individuali in un unico lotto. In REST, questo problema è meno pronunciato poiché lo sviluppatore controlla la struttura della risposta lato server.
Vediamo esempi pratici di utilizzo di GraphQL in un'applicazione mobile Kotlin con Apollo Client. Gli esempi mostrano scenari tipici: caricamento dei dati per una schermata del profilo (query), creazione di un nuovo post (mutation) e sottoscrizione a nuovi commenti (subscription). Ogni esempio include sia la query GraphQL che il codice lato client.
Un'unica query GraphQL carica l'utente, i suoi ultimi post e il numero totale di follower. In REST, sarebbero necessarie almeno 2-3 richieste: /users/42, /users/42/posts, /users/42/stats. GraphQL le combina in un unico round-trip, riducendo il tempo di caricamento dello schermo su connessioni lente.
// Query GraphQL (nel file .graphql)
query ProfileScreen($userId: ID!) {
user(id: $userId) {
name
bio
avatarUrl
posts(limit: 10) {
id
title
createdAt
}
followersCount
followingCount
}
}
// Chiamata sul client (Apollo Client + Kotlin)
val response = apolloClient
.query(ProfileScreenQuery(userId = "42"))
.execute()
binding.nameText.text = response.data?.user?.name
La mutazione non solo crea una risorsa, ma restituisce anche i suoi dati correnti per aggiornare l'interfaccia utente. Il campo __typename è utilizzato da Apollo Client per la normalizzazione della cache — il client aggiornerà automaticamente il record Post nella cache in caso di risposta positiva della mutazione.
// Mutation GraphQL
mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
id
title
createdAt
author {
id
name
}
}
}
// Chiamata mutation con tipo input
val input = CreatePostInput(
title = "Nuovo post su GraphQL",
content = "GraphQL semplifica il lavoro con le API..."
)
val result = apolloClient
.mutation(CreatePostMutation(input))
.execute()
Un importante vantaggio di GraphQL rispetto a REST nel contesto dello sviluppo mobile è la generazione automatica del codice. Apollo Client per Kotlin (Apollo GraphQL) genera classi type-safe da file .graphql in fase di compilazione. Se il server modifica lo schema, il progetto non verrà compilato fino all'aggiornamento delle query. Ciò previene errori a runtime tipici di REST, dove le modifiche alla struttura della risposta possono passare inosservate durante lo sviluppo.
L'ecosistema GraphQL include diverse librerie e strumenti chiave che semplificano lo sviluppo e l'operatività. Apollo Client è la libreria client più popolare, che supporta React, iOS, Android e Kotlin Multiplatform. Relay di Facebook è un'alternativa per applicazioni React con un approccio unico alla gestione dei dati e alla cache. La scelta tra Apollo e Relay dipende dalla piattaforma e dai requisiti di prestazioni.
Lato server, i leader sono Apollo Server (Node.js), Netflix DGS Framework (Kotlin/Java) e graphql-ruby. Per lo sviluppo dello schema e il test delle query, viene utilizzato GraphiQL — un IDE interattivo integrato nel browser. Apollo Studio fornisce metriche delle prestazioni, tracciamento delle query e gestione dello schema per ambienti di produzione. Menzione a parte merita GraphQL Code Generator — uno strumento che genera tipi TypeScript, Kotlin, Swift e Dart da uno schema SDL.
Per lo sviluppo mobile, Apollo Kotlin (Apollo GraphQL) è di particolare interesse — una libreria interamente scritta in Kotlin con supporto per coroutine, Flow e Multiplatform. Consente di utilizzare query GraphQL unificate per Android e iOS in progetti Kotlin Multiplatform. Apollo Kotlin normalizza la cache, supporta errori a livello di campo (errori parziali) e genera automaticamente modelli di dati da file .graphql. Ciò rende GraphQL la scelta preferita per grandi progetti mobili dove la velocità di sviluppo e la sicurezza dei tipi sono importanti.
Domande frequenti
GraphQL non sostituisce REST, ma offre un approccio alternativo. REST è più adatto per API CRUD semplici, cache HTTP e API pubbliche con carico prevedibile. GraphQL è ottimale per interfacce complesse con molti dati correlati.
La migrazione è possibile gradualmente: GraphQL può funzionare come un livello (gateway) davanti ai servizi REST esistenti. Molte aziende aggiungono GraphQL accanto a REST senza disattivare la vecchia API. La sostituzione completa richiede la riscrittura dei resolver.
Il problema N+1 si verifica quando viene eseguita una query SQL separata per ogni elemento di un elenco. Viene risolto utilizzando DataLoader — una libreria che raggruppa le richieste individuali in una sola e memorizza nella cache i risultati all'interno di una singola richiesta HTTP.
La specifica GraphQL non definisce direttamente il caricamento dei file. In pratica, vengono utilizzati: codifica base64 (semplice ma inefficiente per file grandi), richieste multipart secondo il protocollo graphql-multipart-request-spec o un endpoint REST separato per i file.
La sicurezza di GraphQL richiede misure aggiuntive: limitazione della profondità di annidamento, limiti di complessità delle query, rate limiting a livello di operazione. L'introspezione pubblica dello schema può rivelare la struttura dei dati — in produzione si consiglia di disabilitarla.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche