Server GraphQL code-first
Lo schema GraphQL definisce i contratti di un servizio GraphQL, esponendo l'insieme dei tipi, dei campi e delle mutation che possono essere eseguiti sul servizio. Durante la creazione di un servizio GraphQL, possiamo decidere di:
- fare dello schema l'unica fonte di verità e adattare tutto il nostro codice di implementazione alle sue definizioni
- fare del nostro codice l'unica fonte di verità e generare lo schema come un artefatto a partire dal codice
In entrambi i casi disporremo di un servizio GraphQL pienamente funzionante, ma, a seconda dell'approccio scelto, potremo realizzare più o meno funzionalità, con più o meno facilità, nel lungo periodo. Questi due approcci sono chiamati, rispettivamente, "schema-first" (meglio definito "SDL-first") e "code-first".
Gato GraphQL utilizza l'approccio code-first. Vediamo perché.
Perché Gato GraphQL utilizza code-first
Nell'approccio code-first, iniziamo codificando i resolver e poi, a partire dal codice come unica fonte di verità, generiamo lo schema come un artefatto. Pertanto, lo schema viene creato eseguendo uno script, anziché essere creato manualmente come in SDL-first. Poiché anche code-first dispone di uno schema, non manca nulla di significativo rispetto a quanto offerto da SDL-first.
Tuttavia, code-first offre una caratteristica importante rispetto a SDL-first: la possibilità di fornire schemi dinamici, che possono cambiare forma e attributi a seconda del contesto, regolati tramite il codice in fase di esecuzione. Di fatto, tutte le grandi funzionalità offerte da Gato GraphQL sono una conseguenza diretta della sua adozione di code-first.
Vantaggi di code-first
Uno schema dinamico offre, tra gli altri, tutti i vantaggi elencati di seguito:
La fonte di verità per lo schema è un superinsieme di quella richiesta da GraphQL. Le proprietà aggiuntive (come i campi globali, le connessioni globali, le direttive globali e i frammenti persistiti) possono già essere utilizzate nella nostra API senza dover attendere che vengano aggiunte alle specifiche GraphQL, ammesso che ciò avvenga.
Poiché la fonte di verità non è legata allo schema, possiamo generare qualsiasi schema anche per qualsiasi altro sistema: GraphQL è solo uno dei target possibili. Ad esempio, può generare un JSON-schema per un servizio REST a partire dalla stessa fonte di verità.
L'API può essere pubblica/privata allo stesso tempo, a seconda che l'utente sia autenticato o meno e dei ruoli dell'utente autenticato, oppure offrire più o meno campi in base a un'altra proprietà, come il fatto che l'utente abbia sottoscritto l'abbonamento PRO.
I tipi non sanno in anticipo quali campi risolveranno. Al contrario, i resolver di campo si associano ai resolver di tipo tramite il pattern publish-subscribe, e i resolver di campo possono sovrascriverne altri. Questa caratteristica rende l'API molto estendibile, consentendoci di disporre di un codice generale per la nostra API e di personalizzarlo a livello applicativo per un client o un progetto specifico.
Un campo può essere elaborato non da un solo resolver, ma da molti: ogni resolver di campo nella catena può decidere, in fase di esecuzione, se elaborare il campo o meno in base a una proprietà, oppure passarlo lungo la catena. Ad esempio, un resolver di campo speciale può essere utilizzato solo se viene passato un argomento di campo "source: testing", consentendo di testarlo su alcuni siti in produzione prima del rilascio generale; la stessa strategia permette anche di fornire correzioni rapide di bug per un client o un ambiente specifico senza rischiare di provocare effetti collaterali indesiderati altrove.
I tipi e le interfacce possono essere automaticamente inseriti in namespace per evitare collisioni con terze parti.