Introduzione
Negli ultimi anni, nuovi framework, librerie e linguaggi si sono fatti strada sulla scena tecnologica e hanno lottato per ottenere l'adozione mainstream, ma un recente pezzo di tecnologia che ha visto un'enorme adozione da parte dei team di ingegneri del software in un breve periodo è GraphQL. Rilasciato da Facebook nel 2015, è stato implementato in più linguaggi di programmazione e ha portato alla creazione di diversi framework e librerie relative a GraphQL.
GraphQL è un linguaggio di query fortemente tipizzato per le API e un runtime per soddisfare le query con i dati esistenti. Consente ai client di eseguire query per molte risorse in un'unica richiesta richiedendo i campi obbligatori invece di effettuare richieste a più endpoint.
Apollo Server è un server GraphQL open source che fornisce un modo semplice per creare un'API GraphQL in grado di utilizzare dati provenienti da più origini, inclusi diversi database e persino API REST.
MongoDB Atlas è una piattaforma dati applicativa completamente gestita che gestisce la creazione, la gestione e la distribuzione di MongoDB nel cloud. Fornisce una facile distribuzione dei database MongoDB a vari provider di servizi cloud con diversi strumenti per la gestione dei database MongoDB in un ambiente di produzione.
In questo tutorial impareremo come creare e distribuire un server GraphQL connesso a un'origine dati MongoDB. Alla fine di questo tutorial, avrai creato un'API GraphQL funzionale utilizzando Apollo Server e MongoDB Atlas e l'avrai distribuita alla produzione su Koyeb.
Requisiti
Per seguire con successo questo tutorial, hai bisogno di quanto segue:
- Una macchina di sviluppo con Node.js installato. L'app demo in questo tutorial utilizza la versione 16.14.0 di Node.js
- Una macchina di sviluppo con Git installato
- Un account Atlas MongoDB
- Un account Koyeb per distribuire l'applicazione
Passaggi
I passaggi per creare un'API GraphQL con Apollo DataSource e MongoDB Atlas e distribuirla alla produzione su Koyeb includono:
- Crea un database MongoDB utilizzando MongoDB Atlas
- Imposta il progetto
- Crea un server GraphQL utilizzando Apollo Server
- Collega il server GraphQL al database MongoDB
- Utilizza MongoDB come origine dati GraphQL
- Distribuisci su Koyeb
Crea un database MongoDB utilizzando Mongo Atlas
MongoDB Atlas offre la possibilità di creare database MongoDB distribuiti nel Cloud con pochi clic e, in questa sezione, creerai un database MongoDB utilizzando MongoDB Atlas.
Dopo aver effettuato l'accesso al tuo account Atlas MongoDB, fai clic sul pulsante "Crea un database" nella pagina "Distribuzioni dati" ed esegui i seguenti passaggi:
- Fai clic sul pulsante "Crea" sul tipo di distribuzione preferito.
- Seleziona un provider Cloud e una regione preferiti o utilizza le opzioni preselezionate.
- Inserisci un nome cluster o utilizza il nome cluster predefinito.
- Fai clic sul pulsante "Crea cluster".
- Seleziona l'opzione di autenticazione "Nome utente e password", inserisci un nome utente e una password e fai clic sul "pulsante Crea utente". Conserva il nome utente e la password in un luogo sicuro per un uso successivo.
- Inserisci "0.0.0.0/0" senza virgolette nel campo Indirizzo IP della sezione Elenco di accesso IP e fai clic sul pulsante "Aggiungi voce".
- Fai clic sul pulsante "Termina e chiudi" e poi sul pulsante "Vai ai database". Verrai reindirizzato alla pagina "Data Deployments", con il tuo nuovo cluster MongoDB ora visibile.
- Fai clic sul pulsante "Connetti" accanto al nome del tuo cluster MongoDB, seleziona l'opzione "Connetti la tua applicazione" e copia la stringa di connessione al database in un luogo sicuro per un uso successivo.
Seguendo i passaggi precedenti, hai creato un database MongoDB per leggere e archiviare i dati per l'API GraphQL. Nella sezione successiva, configurerai il progetto e installerai le librerie e le dipendenze necessarie.
Configura il progetto
In questa sezione, imposterai un progetto npm e installerai le dipendenze necessarie per creare il server GraphQL demo per questo tutorial. Il server GraphQL esporrà un'API GraphQL che legge e scrive i dati dei filmati da e verso il database MongoDB creato nella sezione precedente. Inizia creando una directory principale per il progetto sulla tua macchina di sviluppo. Per farlo, esegui il comando seguente nella finestra del tuo terminale:
mkdir graphql_movies
I graphql_movies
la directory creata dal comando sopra è la directory principale per l'applicazione demo. Quindi, passa a graphql_movies
directory e inizializzare un repository Git nella directory eseguendo il comando seguente nella finestra del terminale:
cd graphql_movies
git init
Il primo comando sopra ti porta nel graphql_movies
directory nel tuo terminale, mentre il secondo comando inizializza un repository Git per tenere traccia delle modifiche nel graphql_movies
directory. Quindi, crea un progetto npm in graphql_movies
directory eseguendo il comando seguente nella finestra del terminale:
npm init --yes
Esecuzione di npm init
il comando inizializza un progetto npm vuoto e crea un package.json
file nella directory principale. Il --yes
flag risponde automaticamente "sì" a tutti i prompt generati da npm.
Con un progetto npm ora attivo, vai avanti e installa le librerie e i pacchetti necessari per creare l'API GraphQL. Nella finestra del tuo terminale, esegui i comandi seguenti:
npm install apollo-server graphql mongoose apollo-datasource-mongodb dotenv rimraf
npm install -D @babel/preset-env @babel/core @babel/node @babel/cli
L'npm install
il comando sopra installa 10 pacchetti nel progetto e li aggiunge al package.json
del progetto file. Il primo comando installa le dipendenze necessarie per eseguire l'app, mentre il secondo installa le dipendenze necessarie durante lo sviluppo dell'app. Le dipendenze installate includono:
- apollo-server:una libreria open source per la creazione di server GraphQL.
- graphql:l'implementazione JavaScript della specifica GraphQL.
- mongoose:un mappatore di documenti oggetto per MongoDB.
- apollo-datasource-mongodb:una libreria di origini dati Apollo per MongoDB.
- dotenv:una libreria per la gestione delle variabili d'ambiente.
- rimraf:una libreria per l'esecuzione di UNIX
rm -rf
comando in Node.js.
Le altre librerie installate per lo sviluppo includono una serie di babel
librerie per eseguire e trasferire codice JavaScript moderno.
Quindi, crea un .babelrc
file nella directory principale del progetto e aggiungere il codice seguente al file:
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": "3.0.0"
}
]
]
}
Il codice sopra indica a Babel come transpilare l'ultimo codice JavaScript presente nell'app utilizzando env
di Babel opzioni di configurazione.
Infine, crea un src
cartella nella directory principale del progetto. Questo src
cartella conterrà tutti i file di progetto. Con queste modifiche, la struttura del progetto è a posto e, nella sezione successiva, creerai un server GraphQL utilizzando la libreria Apollo Server.
Crea un server GraphQL utilizzando Apollo Server
In questa sezione creerai un server GraphQL utilizzando Apollo Server. La libreria Apollo Server viene fornita con un server Express integrato e può eseguire query e mutazioni GraphQL. Fornisce inoltre una sandbox interna al browser per la connessione a un server GraphQL, la scrittura e l'esecuzione di query GraphQL, la visualizzazione dei risultati delle query e l'esplorazione dello schema GraphQL del server.
Un server GraphQL è costituito da uno schema GraphQL che definisce la struttura della sua API e da risolutori che implementano la struttura dello schema. Uno schema GraphQL è costituito da types
, che descrive i dati che possono essere interrogati e restituiti dal server GraphQL. GraphQL fornisce un linguaggio di definizione dello schema (SDL) utilizzato per definire uno schema GraphQL. Utilizzando l'SDL di GraphQL, un tipo di film può essere definito come segue:
type Movie {
_id: ID!
title: String!
rating: Float!
year: Int!
}
Il Movie
tipo sopra definisce i quattro campi che possono essere interrogati su un film e il loro tipo restituito. GraphQL ha anche tre tipi di radice; query
, mutation
e subscription
. Questi tre tipi servono come punti di ingresso a un server GraphQL e definiscono le possibili operazioni eseguibili in un server GraphQL. La query
type è per le operazioni di recupero dati, la mutation
type è per le operazioni di creazione o modifica dei dati e l'subscription
type è per operazioni di recupero dati in tempo reale.
Per creare uno schema per il server GraphQL, crea un typeDefs.js
file nel src
cartella e aggiungere il seguente codice al file:
import { gql } from 'apollo-server';
export const typeDefs = gql`
type Movie {
_id: ID!
title: String!
rating: Float!
year: Int!
}
type Query {
getMovies: [Movie!]!,
getMovie(id: ID!): Movie!
}
type Mutation {
createMovie(title: String!, rating: Float!, year: Int!): Movie!
}
`;
Il codice sopra è una definizione del tipo di schema GraphQL e definisce tre tipi GraphQL; Movie
, Query
e Mutation
. La Query
e Mutation
tipi sono i tipi radice, mentre il Movie
la mutazione definisce i campi interrogabili per i record di film.
La Query
digitare nella definizione dello schema sopra include i seguenti campi:
getMovies
:Questo campo restituisce un array di uno o piùMovie
digitare oggetti.getMovie
:Questo campo accetta unID
argomento e restituisce un singoloMovie
digitare oggetto.
Inoltre, la Mutation
tipo include un createMovie
campo che accetta un title
, rating
e un year
argomento e restituisce un Movie
tipo oggetto. Questi campi rappresentano le query e le mutazioni accettate dal server GraphQL.
Quando vengono eseguite le query e le mutazioni nei tipi radice, GraphQL si aspetta che le rispettive funzioni di risoluzione raccolgano e restituiscano i dati corrispondenti al tipo restituito dello schema. Per aggiungere funzioni di risoluzione, crea un resolvers.js
file nel src
directory e aggiungere il seguente codice al file:
const movies = [{
_id: "12345",
title: "Sinder Twindler",
year: 2022,
rating: 6.5,
}];
export const resolvers = {
Query: {
getMovies: (_root, _args, _context, _info) => {
return movies;
},
getMovie: (_root, { id }, _context, _info) => {
return movies.find(({ _id }) => _id === id);
}
},
Mutation: {
createMovie: (_root, args, _context, _info) => {
const randomId = Math.random().toString().split('.')[1];
const newMovie = { ...args, _id: randomId }
movies.push(newMovie);
return newMovie;
}
}
}
Nel codice sopra, inizializziamo una matrice di filmati che funge da origine dati temporanea. In aggiunta a ciò, esportiamo un resolvers
oggetto con Query
e Mutation
proprietà che corrispondono a Query
e Mutation
tipi nella definizione dello schema. Le due proprietà del risolutore includono funzioni che corrispondono alle operazioni dichiarate nella Query
e Mutation
tipi. Queste funzioni del resolver eseguono azioni specifiche sull'origine dati e restituiscono i dati richiesti.
Una funzione risolutore GraphQL accetta quattro argomenti:
root
:questo argomento contiene i risultati di eventuali risolutori eseguiti in precedenza.args
:questo argomento contiene i parametri per una query GraphQL.context
:questo argomento contiene dati/oggetti a cui è possibile accedere/condividere tra le funzioni del risolutore.info
:questo argomento contiene informazioni sulla query o la mutazione GraphQL in esecuzione.
Lo schema e i resolver creati devono essere collegati a un server per diventare funzionali. Nel src
directory, crea un index.js
file e aggiungi la seguente parte di codice al file:
import { ApolloServer } from 'apollo-server';
import { typeDefs } from './typeDefs'
import { resolvers } from './resolvers'
const server = new ApolloServer({typeDefs, resolvers})
server.listen({ port: process.env.PORT || 4000 }).then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
Il codice sopra importa e crea un'istanza di Apollo Server. Lo schema (typeDefs
) e anche i risolutori vengono importati nel file e passati all'istanza di Apollo Server. Infine, listen
di Apollo Server il metodo avvia il server web sulla porta fornita o sulla porta 4000 se non viene fornita alcuna porta.
Per eseguire il server, aggiungi lo script seguente a package.json
file che si trova nella directory principale:
{
...
"scripts": {
…
"start:dev": "babel-node src/index.js"
},
...
}
start:dev
lo script precedente esegue il codice in src/index.js
file utilizzando il babel-node
pacchetto. Per eseguire lo script, esegui il comando seguente nella finestra del terminale:
npm run start:dev
Il comando precedente avvia il server web, che viene eseguito sulla porta 4000. L'esecuzione del comando dovrebbe restituire la risposta seguente:
🚀 Server ready at http://localhost:4000/
Per vedere la pagina di destinazione di Apollo Server, visita http://localhost:4000/
nel tuo browser. Dovresti vedere una pagina come quella qui sotto:
Nella pagina di destinazione, fai clic sul pulsante "Interroga il tuo server" per essere reindirizzato alla sandbox del browser. Dovresti vedere una pagina come quella qui sotto, con una query GraphQL precompilata:
La sandbox è composta da tre pannelli; il pannello di sinistra mostra lo schema dell'API GraphQL con le query e le mutazioni disponibili, il pannello centrale serve per scrivere ed eseguire query e il pannello di destra per visualizzare i risultati delle query. Sostituisci la query nella tua sandbox con il codice seguente:
query ExampleQuery {
getMovies {
_id
title
year
rating
}
}
Il codice sopra aggiunge campi extra a ExampleQuery
interrogazione. Per eseguire la query, fare clic sul pulsante "ExampleQuery" per eseguire la query. Dovresti vedere la risposta nel pannello di destra.
In questa sezione è stato creato un server GraphQL con query e mutazioni. Nella sezione successiva, collegherai il server GraphQL a un database MongoDB.
Collega il server GraphQL al database Mongo
Le funzioni del risolutore nel server GraphQL attualmente recuperano i dati da un'origine dati codificata anziché dal database MongoDB creato nella prima sezione. In questa sezione, collegherai il server GraphQL al database MongoDB e creerai anche un modello di mangusta per rappresentare un documento di film su MongoDB.
Innanzitutto, crea un .env
nella directory principale del progetto e aggiungere il codice seguente al file dove <username>
e <password>
rappresenta il tuo utente del database MongoDB e la sua password:
MONGODB_URI="mongodb+srv://<username>:<password>@apollogql-demo.kk9qw.mongodb.net/apollogql-db?retryWrites=true&w=majority"
Il codice sopra rende disponibile la stringa di connessione al database MongoDB come variabile di ambiente. Il .env
il file non deve essere vincolato a git poiché contiene dati segreti.
Quindi, sostituisci il codice in src/index.js
file con quanto segue:
import 'dotenv/config'
import mongoose from 'mongoose';
import { ApolloServer } from 'apollo-server';
import { typeDefs } from './typeDefs';
import { resolvers } from './resolvers';
const uri = process.env.MONGODB_URI
const main = async () => {
await mongoose.connect(uri, { useNewUrlParser: true, useUnifiedTopology: true })
};
main()
.then(console.log('🎉 connected to database successfully'))
.catch(error => console.error(error));
const server = new ApolloServer({ typeDefs, resolvers })
server.listen({ port: process.env.PORT || 4000 }).then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
Il codice sopra importa il dotenv
config e mongoose
pacchetto nel index.js
file. Importazione di dotenv
config crea le variabili di ambiente nel .env
file accessibile tramite process.env
oggetto. Il valore del MONGODB_URI
si accede alla variabile di ambiente tramite process.env
e memorizzato in un uri
variabile e una funzione asincrona main
viene dichiarato per creare una connessione al database MongoDB utilizzando il connect
di mongoose funzione e il uri
stringa di connessione. Il main()
viene quindi chiamata la funzione per aprire una connessione al database MongoDB.
🎉 connected to database successfully
🚀 Server ready at http://localhost:4000/
Infine, crea un models
nella cartella src
cartella e al suo interno, crea un movie.js
file. Aggiungi il codice qui sotto al file:
import mongoose from "mongoose";
export const Movie = mongoose.model("Movie", {
title: String,
rating: Number,
year: Number,
});
Il codice sopra crea un Movie
modello e funge da interfaccia per la creazione e la manipolazione di documenti nel database MongoDB. Questo è l'ultimo passo per rendere il database MongoDB l'origine dati per il server GraphQL. Nella sezione successiva, passerai l'origine dati del server GraphQL dall'array codificato al tuo database MongoDB.
Usa MongoDB come origine dati GraphQL
L'origine dati corrente per il server GraphQL è un array hardcoded e in questa sezione lo sostituirai con il tuo database MongoDB. Per farlo, inizia creando un dataSources
nella cartella src
cartella. In dataSources
cartella, crea un movies.js
file e aggiungi il seguente codice al file:
import { MongoDataSource } from 'apollo-datasource-mongodb'
export default class Movies extends MongoDataSource {
async getMovies() {
return await this.model.find();
}
async getMovie(id) {
return await this.findOneById(id);
}
async createMovie({ title, rating, year }) {
return await this.model.create({ title, rating, year });
}
}
Il codice sopra dichiara un Movie
classe di origine dati che estende il MongoDataSource
classe fornita da apollo-datasource-mongodb
pacchetto. I Movie
l'origine dati contiene tre metodi per ciascuna delle query e delle mutazioni esistenti. getMovies
e createMovie
i metodi utilizzano il modello del filmato creato nella sezione precedente per leggere e inserire dati nel database MongoDB e getMovie
il metodo utilizza il findOneById
metodo fornito da MongoDataSource
class per recuperare un documento dalla raccolta MongoDB che corrisponde all'id
fornito argomento.
Quindi, sostituisci il codice in src/index.js
file con il codice qui sotto:
import 'dotenv/config'
import mongoose from 'mongoose';
import { ApolloServer } from 'apollo-server';
import { typeDefs } from './typeDefs';
import { resolvers } from './resolvers';
import { Movie as MovieModel } from './models/movie';
import Movies from './dataSources/movies';
const uri = process.env.MONGODB_URI
const main = async () => {
await mongoose.connect(uri, { useNewUrlParser: true, useUnifiedTopology: true })
};
main()
.then(console.log('🎉 connected to database successfully'))
.catch(error => console.error(error));
const dataSources = () => ({
movies: new Movies(MovieModel),
});
const server = new ApolloServer({ typeDefs, resolvers, dataSources })
server.listen({ port: process.env.PORT || 4000 }).then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
Il codice aggiornato sopra importa il Movie
modello e i Movie
classe di origine dati in src/index.js
file. Dopo la connessione al database MongoDB, un dataSources
viene creata la funzione. Questa funzione restituisce un oggetto contenente un'istanza dei Movie
origine dati che riceve il Movie
modello come parametro. Le dataSources
la funzione viene quindi passata all'istanza di Apollo Server, creando i Movies
istanza di origine dati disponibile all'interno di ogni funzione di risoluzione.
Per sostituire l'origine dati codificata con il Movie
origine dati, sostituire il codice in src/resolvers.js
file con il codice qui sotto:
export const resolvers = {
Query: {
getMovies: async (_, _args, { dataSources: { movies } }) => {
return movies.getMovies();
},
getMovie: async (_, { id }, { dataSources: { movies } }) => {
return movies.getMovie(id);
}
},
Mutation: {
createMovie: async (_, args, { dataSources: { movies } }) => {
return movies.createMovie(args)
}
}
}
Nel codice aggiornato sopra, i Movie
istanza dell'origine dati passata ad Apollo Server in src/index.js
è disponibile nelle funzioni del resolver tramite dataSources
proprietà dell'oggetto contesto condiviso. Ciascuna funzione del resolver richiama il rispettivo metodo nell'origine dati per eseguire l'operazione specificata sul database MongoDB.
Qualsiasi query eseguita a questo punto restituirà un risultato vuoto poiché il database MongoDB è attualmente vuoto. Riavvia il tuo server, quindi visita il tuo account Mongo Atlas nel tuo browser. Nella pagina "Distribuzioni database" di MongoDB, seleziona il cluster di database e fai clic sulla scheda "Raccolte". Nella scheda "Raccolte", fai clic sul pulsante "INSERIRE DOCUMENTO" e aggiungi tutti i documenti di film che desideri.
Nella sandbox di Apollo Server, esegui ExampleQuery
dalla sezione precedente. Dovresti ottenere un elenco di tutti i documenti del film nella tua raccolta Mongo DB. In questa sezione, hai utilizzato il tuo database MongoDB come origine dati per il tuo server GraphQL. Nella prossima sezione, distribuirai il tuo server GraphQL online su Koyeb.
Distribuisci su Koyeb
Il primo passo verso la distribuzione del server GraphQL su Koyeb consiste nell'aggiungere gli script npm necessari per creare il codice in produzione. Aggiungi i seguenti script di seguito al tuo package.json
file:
"scripts": {
...
"prebuild": "rimraf dist && mkdir dist",
"build": "babel src -d dist",
"start": "node ./dist/index.js"
}
I tre script npm aggiunti sopra includono:
- Un
prebuild
script per assicurarsi che sia presente unadist
vuota directory prima dellabuild
lo script viene eseguito. - Una
build
script che traspone tutto il codice insrc
directory nella sintassi JavaScript ES5 nelladist
directory con l'aiuto dibabel
pacchetto. - Un
start
script che avvia il server.
Quindi, crea un repository GitHub per il tuo server GraphQL, quindi esegui i comandi seguenti nella finestra del tuo terminale:
git add --all
git commit -m "Complete GraphQL server with MongoDB data source."
git remote add origin [email protected]<YOUR_GITHUB_USERNAME>/<YOUR_REPOSITORY_NAME>.git
git branch -M main
git push -u origin main
Sul tuo pannello di controllo Koyeb, vai a Secrets
scheda e crea un nuovo segreto. Inserisci MONGODB_URI
come nome segreto e la stringa di connessione MongoDB come valore. Quindi, vai a Overview
scheda e fai clic sul pulsante "Crea app" per avviare il processo di creazione dell'app.
Nella pagina di creazione dell'app:
- Seleziona GitHub come metodo di distribuzione.
- Nel menu a discesa dei repository, seleziona il repository GitHub per il tuo codice.
- Seleziona il ramo che desideri distribuire. Per esempio.
main
. - Nella sezione delle variabili d'ambiente, fai clic sul pulsante Aggiungi variabile d'ambiente.
- Seleziona il
Secret
digita, inserisciMONGODB_URI
come chiave e seleziona ilMONGODB_URI
segreto creato in precedenza come valore. - Aggiungi una variabile d'ambiente in chiaro con la chiave
PORT
e il valore8080
. - Assegna un nome alla tua app. Per esempio.
graphql-apollo-server
e fai clic sul pulsante "Crea app".
Durante la creazione dell'app, run
e build
le opzioni di comando sono state ignorate poiché la piattaforma Koyeb è in grado di rilevare la build
e start
script nel package.json
file ed eseguirli automaticamente. Facendo clic sul pulsante "Crea app" si reindirizza alla pagina di distribuzione, dove è possibile monitorare il processo di distribuzione dell'app. Una volta completata la distribuzione e superati tutti i controlli di integrità necessari, puoi accedere al tuo URL pubblico.
Testa la tua API GraphQL
Utilizzando il tuo strumento di test API preferito o questo playground online di GraphiQL, crea un getMovies
query GraphQL al tuo URL pubblico. Dovresti ottenere una risposta di tutti i documenti di film sul tuo database MongoDB.
Conclusione
Questo è tutto! Hai creato e distribuito con successo un server GraphQL con Apollo Server e un'origine dati MongoDB su Koyeb. Sentiti libero di aggiungere più query e mutazioni al tuo server GraphQL. Dal momento che abbiamo distribuito su Koyeb utilizzando la distribuzione basata su git, una nuova build verrà automaticamente attivata e distribuita su Koyeb ogni volta che invii le modifiche al tuo repository GitHub.
Le modifiche saranno attive non appena la distribuzione avrà superato tutti i controlli di integrità necessari. In caso di errore durante la distribuzione, Koyeb mantiene l'ultima distribuzione funzionante in produzione per garantire che l'applicazione sia sempre attiva e funzionante.
Grazie all'implementazione su Koyeb, la nostra applicazione beneficia del bilanciamento del carico globale nativo, della scalabilità automatica, della riparazione automatica e della crittografia HTTPS (SSL) automatica senza alcuna configurazione da parte nostra.
Se desideri guardare il codice per l'applicazione demo, puoi trovarlo qui.