MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Implante uma API GraphQL com o MongoDB Atlas e o Apollo Server no Koyeb

Introdução


Nos últimos anos, novas estruturas, bibliotecas e linguagens chegaram ao cenário tecnológico e lutaram para obter a adoção geral, mas uma tecnologia recente que teve grande adoção por equipes de engenharia de software em um curto período é o GraphQL. Lançado pelo Facebook em 2015, foi implementado em várias linguagens de programação e levou à criação de vários frameworks e bibliotecas relacionados ao GraphQL.

GraphQL é uma linguagem de consulta fortemente tipada para APIs e um tempo de execução para atender consultas com dados existentes. Ele permite que os clientes consultem muitos recursos em uma única solicitação solicitando campos obrigatórios em vez de fazer solicitações para vários terminais.

O Apollo Server é um servidor GraphQL de código aberto que fornece uma maneira fácil de criar uma API GraphQL que pode usar dados de várias fontes, incluindo vários bancos de dados e até APIs REST.

O MongoDB Atlas é uma plataforma de dados de aplicativos totalmente gerenciada que trata da criação, gerenciamento e implantação do MongoDB na nuvem. Ele fornece fácil implantação de bancos de dados MongoDB para vários provedores de serviços em nuvem com várias ferramentas para gerenciar bancos de dados MongoDB em um ambiente de produção.

Neste tutorial, aprenderemos como construir e implantar um servidor GraphQL conectado a uma fonte de dados MongoDB. No final deste tutorial, você terá construído uma API GraphQL funcional usando o Apollo Server e o MongoDB Atlas e a implantado para produção no Koyeb.

Requisitos


Para seguir este tutorial com sucesso, você precisa do seguinte:
  • Uma máquina de desenvolvimento com Node.js instalado. O aplicativo de demonstração neste tutorial usa a versão 16.14.0 do Node.js
  • Uma máquina de desenvolvimento com Git instalado
  • Uma conta do MongoDB Atlas
  • Uma conta Koyeb para implantar o aplicativo

Etapas


As etapas para criar uma API GraphQL com Apollo DataSource e MongoDB Atlas e implantá-la em produção no Koyeb incluem:
  1. Crie um banco de dados MongoDB usando o MongoDB Atlas
  2. Configure o projeto
  3. Crie um servidor GraphQL usando o Apollo Server
  4. Conecte o servidor GraphQL ao banco de dados MongoDB
  5. Usar MongoDB como fonte de dados GraphQL
  6. Implantar para Koyeb

Crie um banco de dados MongoDB usando o Mongo Atlas


O MongoDB Atlas oferece a capacidade de criar bancos de dados MongoDB implantados na nuvem com apenas alguns cliques e, nesta seção, você criará um banco de dados MongoDB usando o MongoDB Atlas.

Enquanto estiver conectado à sua conta do MongoDB Atlas, clique no botão "Build a Database" na página "Data Deployments" e execute as seguintes etapas:
  • Clique no botão "Criar" em seu tipo de implantação preferido.
  • Selecione um provedor e região de nuvem preferidos ou use as opções pré-selecionadas.
  • Digite um nome de cluster ou use o nome de cluster padrão.
  • Clique no botão "Criar cluster".
  • Selecione a opção de autenticação "Nome de usuário e senha", insira um nome de usuário e senha e clique no botão "Criar usuário". Armazene o nome de usuário e a senha em um local seguro para uso posterior.
  • Digite "0.0.0.0/0" sem as aspas no campo Endereço IP da seção Lista de acesso IP e clique no botão "Adicionar entrada".
  • Clique no botão "Concluir e Fechar" e depois no botão "Ir para Bancos de Dados". Você será redirecionado para a página "Data Deployments", com seu novo cluster MongoDB agora visível.
  • Clique no botão "Conectar" ao lado do nome do cluster MongoDB, selecione a opção "Conectar seu aplicativo" e copie a string de conexão do banco de dados para um local seguro para uso posterior.



Seguindo as etapas acima, você criou um banco de dados MongoDB para ler e armazenar dados para a API GraphQL. Na próxima seção, você configurará o projeto e instalará as bibliotecas e dependências necessárias.

