sql >> Databasteknik >  >> NoSQL >> MongoDB

Distribuera ett GraphQL API med MongoDB Atlas och Apollo Server på Koyeb

Inledning

Under de senaste åren har nya ramverk, bibliotek och språk hittat sin väg till den tekniska scenen och har kämpat för att samla in mainstream-antaganden, men en ny teknik som har antagits enormt av mjukvaruteknikteam under en kort period är GraphQL. Det släpptes av Facebook 2015 och har implementerats i flera programmeringsspråk och har lett till skapandet av flera GraphQL-relaterade ramverk och bibliotek.

GraphQL är ett starkt skrivet frågespråk för API:er och en körtid för att uppfylla frågor med befintliga data. Det tillåter klienter att fråga efter många resurser i en enda begäran genom att begära obligatoriska fält istället för att göra förfrågningar till flera slutpunkter.

Apollo Server är en GraphQL-server med öppen källkod som ger ett enkelt sätt att bygga ett GraphQL API som kan använda data från flera källor, inklusive flera databaser och till och med REST API:er.

MongoDB Atlas är en helt hanterad applikationsdataplattform som hanterar skapandet, hanteringen och driftsättningen av MongoDB i molnet. Det ger enkel distribution av MongoDB-databaser till olika molntjänsteleverantörer med flera verktyg för att hantera MongoDB-databaser i en produktionsmiljö.

I den här handledningen kommer vi att lära oss hur man bygger och distribuerar en GraphQL-server ansluten till en MongoDB-datakälla. I slutet av denna handledning kommer du att ha byggt ett funktionellt GraphQL API med Apollo Server och MongoDB Atlas och distribuerat det till produktion på Koyeb.

Krav

För att framgångsrikt följa denna handledning behöver du följande:

  • En utvecklingsmaskin med Node.js installerat. Demoappen i den här handledningen använder version 16.14.0 av Node.js
  • En utvecklingsmaskin med Git installerat
  • Ett MongoDB Atlas-konto
  • Ett Koyeb-konto för att distribuera programmet

Steg

Stegen för att skapa ett GraphQL API med Apollo DataSource och MongoDB Atlas och distribuera det till produktion på Koyeb inkluderar:

  1. Skapa en MongoDB-databas med MongoDB Atlas
  2. Konfigurera projektet
  3. Skapa en GraphQL-server med Apollo Server
  4. Anslut GraphQL-servern till MongoDB-databasen
  5. Använd MongoDB som en GraphQL-datakälla
  6. Distribuera till Koyeb

Skapa en MongoDB-databas med Mongo Atlas

MongoDB Atlas erbjuder möjligheten att skapa MongoDB-databaser som distribueras till molnet med bara några klick, och i det här avsnittet kommer du att skapa en MongoDB-databas med MongoDB Atlas.

När du är inloggad på ditt MongoDB Atlas-konto klickar du på knappen "Bygg en databas" på sidan "Datadistributioner" och utför följande steg:

  • Klicka på "Skapa"-knappen på din föredragna distributionstyp.
  • Välj en föredragen molnleverantör och region eller använd de förvalda alternativen.
  • Ange ett klusternamn eller använd standardklusternamnet.
  • Klicka på knappen "Skapa kluster".
  • Välj autentiseringsalternativet "Användarnamn och lösenord", ange ett användarnamn och lösenord och klicka på knappen "Skapa användare". Förvara användarnamnet och lösenordet på ett säkert ställe för senare användning.
  • Ange "0.0.0.0/0" utan citattecken i IP-adressfältet i avsnittet IP-åtkomstlista och klicka på knappen "Lägg till post".
  • Klicka på knappen "Slutför och stäng" och sedan på knappen "Gå till databaser". Du kommer att omdirigeras till sidan "Datadistributioner", med ditt nya MongoDB-kluster nu synligt.
  • Klicka på knappen "Anslut" bredvid ditt MongoDB-klusternamn, välj alternativet "Anslut din applikation" och kopiera din databasanslutningssträng till en säker plats för senare användning.

Genom att följa stegen ovan har du skapat en MongoDB-databas för att läsa och lagra data för GraphQL API. I nästa avsnitt kommer du att ställa in projektet och installera nödvändiga bibliotek och beroenden.

Konfigurera projektet

