Creazione di API GraphQL con Node

Pubblicato: 2022-12-20

GraphQL è la nuova parola d'ordine nello sviluppo di API. Sebbene le API RESTful rimangano il modo più popolare per esporre i dati dalle applicazioni, presentano molte limitazioni che GraphQL mira a risolvere.

GraphQL è un linguaggio di query creato da Facebook, trasformato in un progetto open source nel 2015. Offre una sintassi intuitiva e flessibile per descrivere e accedere ai dati in un'API.

Questa guida esplorerà come creare un progetto GraphQL Node.js. Useremo GraphQL per creare un'applicazione Todo nel framework Web Express.js per Node.

Cos'è GraphQL?

Dalla documentazione ufficiale: “GraphQL è un linguaggio di query per le API e un runtime per soddisfare tali query con i dati esistenti. GraphQL fornisce una descrizione completa e comprensibile dei dati nella tua API, offre ai clienti il ​​potere di chiedere esattamente ciò di cui hanno bisogno e nient'altro, semplifica l'evoluzione delle API nel tempo e abilita potenti strumenti di sviluppo.

GraphQL è un runtime lato server per l'esecuzione di query utilizzando il sistema di tipi definito per i dati. Inoltre, GraphQL non è legato a nessun database o motore di archiviazione specifico. Al contrario, è supportato dal codice e dall'archivio dati esistenti. Puoi ottenere un confronto dettagliato di queste tecnologie con la guida GraphQL vs. API RESTful.

Per creare un servizio GraphQL, si inizia definendo i tipi di schema e creando campi utilizzando tali tipi. Successivamente, fornisci un risolutore di funzioni da eseguire su ciascun campo e tipo ogni volta che i dati vengono richiesti dal lato client.

Terminologia di GraphQL

Il sistema di tipo GraphQL viene utilizzato per descrivere quali dati possono essere interrogati e quali dati è possibile manipolare. È il cuore di GraphQL. Parliamo di diversi modi in cui possiamo descrivere e manipolare i dati in GraphQ.

Tipi

