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:
- Crie um banco de dados MongoDB usando o MongoDB Atlas
- Configure o projeto
- Crie um servidor GraphQL usando o Apollo Server
- Conecte o servidor GraphQL ao banco de dados MongoDB
- Usar MongoDB como fonte de dados GraphQL
- 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 maisMovie
objetos de tipo.getMovie
:Este campo aceita umID
argumento e retorna um únicoMovie
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 umdist
vazio diretório antes dobuild
script é executado. - Uma
build
script que transpila todo o código nosrc
diretório para a sintaxe JavaScript ES5 nodist
diretório com a ajuda dobabel
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, digiteMONGODB_URI
como a chave e selecione oMONGODB_URI
segredo criado anteriormente como o valor. - Adicione uma variável de ambiente de texto simples com a chave
PORT
e valor8080
. - 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.