I det här avsnittet kommer du att ställa in ett npm-projekt och installera de nödvändiga beroenden för att bygga demo GraphQL-servern för den här handledningen. GraphQL-servern kommer att exponera ett GraphQL API som läser och skriver filmdata från och till MongoDB-databasen som skapades i föregående avsnitt. Börja med att skapa en rotkatalog för projektet på din utvecklingsmaskin. För att göra det, kör kommandot nedan i ditt terminalfönster:

mkdir graphql_movies

graphql_movies katalog skapad av kommandot ovan är rotkatalogen för demoapplikationen. Ändra sedan till graphql_movies katalog och initiera ett Git-förråd i katalogen genom att köra kommandot nedan i ditt terminalfönster:

cd graphql_movies
git init

Det första kommandot ovan flyttar dig till graphql_movies katalog i din terminal, medan det andra kommandot initierar ett Git-förråd för att spåra ändringar i graphql_movies katalog. Skapa sedan ett npm-projekt i graphql_movies katalog genom att köra kommandot nedan i ditt terminalfönster:

npm init --yes

Kör npm init kommandot initierar ett tomt npm-projekt och skapar en package.json filen i rotkatalogen. --yes flaggan svarar automatiskt "ja" på alla uppmaningar som höjs av npm.

Med ett npm-projekt nu på plats, fortsätt och installera de bibliotek och paket som krävs för att bygga GraphQL API. Kör kommandona nedan i ditt terminalfönster:

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 kommandot ovan installerar 10 paket i projektet och lägger till dem i projektets package.json fil. Det första kommandot installerar beroenden som krävs för att köra appen, medan det andra installerar beroenden som behövs när appen utvecklas. De beroenden som installeras inkluderar:

  • apollo-server:Ett bibliotek med öppen källkod för att bygga GraphQL-servrar.
  • graphql:JavaScript-implementeringen av GraphQL-specifikationen.
  • mongoose:En objektdokumentmappare för MongoDB.
  • apollo-datasource-mongodb:Ett Apollo-datakällbibliotek för MongoDB.
  • dotenv:Ett bibliotek för hantering av miljövariabler.
  • rimraf:Ett bibliotek för att köra UNIX rm -rf kommandot i Node.js.

De andra biblioteken som är installerade för utveckling inkluderar en mängd babel bibliotek för att köra och transpilera modern JavaScript-kod.

Skapa sedan en .babelrc fil i projektets rotkatalog och lägg till följande kod till filen:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "usage",
        "corejs": "3.0.0"
      }
    ]
  ]
}

Koden ovan instruerar Babel om hur man transpilerar den senaste JavaScript-koden som finns i appen med hjälp av Babels env konfigurationsalternativ.

Till sist, skapa en src mapp i projektets rotkatalog. Denna src mappen kommer att innehålla alla projektfiler. Med dessa ändringar är projektstrukturen på plats, och i nästa avsnitt kommer du att skapa en GraphQL-server med hjälp av Apollo Server-biblioteket.

Skapa en GraphQL-server med Apollo Server

I det här avsnittet kommer du att skapa en GraphQL-server med Apollo Server. Apollo Server-biblioteket kommer med en inbyggd Express-server och kan exekvera GraphQL-frågor och mutationer. Den tillhandahåller också en sandlåda i webbläsaren för att ansluta till en GraphQL-server, skriva och köra GraphQL-frågor, visa frågeresultat och utforska serverns GraphQL-schema.

En GraphQL-server består av ett GraphQL-schema som definierar strukturen för dess API och resolvers som implementerar schemastrukturen. Ett GraphQL-schema består av typer , som beskriver data som kan efterfrågas och returneras av GraphQL-servern. GraphQL tillhandahåller ett schemadefinitionsspråk (SDL) som används för att definiera ett GraphQL-schema. Med GraphQL:s SDL kan en filmtyp definieras enligt följande:

type Movie {
  _id: ID!
  title: String!
  rating: Float!
  year: Int!
  }

Film typ ovan definierar de fyra fälten som kan frågas i en film och deras returtyp. GraphQL har också tre rottyper; fråga , mutation och prenumeration . Dessa tre typer fungerar som ingångspunkter till en GraphQL-server och definierar möjliga körbara operationer i en GraphQL-server. frågan typen är för datahämtningsoperationer, mutationen typen är för operationer för att skapa eller ändra data, och prenumerationen typen är för datahämtningsoperationer i realtid.