Configure o projeto


Nesta seção, você configurará um projeto npm e instalará as dependências necessárias para construir o servidor de demonstração GraphQL para este tutorial. O servidor GraphQL irá expor uma API GraphQL que lê e grava dados de filmes de e para o banco de dados MongoDB criado na seção anterior. Comece criando um diretório raiz para o projeto em sua máquina de desenvolvimento. Para fazer isso, execute o comando abaixo na janela do seu terminal:

mkdir graphql_movies

Os graphql_movies O diretório criado pelo comando acima é o diretório raiz do aplicativo de demonstração. Em seguida, mude para o graphql_movies e inicialize um repositório Git no diretório executando o comando abaixo na janela do seu terminal:

cd graphql_movies
git init

O primeiro comando acima move você para o graphql_movies diretório em seu terminal, enquanto o segundo comando inicializa um repositório Git para rastrear alterações no graphql_movies diretório. Em seguida, crie um projeto npm no graphql_movies diretório executando o comando abaixo na janela do seu terminal:

npm init --yes

Executando o npm init O comando inicializa um projeto npm vazio e cria um package.json arquivo no diretório raiz. O --yes flag responde automaticamente "sim" a todos os prompts gerados pelo npm.

Com um projeto npm agora em vigor, vá em frente e instale as bibliotecas e pacotes necessários para construir a API GraphQL. Na janela do seu terminal, execute os comandos abaixo:

npm install apollo-server graphql mongoose apollo-datasource-mongodb dotenv rimraf

npm install -D @babel/preset-env @babel/core @babel/node @babel/cli

A npm install O comando acima instala 10 pacotes no projeto e os adiciona ao package.json do projeto Arquivo. O primeiro comando instala as dependências necessárias para executar o aplicativo, enquanto o segundo instala as dependências necessárias durante o desenvolvimento do aplicativo. As dependências instaladas incluem:
  • apollo-server:uma biblioteca de código aberto para criar servidores GraphQL.
  • graphql:a implementação JavaScript da especificação GraphQL.
  • mongoose:um mapeador de documentos de objetos para MongoDB.
  • apollo-datasource-mongodb:uma biblioteca de fonte de dados Apollo para MongoDB.
  • dotenv:uma biblioteca para manipular variáveis ​​de ambiente.
  • rimraf:uma biblioteca para executar o UNIX rm -rf comando no Node.js.

As outras bibliotecas instaladas para desenvolvimento incluem um host de babel bibliotecas para executar e transpilar código JavaScript moderno.

Em seguida, crie um .babelrc file no diretório raiz do projeto e adicione o seguinte código ao arquivo:

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

O código acima instrui o Babel sobre como transpilar o código JavaScript mais recente presente no aplicativo usando o env do Babel opções de configuração.

Por fim, crie um src pasta no diretório raiz do projeto. Este src pasta irá abrigar todos os arquivos do projeto. Com essas alterações, a estrutura do projeto está pronta e, na próxima seção, você criará um servidor GraphQL usando a biblioteca Apollo Server.

Crie um servidor GraphQL usando o Apollo Server


Nesta seção, você criará um servidor GraphQL usando o Apollo Server. A biblioteca Apollo Server vem com um servidor Express embutido e pode executar consultas e mutações do GraphQL. Ele também fornece um sandbox no navegador para conectar-se a um servidor GraphQL, gravar e executar consultas GraphQL, visualizar resultados de consultas e explorar o esquema GraphQL do servidor.

Um servidor GraphQL consiste em um esquema GraphQL que define a estrutura de sua API e resolvedores que implementam a estrutura do esquema. Um esquema GraphQL consiste em types , que descreve os dados que podem ser consultados e retornados pelo servidor GraphQL. O GraphQL fornece uma linguagem de definição de esquema (SDL) usada para definir um esquema do GraphQL. Usando o SDL do GraphQL, um tipo de filme pode ser definido da seguinte forma:

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

