Construindo uma API GraphQL com Node.js
Hoje mostraremos como construir uma api utilizando GraphQL, Mongo e Hapi
Mas espere.. Hapi? 🧐
Sim, utilizaremos o hapiJS, esse framework foi criado pelo time do Walmart Labs — liderado por Eran Hammer, que também criou o OAuth — e é focado no desenvolvimento com qualidade corporativa e entre vários times, de fácil manutenção e escalabilidade, e prefere configuração do que código.
O mesmo também conta com alguns pacotes interessantes que são desenvolvidos pela Walmart Labs
- Boom: Esse é usado para enviar erros HTTP corretamente para o cliente, usando o código correto no envio com um objeto estruturado e mensagem personalizada. A principal vantagem é a facilidade de leitura do código durante o desenvolvimento, usando palavras para descrever o erro corretamente e não o código diretamente (Boom.badRequest ao invés de Status 400). Link para o repositório: https://github.com/hapijs/boom
- Joi: Esse é usado para validar e retornar erros de validação de forma automatizada. Ele facilita muito o desenvolvimento e garante um sistema fechado contra usuários mal intencionados. Link para o repositório : https://github.com/hapijs/joi
Caso queira se aventurar na documentação do mesmo o link está aqui
Vamos ao código! 👨💻
Antes precisamos conhecer nossas dependências e o que precisaremos para iniciar nosso projeto:
Agora sim iniciaremos! 👨💻
Para iniciarmos nossa API utilizaremos o comando yarn init
Após a inicialização do nosso projeto instalaremos as dependências com o comando yarn add hapi nodemon
Criaremos um novo arquivo index.js
na raiz do projeto com o seguinte conteúdo :
- Importar o hapi
- Declarar uma constante chamada
api
que criará uma nova instância do Hapi — como argumentos, passaremos um objeto com a porta e o host. - Criaremos uma expressão assíncrona chamada start. Dentro desse método teremos um outro método assíncrono que inicia a aplicação.
Caso esteja em dúvida relacionado ao uso de async await recomendo a seguinte leitura.
Ao acessar pelo navegador o endereço http://localhost:3000
teremos o seguinte resultado:
404 ?! 😡
Isso é normal meu caro, visto que, o hapi espera uma rota e um handler. Faremos isso logo mais, pois antes iremos adicionar o seguinte script dentro de nosso arquivo package.json
Rotas
As rotas com o hapi são relativamente mais simples. Supondo que ao bater na rota /
— o que é esperado que aconteça ? Mas antes disso necessitamos de três informações:
- Qual é o caminho? —
path
- Qual é o método HTTP ? É um
GET
—POST
ou algo parecido? —method
- O que acontecerá caso a rota seja encontrada? —
handler
Agora para rodarmos nossa api utilizaremos o comando yarn start
pois utilizaremos o nodemon para fazer o restart automático após salvarmos nossas alterações:
Conectando nossa API ao MongoDB
Tudo certo até aqui, iremos conectar nossa API ao MongoDB utilizando o Mongoose.
Primeiramente instalaremos o mongoose via yarn:
Para que possamos dar mais agilidade ao desenvolvimento, utilizaremos o mongo na nuvem através do MongoDB Atlas, não se preocupe, pois existe o plano gratuito e que atenderá muito bem esse tutorial.
Após criar sua conta e criar seu primeiro cluster o mesmo deverá estar parecido com a imagem:
Para que façamos a conexão basta ir na opção "Connect" > "Connect Your Application" e copiar a string de conexão :
Após copiarmos a string faremos as seguintes alterações dentro do arquivo index.js
:
- Importar o mongoose
- Realizar a chamada da conexão com o string ID que acabamos de copiar
- Definir que uma vez conectado informar no console que a conexão foi bem sucedida.
Caso tudo tenha ocorrido de acordo com o planejado, deveremos ver ‘conectado ao mongoDB’
Criando nosso model
Com o MongoDB utilizaremos a convenção de models. Caso tenha interesse em aprofundar o conhecimento o link está aqui.
Vamos criar um diretório chamado Models
e nessa pasta criaremos o arquivo User.js
- Inserimos a dependência do mongoose
- Declaramos nosso
userSchema
chamando o construtor do schema do mongoose e passando as informações e os tipos. - Exportamos o model criado e nomeamos o mesmo de
User
Consultando e inserindo usuários na base de dados!
Primeiramente importaremos o model que acabamos de criar no arquivo index.js
Mas para que possamos realizar as requisições de consulta e inserção precisaremos definir as rotas das mesmas. Então vamos lá :
Vamos iniciar com as rotas de GET
e POST
. Onde GET
lista todos os usuários e POST
inclui um novo usuário .
- Inserimos as rotas em um array de objetos, e também utilizaremos arrow functions.
- Criamos um
GET em/v1/users
. Dentro do handler estamos chamando o schema do mongoose. Chamamos o metodo find() que retorna todos os usuários - Também criamos um
POST
no mesmo caminho. A razão para tal é que estamos seguindo as convenções REST. A partir disso desestruturamos o handler da requisição, após obtermos os campos que precisamos e queremos, passamos os mesmos para o schema do mongoose. Após a passagem de argumentos, chamamos o método save() que salva nosso novo documento no MongoDB .
Estarei utilizando o Insomnia para testarmos as requisições criadas. Mas essa parte fica a seu critério, caso tenha preferência pelo Postman ou alguma outra ferramenta 😄
- Realizamos a requisição de post de usuário passando as informações que queremos ser inseridas. Devemos lembrar que os sitesPreferidos se trata de um array.
Após realizarmos a requisição teremos o seguinte resultado:
Ao realizar a consulta dos usuários pelo insomnia teremos o seguinte resultado:
Tudo certo, mas cadê o GraphQL??
Sim, meu consagrado , deixei a melhor parte para o final. Mas antes, afinal de contas o que é o GraphQL?
Uma forma de compreender é entendendo que ele é uma abstração ao protocolo HTTP, ou seja, você estará utilizando um endpoint na sua aplicação que estará subindo um server GraphQL nela e este server receberá requests do tipo POST e GET e responderá usando um formato JSON.
Para começarmos iremos adicionar o grapghql e o apollo-server-hapi:
GrapghQL é o pacote core do mesmo e o apollo-server-hapi é responsável pela comunicação do hapi com o graphql
Vamos criar um novo diretório chamado graphql
e dentro do mesmo o arquivo UserType.js
Importamos o graphQL
Após isso desestruturamos os seguintes objetos do graphqlconst { GraphQLObjectType, GraphQLString } = graphql
Que é o mesmo que:const GraphQLObjectType = graphql.GraphQLObjectType
const GraphQLString = graphql.GraphQLString
Após isso definimos os tipos dos campos, utilizamos os campos do tipo string e numérico, GraphQLString
e GraphQLEnumType
Agora que temos nossa query de usuários corretamente criada, precisamos criar o schema da mesma.
Vamos criar um arquivo chamado schema.js
dentro da nossa pasta graphql.
Essa será a query que utilizaremos, vamos aos detalhes:
Veja que estamos informando o tipo da query apontando para o arquivo UserType.js
e também estamos utilizando o args
pois utilizaremos a busca da partir de ID
No final do arquivo exportamos a query criada e a mesma estará pronta para que o hapi utilize a mesma.
Voltando para nosso index.js
— Nos importamos: graphqlHapi, graphiqlHapi e o schema.js
Agora iremos realizar a configuração do nosso GraphQL:
Primeiramente realizarmos a configuração do graphiql, responsável por uma interface que irá facilitar nossas requisições futuras.
Agora que temos a configuração do graphQL devidamente realizada, se formos em http://localhost:3000/graphiql teremos a seguinte interface:
Ao fazer a chamada de nossa query teremos o seguinte resultado:
Temos nulo por dois motivos:
- Não estamos buscando as informações do MongoDB
- Provavelmente não temos um usuário com ID = 20
Vamos implementar a consulta ao MongoDB:
Veja que dentro do arquivo schema.js
incluímos as linhas 3 e 14, importando o model e após isso fazendo a busca por ID na linha 14.
Mas como vamos obter o ID do usuário ? Basta fazer a requisição via insomnia conforme tratado anteriormente ou até mesmo acessando a url http://localhost:3000/v1/users
Ao colocar as informações corretas dentro do GraphiQL teremos:
E é isso meu caro padawan, espero que tenha gostado desse guia, ficou um pouco extenso, porém, dando bastante informação para seus primeiros passos com essa stack. Ela também abre portas, para por exemplo, realizar mutations, para inclusão e exclusão de usuários, utilização do hapi-swagger, para gerar documentação do swagger e etc.
segue link do projeto no github:
Espero que tenha se divertido ❤