För att skapa ett schema för GraphQL-servern, skapa en typeDefs.js fil i src mapp och lägg till följande kod till 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!
  }
`;

Koden ovan är en GraphQL-schematypdefinition och definierar tre GraphQL-typer; Film , Fråga och Mutation . Frågan och Mutation typer är rottyperna, medan Film mutation definierar de frågebara fälten för filminspelningar.
Frågan typ i schemadefinitionen ovan inkluderar följande fält:

  • getMovies :Detta fält returnerar en array med en eller flera Film skriv objekt.
  • getMovie :Det här fältet accepterar ett ID argument och returnerar en enda Film skriv objekt.

Dessutom, Mutation typen innehåller en createMovie fält som accepterar en titel , betyg och ett år argument och returnerar en Film typ objekt. Dessa fält representerar de frågor och mutationer som accepteras av GraphQL-servern.

När frågorna och mutationerna i rottyperna exekveras, förväntar sig GraphQL att deras respektive resolverfunktioner hämtar och returnerar data som motsvarar schemareturtypen. För att lägga till resolverfunktioner, skapa en resolvers.js fil i src katalog och lägg till följande kod till 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 ovan initierar vi en rad filmer som fungerar som en tillfällig datakälla. Utöver det exporterar vi en resolvers objekt med Fråga och Mutation egenskaper som matchar Query och Mutation typer i schemadefinitionen. De två resolveregenskaperna inkluderar funktioner som matchar operationerna som deklareras i Frågan och Mutation typer. Dessa resolverfunktioner utför specifika åtgärder på datakällan och returnerar den begärda informationen.

En GraphQL-resolverfunktion accepterar fyra argument:

  • root :Detta argument innehåller resultaten från tidigare körda resolvers.
  • args :Detta argument innehåller parametrarna för en GraphQL-fråga.
  • sammanhang :Detta argument innehåller data/objekt som kan nås/delas mellan resolverfunktioner.
  • info :Detta argument innehåller information om GraphQL-frågan eller mutationen som körs.

Schemat och resolvers som skapas måste vara anslutna till en server för att fungera. I src katalog, skapa en index.js fil och lägg till följande kod till 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}`);
});

Koden ovan importerar och skapar en instans av Apollo Server. Schemat (typeDefs ) och resolvers importeras också till filen och skickas till Apollo Server-instansen. Slutligen, Apollo Servers lyssna metoden startar webbservern på den angivna porten eller port 4000 om ingen port tillhandahålls.

För att köra servern, lägg till skriptet nedan i package.json fil som finns i rotkatalogen:

{
  ...
  "scripts": {
    …
    "start:dev": "babel-node src/index.js"
  },
...
}

start:dev skriptet ovan kör koden i src/index.js fil med babel-noden paket. För att köra skriptet, kör kommandot nedan i ditt terminalfönster:

npm run start:dev

Kommandot ovan startar webbservern, som körs på port 4000. Körning av kommandot bör returnera svaret nedan:

🚀  Server ready at http://localhost:4000/

För att se Apollo Server-målsidan, besök http://localhost:4000/ i din webbläsare. Du bör se en sida som den nedan:

På målsidan klickar du på knappen "Fråga din server" för att omdirigeras till sandlådan i webbläsaren. Du bör se en sida som den nedan, med en förifylld GraphQL-fråga:

Sandlådan består av tre paneler; den vänstra panelen visar schemat för GraphQL API med tillgängliga frågor och mutationer, den mittersta panelen är för att skriva och köra frågor, och den högra panelen är för att visa frågeresultat. Ersätt frågan i din sandlåda med koden nedan:

query ExampleQuery {
  getMovies {
    _id
    title
    year
    rating
  }
}

Koden ovan lägger till extra fält i ExampleQuery fråga. För att köra frågan, klicka på knappen "ExampleQuery" för att köra frågan. Du bör se svaret i den högra panelen.

I det här avsnittet skapade du en GraphQL-server med frågor och mutationer. I nästa avsnitt kommer du att ansluta GraphQL-servern till en MongoDB-databas.

Anslut GraphQL-servern till Mongo-databasen