I tipi di oggetto GraphQL sono modelli di dati contenenti campi fortemente tipizzati. Dovrebbe esserci una mappatura 1 a 1 tra i tuoi modelli e i tipi GraphQL. Di seguito è riportato un esempio di tipo GraphQL:

 type User { id: ID! # The "!" means required firstname: String lastname: String email: String username: String todos: [Todo] # Todo is another GraphQL type }

Interrogazioni

GraphQL Query definisce tutte le query che un client può eseguire sull'API GraphQL. È necessario definire una RootQuery che conterrà tutte le query esistenti per convenzione.

Di seguito definiamo e mappiamo le query all'API RESTful corrispondente:

 type RootQuery { user(id: ID): User # Corresponds to GET /api/users/:id users: [User] # Corresponds to GET /api/users todo(id: ID!): Todo # Corresponds to GET /api/todos/:id todos: [Todo] # Corresponds to GET /api/todos }

Mutazioni

Se le query GraphQL sono richieste GET , le mutazioni sono richieste POST , PUT , PATCH e DELETE che manipolano l'API GraphQL.

Metteremo tutte le mutazioni in una singola RootMutation per dimostrare:

 type RootMutation { createUser(input: UserInput!): User # Corresponds to POST /api/users updateUser(id: ID!, input: UserInput!): User # Corresponds to PATCH /api/users removeUser(id: ID!): User # Corresponds to DELETE /api/users createTodo(input: TodoInput!): Todo updateTodo(id: ID!, input: TodoInput!): Todo removeTodo(id: ID!): Todo }

Hai notato l'uso di tipi -input per le mutazioni come UserInput , TodoInput . È sempre consigliabile definire sempre i tipi di input per la creazione e l'aggiornamento delle risorse.

È possibile definire i tipi di input come quello qui sotto:

 input UserInput { firstname: String! lastname: String email: String! username: String! }

Risolutori

I resolver dicono a GraphQL cosa fare quando viene richiesta ogni query o mutazione. È una funzione di base che fa il duro lavoro di raggiungere il livello del database per eseguire le operazioni CRUD (crea, leggi, aggiorna, elimina), raggiungendo un endpoint API RESTful interno o chiamando un microservizio per soddisfare la richiesta del client.

Puoi creare un nuovo file resolvers.js e aggiungere il seguente codice:

 import sequelize from '../models'; export default function resolvers () { const models = sequelize.models; return { // Resolvers for Queries RootQuery: { user (root, { id }, context) { return models.User.findById(id, context); }, users (root, args, context) { return models.User.findAll({}, context); } }, User: { todos (user) { return user.getTodos(); } }, } // Resolvers for Mutations RootMutation: { createUser (root, { input }, context) { return models.User.create(input, context); }, updateUser (root, { id, input }, context) { return models.User.update(input, { ...context, where: { id } }); }, removeUser (root, { id }, context) { return models.User.destroy(input, { ...context, where: { id } }); }, // ... Resolvers for Todos go here } }; }

Schema

Lo schema GraphQL è ciò che GraphQL espone al mondo. Pertanto, i tipi, le query e le mutazioni verranno inclusi all'interno dello schema per essere esposti al mondo.

Di seguito è riportato come esporre tipi, query e mutazioni al mondo:

 schema { query: RootQuery mutation: RootMutation }

Nello script sopra, abbiamo incluso RootQuery e RootMutation che abbiamo creato in precedenza per essere esposti al mondo.

Come funziona GraphQL con Nodejs ed Expressjs

GraphQL fornisce un'implementazione per tutti i principali linguaggi di programmazione e Node.js non è esentato. Sul sito Web ufficiale di GraphQL è presente una sezione per il supporto JavaScript e inoltre sono disponibili altre implementazioni di GraphQL per semplificare la scrittura e la codifica in GraphQL.

GraphQL Apollo fornisce un'implementazione per Node.js ed Express.js e semplifica l'utilizzo di GraphQL.

Imparerai come creare e sviluppare la tua prima applicazione GraphQL nel framework di backend Nodes.js ed Express.js utilizzando GraphQL Apollo nella sezione successiva.

Configurazione di GraphQL con Express.js

Creare un server API GraphQL con Express.js è semplice per iniziare. In questa sezione, esploreremo come costruire un server GraphQL.

Inizializza il progetto con Express

Innanzitutto, devi installare e configurare un nuovo progetto Express.js.

Crea una cartella per il tuo progetto e installa Express.js usando questo comando:

 cd <project-name> && npm init -y npm install express

Il comando precedente crea un nuovo file package.json e installa la libreria Express.js nel tuo progetto.

Successivamente, struttureremo il nostro progetto come mostrato nell'immagine qui sotto. Conterrà diversi moduli per le caratteristiche del progetto come utenti, cose da fare, ecc.

Un elenco di file in graphql-todo.
File per graphql-todo .

Inizializza GraphQL

Iniziamo installando le dipendenze di GraphQL Express.js. Eseguire il comando seguente per installare:

 npm install apollo-server-express graphql @graphql-tools/schema --save

Creazione di schemi e tipi

Successivamente, creeremo un file index.js all'interno della cartella dei moduli e aggiungeremo il seguente frammento di codice:

 const { gql } = require('apollo-server-express'); const users = require('./users'); const todos = require('./todos'); const { GraphQLScalarType } = require('graphql'); const { makeExecutableSchema } = require('@graphql-tools/schema'); const typeDefs = gql` scalar Time type Query { getVersion: String! } type Mutation { version: String! } `; const timeScalar = new GraphQLScalarType({ name: 'Time', description: 'Time custom scalar type', serialize: (value) => value, }); const resolvers = { Time: timeScalar, Query: { getVersion: () => `v1`, }, }; const schema = makeExecutableSchema({ typeDefs: [typeDefs, users.typeDefs, todos.typeDefs], resolvers: [resolvers, users.resolvers, todos.resolvers], }); module.exports = schema;

Procedura dettagliata del codice

Esaminiamo lo snippet di codice e scomponiamolo:

Passo 1

Innanzitutto, abbiamo importato le librerie richieste e creato query e tipi di mutazione predefiniti. La query e la mutazione impostano solo la versione dell'API GraphQL per ora. Tuttavia, mentre procediamo, estenderemo la query e la mutazione per includere altri schemi.

Un'interfaccia a riga di comando che mostra il codice "const" per l'importazione di GraphQL e altre estensioni.
Importazione di GraphQL ed estensioni.
Passo 2:

Quindi abbiamo creato un nuovo tipo scalare per time e il nostro primo risolutore per la query e la mutazione create sopra. Inoltre, abbiamo anche generato uno schema utilizzando la funzione makeExecutableEchema .

Lo schema generato include tutti gli altri schemi che abbiamo importato e ne includerà anche altri quando li creiamo e li importiamo.

Lottando con tempi di inattività e problemi con WordPress? Kinsta è la soluzione di hosting progettata per farti risparmiare tempo! Scopri le nostre funzionalità
Un'interfaccia a riga di comando che mostra il codice "const" per creare il nostro tipo scalare e il nostro primo risolutore.
Creazione di un tipo scalare per time e del nostro primo risolutore.

Il frammento di codice precedente mostra che abbiamo importato diversi schemi nella funzione makeExecutableEchema. Questo approccio ci aiuta a strutturare l'applicazione per la complessità. Successivamente, creeremo gli schemi Todo e User che abbiamo importato.

Creazione dello schema delle cose da fare

Lo schema Todo mostra semplici operazioni CRUD che gli utenti dell'applicazione possono eseguire. Di seguito è riportato lo schema che implementa l'operazione Todo CRUD.

 const { gql } = require('apollo-server-express'); const createTodo = require('./mutations/create-todo'); const updateTodo = require('./mutations/update-todo'); const removeTodo = require('./mutations/delete-todo'); const todo = require('./queries/todo'); const todos = require('./queries/todos'); const typeDefs = gql` type Todo { id: ID! title: String description: String user: User } input CreateTodoInput { title: String! description: String isCompleted: Boolean } input UpdateTodoInput { title: String description: String isCompleted: Boolean } extend type Query { todo(id: ID): Todo! todos: [Todo!] } extend type Mutation { createTodo(input: CreateTodoInput!): Todo updateTodo(id: ID!, input: UpdateTodoInput!): Todo removeTodo(id: ID!): Todo } `; // Provide resolver functions for your schema fields const resolvers = { // Resolvers for Queries Query: { todo, todos, }, // Resolvers for Mutations Mutation: { createTodo, updateTodo, removeTodo, }, }; module.exports = { typeDefs, resolvers };

Procedura dettagliata del codice

Esaminiamo lo snippet di codice e scomponiamolo:

Passo 1:

Innanzitutto, abbiamo creato uno schema per il nostro Todo utilizzando GraphQL type , input ed extend . La parola chiave extend viene utilizzata per ereditare e aggiungere nuove query e mutazioni alla query radice esistente e alla mutazione che abbiamo creato in precedenza.

Un'interfaccia a riga di comando che mostra lo schema per il nostro script Todo, inclusi i nuovi input.
Creazione dello schema per il nostro Todo.
Passo 2:

Successivamente, abbiamo creato un risolutore, che viene utilizzato per recuperare i dati corretti quando viene chiamata una particolare query o mutazione.

Un'interfaccia a riga di comando che mostra il codice per creare un risolutore per il nostro Todo.
Creazione di un risolutore.

Con la funzione resolver in atto, possiamo creare metodi individuali per la logica aziendale e la manipolazione del database, come mostrato nell'esempio create-todo.js .

Crea un file create-user.js nella cartella <code>./mutations</code> e aggiungi la logica di business per creare un nuovo Todo nel tuo database.

 const models = require('../../../models'); module.exports = async (root, { input }, context) => { return models.todos.push({ ...input }); };

Lo snippet di codice sopra è un modo semplificato per creare un nuovo Todo nel nostro database utilizzando Sequelize ORM. Puoi saperne di più su Sequelize e su come configurarlo con Node.js.

Puoi seguire lo stesso passaggio per creare molti schemi a seconda della tua applicazione oppure puoi clonare il progetto completo da GitHub.

Successivamente, configureremo il server con Express.js ed eseguiremo l'applicazione Todo appena creata con GraphQL e Node.js

Configurazione ed esecuzione del server

Infine, configureremo il nostro server utilizzando la libreria apollo-server-express che abbiamo installato in precedenza e lo configureremo.

Apollo-server-express è un semplice wrapper di Apollo Server per Express.js, consigliato perché è stato sviluppato per adattarsi allo sviluppo di Express.js.

Usando gli esempi discussi sopra, configuriamo il server Express.js in modo che funzioni con apollo-server-express appena installato.

Crea un file server.js nella directory principale e incolla il seguente codice:

 const express = require('express'); const { ApolloServer } = require('apollo-server-express'); const schema = require('./modules'); const app = express(); async function startServer() { const server = new ApolloServer({ schema }); await server.start(); server.applyMiddleware({ app }); } startServer(); app.listen({ port: 3000 }, () => console.log(`Server ready at http://localhost:3000`) );

Nel codice sopra, hai creato con successo il tuo primo server CRUD GraphQL per Todos e Users. Puoi avviare il tuo server di sviluppo e accedere al playground usando http://localhost:3000/graphql. Se tutto è andato a buon fine, ti dovrebbe essere presentata la schermata qui sotto:

Un'interfaccia di sviluppo che mostra una semplice query in risposta.
La schermata di verifica.

Sommario

GraphQL è una tecnologia moderna supportata da Facebook che semplifica il noioso lavoro coinvolto nella creazione di API su larga scala con modelli architetturali RESTful.

Questa guida ha chiarito GraphQL e dimostrato come sviluppare la tua prima API GraphQL con Express.js.

Facci sapere cosa costruisci usando GraphQL.