O Movie O tipo acima define os quatro campos que podem ser consultados em um filme e seu tipo de retorno. O GraphQL também possui três tipos de raiz; query , mutation e subscription . Esses três tipos servem como pontos de entrada para um servidor GraphQL e definem as possíveis operações executáveis ​​em um servidor GraphQL. A query type é para operações de busca de dados, a mutation type é para operações de criação ou modificação de dados, e a subscription type é para operações de busca de dados em tempo real.

Para criar um esquema para o servidor GraphQL, crie um typeDefs.js arquivo no src pasta e adicione o seguinte código ao arquivo:

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!
  }
`;

O código acima é uma definição de tipo de esquema GraphQL e define três tipos de GraphQL; Movie , Query e Mutation . A Query e Mutation tipos são os tipos raiz, enquanto o Movie mutação define os campos que podem ser consultados para registros de filmes.
A Query type na definição do esquema acima inclui os seguintes campos:
  • getMovies :Este campo retorna um array de um ou mais Movie objetos de tipo.
  • getMovie :Este campo aceita um ID argumento e retorna um único Movie tipo objeto.

Além disso, a Mutation type inclui um createMovie campo que aceita um title , rating e um year argumento e retorna um Movie tipo objeto. Esses campos representam as consultas e mutações aceitas pelo servidor GraphQL.

Quando as consultas e mutações nos tipos raiz são executadas, o GraphQL espera que suas respectivas funções de resolução busquem e retornem dados correspondentes ao tipo de retorno do esquema. Para adicionar funções de resolução, crie um resolvers.js arquivo no src diretório e adicione o seguinte código ao arquivo:

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;
    }
  }
}

No código acima, inicializamos um array de filmes que serve como fonte de dados temporária. Além disso, exportamos um resolvers objeto com Query e Mutation propriedades que correspondem à Query e Mutation tipos na definição do esquema. As duas propriedades do resolvedor incluem funções que correspondem às operações declaradas na Query e Mutation tipos. Essas funções de resolução executam ações específicas na fonte de dados e retornam os dados solicitados.

Uma função de resolução GraphQL aceita quatro argumentos:
  • root :este argumento contém os resultados de quaisquer resolvedores executados anteriormente.
  • args :este argumento contém os parâmetros para uma consulta GraphQL.
  • context :este argumento contém dados/objetos que podem ser acessados/compartilhados nas funções do resolvedor.
  • info :este argumento contém informações sobre a consulta ou mutação do GraphQL que está sendo executada.

O esquema e os resolvedores criados precisam estar conectados a um servidor para se tornarem funcionais. No src diretório, crie um index.js arquivo e adicione o seguinte trecho de código ao arquivo:

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}`);
});

O código acima importa e cria uma instância do Apollo Server. O esquema (typeDefs ) e os resolvedores também são importados para o arquivo e passados ​​para a instância do Apollo Server. Finalmente, o listen do Apollo Server O método inicia o servidor da Web na porta fornecida ou na porta 4000 se nenhuma porta for fornecida.

Para executar o servidor, adicione o script abaixo ao package.json arquivo localizado no diretório raiz:

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

O start:dev script acima executa o código no src/index.js arquivo usando o babel-node pacote. Para executar o script, execute o comando abaixo na janela do seu terminal:

npm run start:dev

O comando acima inicia o servidor web, que roda na porta 4000. A execução do comando deve retornar a resposta abaixo:

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

Para ver a página de destino do Apollo Server, visite http://localhost:4000/ no seu navegador. Você deverá ver uma página como a abaixo:



Na página de destino, clique no botão "Consulte seu servidor" para ser redirecionado para o sandbox do navegador. Você deverá ver uma página como a abaixo, com uma consulta GraphQL pré-preenchida:



A caixa de areia consiste em três painéis; o painel esquerdo exibe o esquema da API GraphQL com as consultas e mutações disponíveis, o painel do meio é para escrever e executar consultas e o painel direito é para visualizar os resultados da consulta. Substitua a consulta em seu sandbox pelo código abaixo:

query ExampleQuery {
  getMovies {
    _id
    title
    year
    rating
  }
}