Resolverfunktionerna i GraphQL-servern hämtar för närvarande data från en hårdkodad datakälla istället för MongoDB-databasen som skapades i det första avsnittet. I det här avsnittet kommer du att ansluta GraphQL-servern till MongoDB-databasen och även skapa en mongoosemodell för att representera ett filmdokument på MongoDB.

Skapa först en .env fil i projektets rotkatalog och lägg till följande kod till filen där och representera din MongoDB-databasanvändare och dess lösenord:

MONGODB_URI="mongodb+srv://<username>:<password>@apollogql-demo.kk9qw.mongodb.net/apollogql-db?retryWrites=true&w=majority"

Koden ovan gör din MongoDB-databasanslutningssträng tillgänglig som en miljövariabel. .env filen ska inte vara bunden till git eftersom den innehåller hemliga data.

Byt sedan ut koden i src/index.js fil med följande:

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 ovan importerar dotenv config och mongoose paketet till index.js fil. Importera dotenv config gör miljövariablerna i .env fil tillgänglig via process.env objekt. Värdet på MONGODB_URI miljövariabeln nås via process.env och lagras i en uri variabel och en asynkronfunktion main deklareras för att skapa en anslutning till MongoDB-databasen med hjälp av mongoose connect funktionen och uri anslutningssträng. main() funktionen anropas sedan för att öppna en anslutning till MongoDB-databasen.

🎉 connected to database successfully
🚀  Server ready at http://localhost:4000/

Till sist, skapa en modeller mappen i src mapp och skapa en movie.js inuti den fil. Lägg till koden nedan i filen:

import mongoose from "mongoose";

export const Movie = mongoose.model("Movie", {
  title: String,
  rating: Number,
  year: Number,
});

Koden ovan skapar en Film modell, och den fungerar som gränssnitt för att skapa och manipulera dokument i MongoDB-databasen. Detta är det sista steget mot att göra MongoDB-databasen till datakällan för GraphQL-servern. I nästa avsnitt kommer du att byta GraphQL-serverns datakälla från den hårdkodade arrayen till din MongoDB-databas.

Använd MongoDB som en GraphQL-datakälla

Den aktuella datakällan för GraphQL-servern är en hårdkodad array, och i det här avsnittet kommer du att ersätta den med din MongoDB-databas. För att göra det, börja med att skapa en dataSources mappen i src mapp. I dataSources mapp skapar du en movies.js fil och lägg till följande kod till 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 ovan deklarerar en Movies datakällsklass som utökar MongoDataSource klass tillhandahållen av apollo-datasource-mongodb paket. Filmer datakällan innehåller tre metoder för var och en av de befintliga frågorna och mutationerna. getMovies och createMovie metoder använder filmmodellen som skapades i föregående avsnitt för att läsa och infoga data i MongoDB-databasen och getMovie metoden använder findOneById metod som tillhandahålls av MongoDataSource klass för att hämta ett dokument från MongoDB-samlingen som matchar det angivna id argument.

Byt sedan ut koden i src/index.js fil med koden nedan:

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 uppdaterade koden ovan importerar Film modellen och Filmerna datakällklassen till src/index.js fil. Efter anslutning till MongoDB-databasen, en dataSources funktionen skapas. Denna funktion returnerar ett objekt som innehåller en instans av Movies datakälla som tar emot Film modell som parameter. datakällorna funktionen skickas sedan till Apollo Server-instansen, vilket gör Movies datakällasinstans tillgänglig inom varje resolverfunktion.

För att ersätta den hårdkodade datakällan med Film datakälla, byt ut koden i src/resolvers.js fil med koden nedan:

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 uppdaterade koden ovan, Movies datakällan instans skickas till Apollo Server i src/index.js filen är tillgänglig i resolverfunktionerna via dataSources egenskapen för det delade kontextobjektet. Varje resolverfunktion anropar sin respektive metod i datakällan för att utföra den specificerade operationen på MongoDB-databasen.

Alla frågor som görs vid denna tidpunkt kommer att returnera ett tomt resultat eftersom MongoDB-databasen för närvarande är tom. Starta om din server och besök sedan ditt Mongo Atlas-konto i din webbläsare. På din MongoDB-sida "Databasdistributioner", välj ditt databaskluster och klicka på fliken "Samlingar". På fliken "Samlingar", klicka på knappen "INSERT DOKUMENT" och lägg till så många filmdokument du vill.

