Introduktion
I løbet af de seneste år har nye rammer, biblioteker og sprog fundet vej til den teknologiske scene og har kæmpet for at samle mainstream-adoption, men et nyligt stykke teknologi, der har oplevet enorm adoption af softwareingeniørteams over en kort periode, er GraphQL. Udgivet af Facebook i 2015, er det blevet implementeret i flere programmeringssprog og har ført til oprettelsen af flere GraphQL-relaterede rammer og biblioteker.
GraphQL er et stærkt indtastet forespørgselssprog til API'er og en runtime til at opfylde forespørgsler med eksisterende data. Det giver klienter mulighed for at forespørge efter mange ressourcer i en enkelt anmodning ved at anmode om obligatoriske felter i stedet for at foretage anmodninger til flere slutpunkter.
Apollo Server er en open source GraphQL-server, der giver en nem måde at bygge en GraphQL API, der kan bruge data fra flere kilder, herunder flere databaser og endda REST API'er.
MongoDB Atlas er en fuldt administreret applikationsdataplatform, der håndterer oprettelse, administration og implementering af MongoDB i skyen. Det giver nem udrulning af MongoDB-databaser til forskellige cloud-tjenesteudbydere med flere værktøjer til at administrere MongoDB-databaser i et produktionsmiljø.
I denne vejledning lærer vi, hvordan man bygger og implementerer en GraphQL-server, der er forbundet til en MongoDB-datakilde. I slutningen af denne øvelse vil du have bygget en funktionel GraphQL API ved hjælp af Apollo Server og MongoDB Atlas og implementeret den til produktion på Koyeb.
Krav
For at kunne følge denne vejledning skal du bruge følgende:
- En udviklingsmaskine med Node.js installeret. Demo-appen i dette selvstudie bruger version 16.14.0 af Node.js
- En udviklingsmaskine med Git installeret
- En MongoDB Atlas-konto
- En Koyeb-konto til at implementere applikationen
Trin
Trinene til at oprette en GraphQL API med Apollo DataSource og MongoDB Atlas og implementere den til produktion på Koyeb inkluderer:
- Opret en MongoDB-database ved hjælp af MongoDB Atlas
- Konfigurer projektet
- Opret en GraphQL-server ved hjælp af Apollo Server
- Forbind GraphQL-serveren til MongoDB-databasen
- Brug MongoDB som en GraphQL-datakilde
- Implementer til Koyeb
Opret en MongoDB-database ved hjælp af Mongo Atlas
MongoDB Atlas tilbyder muligheden for at oprette MongoDB-databaser implementeret til skyen med blot et par klik, og i dette afsnit vil du oprette en MongoDB-database ved hjælp af MongoDB Atlas.
Mens du er logget ind på din MongoDB Atlas-konto, skal du klikke på knappen "Byg en database" på siden "Dataimplementeringer" og udføre følgende trin:
- Klik på knappen "Opret" på din foretrukne implementeringstype.
- Vælg en foretrukken cloud-udbyder og region, eller brug de forudvalgte muligheder.
- Indtast et klyngenavn, eller brug standardklyngenavnet.
- Klik på knappen "Opret klynge".
- Vælg godkendelsesmuligheden "Brugernavn og adgangskode", indtast et brugernavn og en adgangskode, og klik på knappen "Opret bruger". Gem brugernavnet og adgangskoden et sikkert sted til senere brug.
- Indtast "0.0.0.0/0" uden anførselstegn i feltet IP-adresse i afsnittet IP-adgangsliste, og klik på knappen "Tilføj post".
- Klik på knappen "Udfør og luk" og derefter på knappen "Gå til databaser". Du vil blive omdirigeret til siden "Dataimplementeringer", med din nye MongoDB-klynge nu synlig.
- Klik på knappen "Forbind" ved siden af dit MongoDB-klyngenavn, vælg indstillingen "Forbind din applikation", og kopier din databaseforbindelsesstreng til et sikkert sted til senere brug.
Ved at følge ovenstående trin har du oprettet en MongoDB-database til at læse og gemme data til GraphQL API. I næste afsnit vil du opsætte projektet og installere de nødvendige biblioteker og afhængigheder.
Konfigurer projektet
I dette afsnit vil du opsætte et npm-projekt og installere de nødvendige afhængigheder til at bygge demo-GraphQL-serveren til denne øvelse. GraphQL-serveren vil afsløre en GraphQL API, der læser og skriver filmdata fra og til MongoDB-databasen oprettet i det foregående afsnit. Start med at oprette en rodmappe til projektet på din udviklingsmaskine. For at gøre det skal du køre kommandoen nedenfor i dit terminalvindue:
mkdir graphql_movies
graphql_movies
mappe, der er oprettet af kommandoen ovenfor, er rodmappen til demoapplikationen. Skift derefter til graphql_movies
mappe og initialiser et Git-lager i mappen ved at køre kommandoen nedenfor i dit terminalvindue:
cd graphql_movies
git init
Den første kommando ovenfor flytter dig ind i graphql_movies
mappe i din terminal, mens den anden kommando initialiserer et Git-lager for at spore ændringer i graphql_movies
vejviser. Opret derefter et npm-projekt i graphql_movies
mappe ved at køre kommandoen nedenfor i dit terminalvindue:
npm init --yes
Kører npm init
kommando initialiserer et tomt npm-projekt og opretter en pakke.json
fil i rodmappen. --yes
flaget svarer automatisk "ja" til alle de prompter, der er rejst af npm.
Med et npm-projekt nu på plads, skal du gå videre og installere de biblioteker og pakker, der kræves for at bygge GraphQL API. Kør kommandoerne nedenfor i dit terminalvindue:
npm install apollo-server graphql mongoose apollo-datasource-mongodb dotenv rimraf
npm install -D @babel/preset-env @babel/core @babel/node @babel/cli
npm-installationen
kommandoen ovenfor installerer 10 pakker på projektet og tilføjer dem til projektets package.json
fil. Den første kommando installerer afhængigheder, der kræves for at køre appen, mens den anden installerer afhængigheder, der er nødvendige, mens appen udvikles. De installerede afhængigheder inkluderer:
- apollo-server:Et open source-bibliotek til at bygge GraphQL-servere.
- graphql:JavaScript-implementeringen af GraphQL-specifikationen.
- mongoose:An Object Document Mapper til MongoDB.
- apollo-datasource-mongodb:Et Apollo-datakildebibliotek til MongoDB.
- dotenv:Et bibliotek til håndtering af miljøvariabler.
- rimraf:Et bibliotek til at køre UNIX
rm -rf
kommando i Node.js.
De andre biblioteker, der er installeret til udvikling, inkluderer et væld af babel
biblioteker til at køre og transpilere moderne JavaScript-kode.
Opret derefter en .babelrc
fil i projektets rodmappe og tilføj følgende kode til filen:
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": "3.0.0"
}
]
]
}
Ovenstående kode instruerer Babel om, hvordan man transpilerer den seneste JavaScript-kode, der findes i appen ved hjælp af Babels env
konfigurationsmuligheder.
Til sidst skal du oprette en src
mappe i projektets rodmappe. Denne src
mappen vil indeholde alle projektfilerne. Med disse ændringer er projektstrukturen på plads, og i næste afsnit vil du oprette en GraphQL-server ved hjælp af Apollo Server-biblioteket.
Opret en GraphQL-server ved hjælp af Apollo Server
I dette afsnit vil du oprette en GraphQL-server ved hjælp af Apollo Server. Apollo Server-biblioteket leveres med en indbygget Express-server og kan udføre GraphQL-forespørgsler og mutationer. Det giver også en sandkasse i browseren til at oprette forbindelse til en GraphQL-server, skrive og udføre GraphQL-forespørgsler, se forespørgselsresultater og udforske serverens GraphQL-skema.
En GraphQL-server består af et GraphQL-skema, der definerer strukturen af dens API og resolvere, der implementerer skemastrukturen. Et GraphQL-skema består af typer
, som beskriver de data, der kan forespørges og returneres af GraphQL-serveren. GraphQL giver et skemadefinitionssprog (SDL), der bruges til at definere et GraphQL-skema. Ved at bruge GraphQL's SDL kan en filmtype defineres som følger:
type Movie {
_id: ID!
title: String!
rating: Float!
year: Int!
}
Film
type ovenfor definerer de fire felter, der kan forespørges på en film og deres returtype. GraphQL har også tre rodtyper; forespørgsel
, mutation
og abonnement
. Disse tre typer tjener som indgangspunkter til en GraphQL-server og definerer de mulige eksekverbare operationer i en GraphQL-server. forespørgslen
typen er til datahentningsoperationer, mutationen
type er til operationer til oprettelse eller ændring af data, og abonnementet
typen er til datahentningsoperationer i realtid.
For at oprette et skema til GraphQL-serveren skal du oprette en typeDefs.js
fil i src
mappe og tilføj følgende kode til filen:
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!
}
`;
Ovenstående kode er en GraphQL-skematypedefinition og definerer tre GraphQL-typer; Film
, Forespørgsel
og Mutation
. Forespørgsel
og Mutation
typer er rodtyperne, mens Film
mutation definerer de forespørgselsfelter for filmoptagelser.
Forespørgsel
type i skemadefinitionen ovenfor omfatter følgende felter:
getMovies
:Dette felt returnerer en matrix af en eller flereFilm
skriv objekter.getMovie
:Dette felt accepterer etID
argument og returnerer en enkeltFilm
skriv objekt.
Derudover er Mutation
typen inkluderer en createMovie
felt, der accepterer en titel
, rating
og et år
argument og returnerer en Film
type objekt. Disse felter repræsenterer de forespørgsler og mutationer, der accepteres af GraphQL-serveren.
Når forespørgsler og mutationer i rodtyperne udføres, forventer GraphQL, at deres respektive resolverfunktioner henter og returnerer data svarende til skemareturtypen. For at tilføje resolver-funktioner skal du oprette en resolvers.js
fil i src
mappe og tilføj følgende kode til filen:
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;
}
}
}
I koden ovenfor initialiserer vi en række film, der fungerer som en midlertidig datakilde. Ud over det eksporterer vi en resolvers
objekt med Forespørgsel
og Mutation
egenskaber, der matcher Forespørgslen
og Mutation
typer i skemadefinitionen. De to resolveregenskaber inkluderer funktioner, der matcher de operationer, der er erklæret i Query
og Mutation
typer. Disse resolverfunktioner udfører specifikke handlinger på datakilden og returnerer de anmodede data.
En GraphQL-resolverfunktion accepterer fire argumenter:
root
:Dette argument indeholder resultaterne af tidligere kørte resolvere.args
:Dette argument indeholder parametrene for en GraphQL-forespørgsel.kontekst
:Dette argument indeholder data/objekter, der kan tilgås/deles på tværs af resolverfunktioner.info
:Dette argument indeholder information om GraphQL-forespørgslen eller mutationen, der udføres.
Skemaet og de oprettede resolvere skal forbindes til en server for at blive funktionelle. I src
mappe, skal du oprette en index.js
fil og tilføj følgende stykke kode til filen:
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}`);
});
Ovenstående kode importerer og opretter en forekomst af Apollo-serveren. Skemaet (typeDefs
) og resolvere importeres også til filen og sendes til Apollo Server-instansen. Endelig Apollo Servers lyt
metoden starter webserveren på den angivne port eller port 4000, hvis der ikke er nogen port.
For at køre serveren skal du tilføje scriptet nedenfor til package.json
fil placeret i rodmappen:
{
...
"scripts": {
…
"start:dev": "babel-node src/index.js"
},
...
}
start:dev
scriptet ovenfor kører koden i src/index.js
fil ved hjælp af babel-node
pakke. For at køre scriptet skal du køre kommandoen nedenfor i dit terminalvindue:
npm run start:dev
Kommandoen ovenfor starter webserveren, som kører på port 4000. Kørsel af kommandoen skulle returnere nedenstående svar:
🚀 Server ready at http://localhost:4000/
Besøg http://localhost:4000/
for at se Apollo Server-landingssiden i din browser. Du bør se en side som den nedenfor:
På landingssiden skal du klikke på knappen "Forespørg på din server" for at blive omdirigeret til sandkassen i browseren. Du bør se en side som den nedenfor med en forududfyldt GraphQL-forespørgsel:
Sandkassen består af tre paneler; det venstre panel viser skemaet for GraphQL API med tilgængelige forespørgsler og mutationer, det midterste panel er til at skrive og udføre forespørgsler, og det højre panel er til at se forespørgselsresultater. Erstat forespørgslen i din sandbox med koden nedenfor:
query ExampleQuery {
getMovies {
_id
title
year
rating
}
}
Ovenstående kode tilføjer ekstra felter til ExampleQuery
forespørgsel. For at udføre forespørgslen skal du klikke på knappen "ExampleQuery" for at køre forespørgslen. Du bør se svaret i højre panel.
I dette afsnit oprettede du en GraphQL-server med forespørgsler og mutationer. I næste afsnit vil du forbinde GraphQL-serveren til en MongoDB-database.
Forbind GraphQL-serveren til Mongo-databasen
Resolverfunktionerne i GraphQL-serveren henter i øjeblikket data fra en hårdkodet datakilde i stedet for MongoDB-databasen, der blev oprettet i den første sektion. I dette afsnit vil du forbinde GraphQL-serveren til MongoDB-databasen og også oprette en mongoose-model til at repræsentere et filmdokument på MongoDB.
Først skal du oprette en .env
fil i projektets rodbibliotek og tilføj følgende kode til filen hvor
MONGODB_URI="mongodb+srv://<username>:<password>@apollogql-demo.kk9qw.mongodb.net/apollogql-db?retryWrites=true&w=majority"
Koden ovenfor gør din MongoDB-databaseforbindelsesstreng tilgængelig som en miljøvariabel. .env
fil bør ikke være forpligtet til git, da den indeholder hemmelige data.
Udskift derefter koden i src/index.js
fil med følgende:
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}`);
});
Koden ovenfor importerer dotenv
config og mongoose
pakke ind i index.js
fil. Import af dotenv
config laver miljøvariablerne i .env
fil tilgængelig via process.env
objekt. Værdien af MONGODB_URI
miljøvariablen tilgås via process.env
og gemt i en uri
variabel og en asynkron funktion main
er erklæret at oprette en forbindelse til MongoDB-databasen ved hjælp af mongoose connect
funktionen og uri
forbindelsesstreng. main()
funktionen kaldes derefter for at åbne en forbindelse til MongoDB-databasen.
🎉 connected to database successfully
🚀 Server ready at http://localhost:4000/
Til sidst skal du oprette en models
mappe i src
mappe, og inde i den skal du oprette en movie.js
fil. Tilføj koden nedenfor til filen:
import mongoose from "mongoose";
export const Movie = mongoose.model("Movie", {
title: String,
rating: Number,
year: Number,
});
Koden ovenfor opretter en Film
model, og den tjener som grænseflade til oprettelse og manipulation af dokumenter i MongoDB-databasen. Dette er det sidste skridt mod at gøre MongoDB-databasen til datakilden for GraphQL-serveren. I næste afsnit skifter du GraphQL-serverens datakilde fra det hårdtkodede array til din MongoDB-database.
Brug MongoDB som en GraphQL-datakilde
Den aktuelle datakilde til GraphQL-serveren er et hårdkodet array, og i dette afsnit vil du erstatte det med din MongoDB-database. For at gøre det, start med at oprette en dataSources
mappe i src
folder. I dataSources
mappe, skal du oprette en movies.js
fil og tilføj følgende kode til filen:
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 });
}
}
Koden ovenfor erklærer en Film
datakildeklasse, der udvider MongoDataSource
klasse leveret af apollo-datasource-mongodb
pakke. Film
datakilden indeholder tre metoder for hver af de eksisterende forespørgsler og mutationer. getMovies
og createMovie
metoder bruger filmmodellen oprettet i det foregående afsnit til at læse og indsætte data i MongoDB-databasen og getMovie
metoden bruger findOneById
metode leveret af MongoDataSource
klasse for at hente et dokument fra MongoDB-samlingen, der matcher det angivne id
argument.
Udskift derefter koden i src/index.js
fil med nedenstående kode:
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}`);
});
Den opdaterede kode ovenfor importerer Film
model og Film
datakildeklassen i src/index.js
fil. Efter at have oprettet forbindelse til MongoDB-databasen, en dataSources
funktion oprettes. Denne funktion returnerer et objekt, der indeholder en forekomst af Movies
datakilde, der modtager Film
model som parameter. datakilderne
funktionen sendes derefter til Apollo Server-instansen, hvilket gør Movies
datakildeinstans tilgængelig inden for hver resolverfunktion.
For at erstatte den hårdkodede datakilde med Film
datakilde, skal du erstatte koden i src/resolvers.js
fil med nedenstående kode:
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)
}
}
}
I den opdaterede kode ovenfor er Film
datakildeforekomst sendt til Apollo Server i src/index.js
fil er tilgængelig i resolverfunktionerne via dataSources
egenskaben for det delte kontekstobjekt. Hver resolverfunktion kalder sin respektive metode i datakilden for at udføre den specificerede operation på MongoDB-databasen.
Enhver forespørgsel foretaget på dette tidspunkt vil returnere et tomt resultat, da MongoDB-databasen i øjeblikket er tom. Genstart din server, og besøg derefter din Mongo Atlas-konto i din browser. På din MongoDB-side "Databaseimplementeringer" skal du vælge din databaseklynge og klikke på fanen "Samlinger". På fanen "Samlinger" skal du klikke på knappen "INDSÆT DOKUMENT" og tilføje så mange filmdokumenter, som du vil.
Kør ExampleQuery
i din Apollo Server-sandbox fra forrige afsnit. Du bør få en liste over alle filmdokumenterne i din Mongo DB-samling. I dette afsnit brugte du din MongoDB-database som en datakilde til din GraphQL-server. I næste afsnit vil du implementere din GraphQL-server online på Koyeb.
Implementer til Koyeb
Det første skridt mod at implementere GraphQL-serveren på Koyeb er at tilføje de npm-scripts, der er nødvendige for at bygge koden i produktionen. Tilføj følgende scripts nedenfor til din package.json
fil:
"scripts": {
...
"prebuild": "rimraf dist && mkdir dist",
"build": "babel src -d dist",
"start": "node ./dist/index.js"
}
De tre npm scripts tilføjet ovenfor inkluderer:
- En
prebuild
script for at sikre, at der er en tomdist
bibliotek førbuild
scriptet udføres. - En
build
script, der transpilerer al koden isrc
mappe til JavaScript ES5-syntaks tildist
bibliotek ved hjælp afbabel
pakke. - En
start
script, der starter serveren.
Opret derefter et GitHub-lager til din GraphQL-server, og kør derefter kommandoerne nedenfor i dit terminalvindue:
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
Gå til Secrets
på dit Koyeb kontrolpanel fanen og opret en ny hemmelighed. Indtast MONGODB_URI
som det hemmelige navn og din MongoDB-forbindelsesstreng som værdien. Gå derefter til Oversigt
fanen og klik på knappen `Opret app' for at starte processen til oprettelse af app.
På appoprettelsessiden:
- Vælg GitHub som din implementeringsmetode.
- Vælg GitHub-lageret til din kode i rullemenuen for repositories.
- Vælg den filial, du vil implementere. For eksempel.
hoved
. - I sektionen miljøvariable skal du klikke på knappen Tilføj miljøvariabel.
- Vælg
Hemmeligheden type, indtast MONGODB_URI
som nøglen og vælgMONGODB_URI
hemmelighed oprettet tidligere som værdien. - Tilføj en almindelig tekst-miljøvariabel med nøglen
PORT
og værdien8080
. - Giv din app et navn. For eksempel.
graphql-apollo-server
og klik på knappen "Opret app".
Mens du opretter appen, vises run
og build
kommandoindstillinger blev sprunget over, da Koyeb-platformen kan registrere build
og start
scripts i package.json
fil og udføre dem automatisk. Ved at klikke på knappen "Opret app" omdirigeres du til implementeringssiden, hvor du kan overvåge app-implementeringsprocessen. Når implementeringen er fuldført, og alle nødvendige sundhedstjek er bestået, kan du få adgang til din offentlige URL.
Test din GraphQL API
Brug dit foretrukne API-testværktøj eller denne online GraphiQL-legeplads til at lave en getMovies
GraphQL-forespørgsel til din offentlige URL. Du bør få et svar på alle filmdokumenter på din MongoDB-database.
Konklusion
Det er det! Du har med succes oprettet og implementeret en GraphQL-server med Apollo Server og en MongoDB-datakilde til Koyeb. Tilføj gerne flere forespørgsler og mutationer til din GraphQL-server. Da vi implementerede til Koyeb ved hjælp af git-drevet implementering, vil en ny build automatisk blive udløst og implementeret på Koyeb, hver gang du skubber dine ændringer til dit GitHub-lager.
Dine ændringer vil gå live, så snart din implementering består alle nødvendige sundhedstjek. I tilfælde af en fejl under implementeringen, vedligeholder Koyeb den seneste fungerende implementering i produktionen for at sikre, at din applikation altid er oppe og køre.
Ved at implementere på Koyeb drager vores applikation fordel af indbygget global belastningsbalancering, autoskalering, autohealing og automatisk HTTPS (SSL)-kryptering uden konfiguration fra vores side.
Hvis du gerne vil se på koden til demoapplikationen, kan du finde den her.