O código acima adiciona campos extras ao ExampleQuery inquerir. Para executar a consulta, clique no botão "ExampleQuery" para executar a consulta. Você deve ver a resposta no painel direito.



Nesta seção, você criou um servidor GraphQL com consultas e mutação. Na próxima seção, você conectará o servidor GraphQL a um banco de dados MongoDB.

Conecte o servidor GraphQL ao banco de dados Mongo


As funções do resolvedor no servidor GraphQL atualmente buscam dados de uma fonte de dados codificada em vez do banco de dados MongoDB criado na primeira seção. Nesta seção, você conectará o servidor GraphQL ao banco de dados MongoDB e também criará um modelo mongoose para representar um documento de filme no MongoDB.

Primeiro, crie um .env file no diretório raiz do projeto e adicione o seguinte código ao arquivo onde <username> e <password> represente seu usuário do banco de dados MongoDB e sua senha:

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

O código acima disponibiliza sua string de conexão do banco de dados MongoDB como uma variável de ambiente. O .env O arquivo não deve ser confirmado no git, pois contém dados secretos.

Em seguida, substitua o código no src/index.js arquivo com o seguinte:

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}`);
});

O código acima importa o dotenv config e mongoose pacote no index.js Arquivo. Importando o dotenv config torna as variáveis ​​de ambiente no .env arquivo acessível através do process.env objeto. O valor do MONGODB_URI variável de ambiente é acessada através do process.env e armazenado em um uri variável e uma função assíncrona main é declarado para criar uma conexão com o banco de dados MongoDB usando o mongoose connect função e o uri cadeia de conexão. O main() A função é então chamada para abrir uma conexão com o banco de dados MongoDB.

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

Por fim, crie um models pasta no src pasta e dentro dela, crie um movie.js Arquivo. Adicione o código abaixo ao arquivo:

import mongoose from "mongoose";

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

O código acima cria um Movie model, e serve como interface para criação e manipulação de documentos no banco de dados MongoDB. Este é o último passo para tornar o banco de dados MongoDB a fonte de dados para o servidor GraphQL. Na próxima seção, você mudará a fonte de dados do servidor GraphQL do array codificado para seu banco de dados MongoDB.

Use o MongoDB como uma fonte de dados GraphQL


A fonte de dados atual para o servidor GraphQL é uma matriz codificada e, nesta seção, você a substituirá pelo banco de dados MongoDB. Para fazer isso, comece criando um dataSources pasta no src pasta. Em dataSources pasta, crie um movies.js arquivo e adicione o seguinte código ao arquivo:

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 });
  }
}

O código acima declara um Movies classe de fonte de dados que estende o MongoDataSource classe fornecida pelo apollo-datasource-mongodb pacote. Os Movies fonte de dados contém três métodos para cada uma das consultas e mutações existentes. O getMovies e createMovie métodos usam o modelo de filme criado na seção anterior para ler e inserir dados no banco de dados MongoDB e o getMovie método usa o findOneById método fornecido pelo MongoDataSource class para buscar um documento da coleção do MongoDB que corresponda ao id fornecido argumento.

Em seguida, substitua o código no src/index.js arquivo com o código abaixo:

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}`);
});

O código atualizado acima importa o Movie model e os Movies classe de fonte de dados no src/index.js Arquivo. Após conectar-se ao banco de dados MongoDB, um dataSources função é criada. Esta função retorna um objeto contendo uma instância do Movies fonte de dados que recebe o Movie modelo como parâmetro. As dataSources A função é então passada para a instância do Apollo Server, tornando o Movies instância de fonte de dados disponível em cada função de resolução.

Para substituir a fonte de dados codificada pelo Movie fonte de dados, substitua o código no src/resolvers.js arquivo com o código abaixo:

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)
    }
  }
}

No código atualizado acima, o Movies instância da fonte de dados passada para o Apollo Server no src/index.js arquivo está disponível nas funções do resolvedor através do dataSources propriedade do objeto de contexto compartilhado. Cada função de resolução chama seu respectivo método na fonte de dados para realizar a operação especificada no banco de dados MongoDB.