Kör ExampleQuery i din Apollo Server-sandlåda från föregående avsnitt. Du bör få en lista över alla filmdokument i din Mongo DB-samling. I det här avsnittet använde du din MongoDB-databas som en datakälla för din GraphQL-server. I nästa avsnitt kommer du att distribuera din GraphQL-server online på Koyeb.

Distribuera till Koyeb

Det första steget mot att distribuera GraphQL-servern på Koyeb är att lägga till de npm-skript som behövs för att bygga koden i produktionen. Lägg till följande skript nedan till din package.json fil:

"scripts": {
  ...
  "prebuild": "rimraf dist && mkdir dist",
  "build": "babel src -d dist",
  "start": "node ./dist/index.js"
  }

De tre npm-skripten som lagts till ovan inkluderar:

  • En förbyggd skript för att säkerställa att det finns ett tomt avstånd katalogen före build skriptet körs.
  • En build skript som transpilerar all kod i src katalogen till JavaScript ES5-syntaxen till dist katalogen med hjälp av babel paket.
  • En start skript som startar servern.

Skapa sedan ett GitHub-förråd för din GraphQL-server och kör sedan kommandona nedan i ditt terminalfönster:

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å till Secrets på din Koyeb kontrollpanel flik och skapa en ny hemlighet. Ange MONGODB_URI som det hemliga namnet och din MongoDB-anslutningssträng som värdet. Gå sedan till Översikt och klicka på knappen "Skapa app" för att starta processen för att skapa appen.

På sidan för att skapa appar:

  • Välj GitHub som din distributionsmetod.
  • Välj GitHub-förvaret för din kod i rullgardinsmenyn för repositories.
  • Välj grenen du vill distribuera. T.ex. huvud .
  • I avsnittet miljövariabler klickar du på knappen lägg till miljövariabel.
  • Välj Hemlighet typ, ange MONGODB_URI som nyckel och välj MONGODB_URI hemlighet skapad tidigare som värdet.
  • Lägg till en vanlig textmiljövariabel med nyckeln PORT och värde 8080 .
  • Ge din app ett namn. T.ex. graphql-apollo-server och klicka på knappen "Skapa app".

När du skapar appen visas run och build kommandoalternativ hoppades över eftersom Koyeb-plattformen kan upptäcka build och start skript i package.json fil och kör dem automatiskt. Genom att klicka på knappen "Skapa app" omdirigeras du till implementeringssidan, där du kan övervaka appimplementeringsprocessen. När distributionen är klar och alla nödvändiga hälsokontroller har passerat kan du komma åt din offentliga webbadress.

Testa ditt GraphQL API

Använd ditt favorit-API-testverktyg eller denna online GraphiQL-lekplats, skapa en getMovies GraphQL-fråga till din offentliga URL. Du bör få svar på alla filmdokument i din MongoDB-databas.

Slutsats

Det är allt! Du har framgångsrikt skapat och distribuerat en GraphQL-server med Apollo Server och en MongoDB-datakälla till Koyeb. Lägg gärna till fler frågor och mutationer till din GraphQL-server. Eftersom vi distribuerade till Koyeb med hjälp av git-driven distribution, kommer en ny version automatiskt att triggas och distribueras på Koyeb när du överför dina ändringar till ditt GitHub-förråd.

Dina ändringar kommer att aktiveras så snart din implementering klarar alla nödvändiga hälsokontroller. I händelse av ett fel under driftsättningen, underhåller Koyeb den senaste fungerande driftsättningen i produktionen för att säkerställa att din applikation alltid är igång.

Genom att implementera på Koyeb drar vår applikation nytta av inbyggd global lastbalansering, autoskalning, autohealing och automatisk HTTPS (SSL)-kryptering med noll konfiguration från vår sida.

Om du vill titta på koden för demoapplikationen kan du hitta den här.


  1. expire redis cache-nyckel vid vissa timmar snarare än varaktighet

  2. 8 sätt att få dagen från en dejt i MongoDB

  3. Skala Socket.IO till flera Node.js-processer med hjälp av kluster

  4. MongoDB, prestanda för fråga genom reguljärt uttryck på indexerade fält