Qualquer consulta feita neste ponto retornará um resultado vazio, pois o banco de dados MongoDB está vazio no momento. Reinicie o servidor e visite sua conta do Mongo Atlas em seu navegador. Na página "Database Deployments" do MongoDB, selecione seu cluster de banco de dados e clique na guia "Collections". Na guia "Coleções", clique no botão "INSERIR DOCUMENTO" e adicione quantos documentos de filme desejar.



Em sua sandbox do Apollo Server, execute o ExampleQuery da seção anterior. Você deve obter uma lista de todos os documentos do filme em sua coleção do Mongo DB. Nesta seção, você usou seu banco de dados MongoDB como fonte de dados para seu servidor GraphQL. Na próxima seção, você implantará seu servidor GraphQL online no Koyeb.

Implantar em Koyeb


O primeiro passo para implantar o servidor GraphQL no Koyeb é adicionar os scripts npm necessários para construir o código em produção. Adicione os seguintes scripts abaixo ao seu package.json Arquivo:

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

Os três scripts npm adicionados acima incluem:
  • Uma prebuild script para garantir que haja um dist vazio diretório antes do build script é executado.
  • Uma build script que transpila todo o código no src diretório para a sintaxe JavaScript ES5 no dist diretório com a ajuda do babel pacote.
  • Um start script que inicia o servidor.

Em seguida, crie um repositório GitHub para seu servidor GraphQL e execute os comandos abaixo na janela do seu terminal:

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

No painel de controle do Koyeb, vá para Secrets guia e crie um novo segredo. Digite MONGODB_URI como o nome do segredo e sua string de conexão do MongoDB como o valor. Em seguida, vá para a Overview guia e clique no botão "Criar aplicativo" para iniciar o processo de criação do aplicativo.

Na página de criação do aplicativo:
  • Selecione GitHub como seu método de implantação.
  • Na lista suspensa de repositórios, selecione o repositório do GitHub para seu código.
  • Selecione a ramificação que você deseja implantar. Por exemplo. main .
  • Na seção de variáveis ​​de ambiente, clique no botão adicionar variável de ambiente.
  • Selecione o Secret digite, digite MONGODB_URI como a chave e selecione o MONGODB_URI segredo criado anteriormente como o valor.
  • Adicione uma variável de ambiente de texto simples com a chave PORT e valor 8080 .
  • Dê um nome ao seu aplicativo. Por exemplo. graphql-apollo-server e clique no botão "Criar aplicativo".

Ao criar o aplicativo, o run e build as opções de comando foram ignoradas, pois a plataforma Koyeb pode detectar o build e start scripts no package.json arquivo e executá-los automaticamente. Clicar no botão "Criar aplicativo" redireciona você para a página de implantação, onde você pode monitorar o processo de implantação do aplicativo. Depois que a implantação for concluída e todas as verificações de integridade necessárias forem aprovadas, você poderá acessar sua URL pública.

Teste sua API GraphQL


Usando sua ferramenta de teste de API favorita ou este playground online GraphiQL, faça um getMovies Consulta GraphQL para seu URL público. Você deve obter uma resposta de todos os documentos do filme em seu banco de dados MongoDB.


Conclusão


É isso! Você criou e implantou com sucesso um servidor GraphQL com Apollo Server e uma fonte de dados MongoDB para Koyeb. Sinta-se à vontade para adicionar mais consultas e mutações ao seu servidor GraphQL. Como implantamos no Koyeb usando a implantação orientada por git, uma nova compilação será acionada e implantada automaticamente no Koyeb sempre que você enviar suas alterações para o repositório do GitHub.

Suas alterações serão publicadas assim que sua implantação for aprovada em todas as verificações de integridade necessárias. Em caso de falha durante a implantação, a Koyeb mantém a implantação mais recente em produção para garantir que seu aplicativo esteja sempre funcionando.

Ao implantar no Koyeb, nosso aplicativo se beneficia do balanceamento de carga global nativo, dimensionamento automático, recuperação automática e criptografia HTTPS (SSL) automática com configuração zero de nossa parte.

Se você quiser ver o código do aplicativo de demonstração, você pode encontrá-lo aqui.