Introducción
En los últimos años, nuevos marcos, bibliotecas y lenguajes se han abierto camino en la escena tecnológica y han luchado por obtener una adopción generalizada, pero una pieza tecnológica reciente que ha visto una gran adopción por parte de los equipos de ingeniería de software en un período corto es GraphQL. Lanzado por Facebook en 2015, se ha implementado en múltiples lenguajes de programación y ha llevado a la creación de varios marcos y bibliotecas relacionados con GraphQL.
GraphQL es un lenguaje de consulta fuertemente tipado para API y un tiempo de ejecución para completar consultas con datos existentes. Permite a los clientes consultar muchos recursos en una sola solicitud solicitando campos obligatorios en lugar de realizar solicitudes a múltiples puntos finales.
Apollo Server es un servidor GraphQL de código abierto que proporciona una manera fácil de crear una API GraphQL que puede usar datos de múltiples fuentes, incluidas varias bases de datos e incluso API REST.
MongoDB Atlas es una plataforma de datos de aplicaciones completamente administrada que maneja la creación, administración e implementación de MongoDB en la nube. Proporciona una fácil implementación de las bases de datos de MongoDB a varios proveedores de servicios en la nube con varias herramientas para administrar las bases de datos de MongoDB en un entorno de producción.
En este tutorial, aprenderemos cómo construir e implementar un servidor GraphQL conectado a una fuente de datos MongoDB. Al final de este tutorial, habrá creado una API GraphQL funcional utilizando Apollo Server y MongoDB Atlas y la habrá implementado en producción en Koyeb.
Requisitos
Para seguir con éxito este tutorial, necesita lo siguiente:
- Una máquina de desarrollo con Node.js instalado. La aplicación de demostración de este tutorial usa la versión 16.14.0 de Node.js
- Una máquina de desarrollo con Git instalado
- Una cuenta de MongoDB Atlas
- Una cuenta de Koyeb para implementar la aplicación
Pasos
Los pasos para crear una API GraphQL con Apollo DataSource y MongoDB Atlas e implementarla en producción en Koyeb incluyen:
- Cree una base de datos MongoDB usando MongoDB Atlas
- Configurar el proyecto
- Cree un servidor GraphQL usando Apollo Server
- Conecte el servidor GraphQL a la base de datos MongoDB
- Usar MongoDB como fuente de datos de GraphQL
- Implementar en Koyeb
Crear una base de datos MongoDB usando Mongo Atlas
MongoDB Atlas ofrece la capacidad de crear bases de datos MongoDB implementadas en la nube con solo unos pocos clics y, en esta sección, creará una base de datos MongoDB utilizando MongoDB Atlas.
Mientras está conectado a su cuenta de MongoDB Atlas, haga clic en el botón "Crear una base de datos" en la página "Despliegues de datos" y siga los siguientes pasos:
- Haga clic en el botón "Crear" en su tipo de implementación preferido.
- Seleccione un proveedor de nube y una región preferidos o use las opciones preseleccionadas.
- Ingrese un nombre de clúster o use el nombre de clúster predeterminado.
- Haga clic en el botón "Crear clúster".
- Seleccione la opción de autenticación "Nombre de usuario y contraseña", ingrese un nombre de usuario y una contraseña y haga clic en el botón "Crear usuario". Guarde el nombre de usuario y la contraseña en un lugar seguro para su uso posterior.
- Ingrese "0.0.0.0/0" sin las comillas en el campo Dirección IP de la sección Lista de acceso IP y haga clic en el botón "Agregar entrada".
- Haga clic en el botón "Finalizar y cerrar" y luego en el botón "Ir a bases de datos". Será redirigido a la página "Despliegues de datos", con su nuevo clúster de MongoDB ahora visible.
- Haga clic en el botón "Conectar" junto al nombre de su clúster MongoDB, seleccione la opción "Conectar su aplicación" y copie la cadena de conexión de su base de datos en un lugar seguro para su uso posterior.
Siguiendo los pasos anteriores, ha creado una base de datos MongoDB para leer y almacenar datos para la API de GraphQL. En la siguiente sección, configurará el proyecto e instalará las bibliotecas y dependencias necesarias.
Configurar el proyecto
En esta sección, configurará un proyecto npm e instalará las dependencias necesarias para construir el servidor GraphQL de demostración para este tutorial. El servidor GraphQL expondrá una API GraphQL que lee y escribe datos de películas desde y hacia la base de datos MongoDB creada en la sección anterior. Comience por crear un directorio raíz para el proyecto en su máquina de desarrollo. Para hacer eso, ejecute el siguiente comando en la ventana de su terminal:
mkdir graphql_movies
Las graphql_movies
El directorio creado por el comando anterior es el directorio raíz de la aplicación de demostración. A continuación, cambie a graphql_movies
directorio e inicialice un repositorio de Git en el directorio ejecutando el siguiente comando en la ventana de su terminal:
cd graphql_movies
git init
El primer comando anterior lo lleva a graphql_movies
directorio en su terminal, mientras que el segundo comando inicializa un repositorio de Git para realizar un seguimiento de los cambios en graphql_movies
directorio. A continuación, cree un proyecto npm en graphql_movies
directorio ejecutando el siguiente comando en la ventana de su terminal:
npm init --yes
Ejecutando npm init
El comando inicializa un proyecto npm vacío y crea un package.json
archivo en el directorio raíz. El --yes
flag responde automáticamente "sí" a todas las solicitudes planteadas por npm.
Con un proyecto npm ahora en su lugar, continúe e instale las bibliotecas y los paquetes necesarios para compilar la API de GraphQL. En la ventana de su terminal, ejecute los siguientes comandos:
npm install apollo-server graphql mongoose apollo-datasource-mongodb dotenv rimraf
npm install -D @babel/preset-env @babel/core @babel/node @babel/cli
La npm install
El comando anterior instala 10 paquetes en el proyecto y los agrega al package.json
del proyecto. expediente. El primer comando instala las dependencias necesarias para ejecutar la aplicación, mientras que el segundo instala las dependencias necesarias durante el desarrollo de la aplicación. Las dependencias instaladas incluyen:
- apollo-server:una biblioteca de código abierto para crear servidores GraphQL.
- graphql:La implementación JavaScript de la especificación GraphQL.
- mongoose:un mapeador de documentos de objetos para MongoDB.
- apollo-datasource-mongodb:una biblioteca de fuente de datos Apollo para MongoDB.
- dotenv:una biblioteca para manejar variables de entorno.
- rimraf:una biblioteca para ejecutar UNIX
rm -rf
comando en Node.js.
Las otras bibliotecas instaladas para el desarrollo incluyen una gran cantidad de babel
bibliotecas para ejecutar y transpilar código JavaScript moderno.
A continuación, crea un .babelrc
archivo en el directorio raíz del proyecto y agregue el siguiente código al archivo:
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": "3.0.0"
}
]
]
}
El código anterior instruye a Babel sobre cómo transpilar el código JavaScript más reciente presente en la aplicación utilizando env
de Babel. opciones de configuración.
Por último, crea un src
carpeta en el directorio raíz del proyecto. Este src
La carpeta albergará todos los archivos del proyecto. Con estos cambios, la estructura del proyecto está en su lugar y, en la siguiente sección, creará un servidor GraphQL utilizando la biblioteca del servidor Apollo.
Cree un servidor GraphQL usando Apollo Server
En esta sección, creará un servidor GraphQL usando Apollo Server. La biblioteca de Apollo Server viene con un servidor Express incorporado y puede ejecutar consultas y mutaciones de GraphQL. También proporciona un espacio aislado en el navegador para conectarse a un servidor GraphQL, escribir y ejecutar consultas GraphQL, ver los resultados de las consultas y explorar el esquema GraphQL del servidor.
Un servidor GraphQL consta de un esquema GraphQL que define la estructura de su API y los solucionadores que implementan la estructura del esquema. Un esquema de GraphQL consta de types
, que describe los datos que el servidor GraphQL puede consultar y devolver. GraphQL proporciona un lenguaje de definición de esquemas (SDL) que se utiliza para definir un esquema de GraphQL. Usando SDL de GraphQL, un tipo de película se puede definir de la siguiente manera:
type Movie {
_id: ID!
title: String!
rating: Float!
year: Int!
}
La Movie
type above define los cuatro campos que se pueden consultar en una película y su tipo de devolución. GraphQL también tiene tres tipos de raíz; query
, mutation
y subscription
. Estos tres tipos sirven como puntos de entrada a un servidor GraphQL y definen las posibles operaciones ejecutables en un servidor GraphQL. La query
type es para operaciones de obtención de datos, la mutation
type es para operaciones de creación o modificación de datos, y subscription
type es para operaciones de obtención de datos en tiempo real.
Para crear un esquema para el servidor GraphQL, cree un typeDefs.js
archivo en el src
carpeta y agregue el siguiente código al archivo:
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!
}
`;
El código anterior es una definición de tipo de esquema de GraphQL y define tres tipos de GraphQL; Movie
, Query
y Mutation
. La Query
y Mutation
son los tipos raíz, mientras que Movie
La mutación define los campos consultables para registros de películas.
La Query
tipo en la definición de esquema anterior incluye los siguientes campos:
getMovies
:este campo devuelve una matriz de uno o másMovie
escribir objetos.getMovie
:Este campo acepta unID
argumento y devuelve una solaMovie
tipo de objeto.
Además, la mutation
tipo incluye un createMovie
campo que acepta un title
, rating
y un year
argumento y devuelve una Movie
tipo de objeto. Estos campos representan las consultas y mutaciones aceptadas por el servidor GraphQL.
Cuando se ejecutan las consultas y mutaciones en los tipos raíz, GraphQL espera que sus respectivas funciones de resolución obtengan y devuelvan los datos correspondientes al tipo de retorno del esquema. Para agregar funciones de resolución, cree un resolvers.js
archivo en el src
directorio y agregue el siguiente código al archivo:
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;
}
}
}
En el código anterior, inicializamos una matriz de películas que sirve como fuente de datos temporal. Además de eso, exportamos un resolvers
objeto con Query
y Mutation
propiedades que coinciden con la Query
y Mutation
tipos en la definición del esquema. Las dos propiedades de resolución incluyen funciones que coinciden con las operaciones declaradas en Query
y Mutation
tipos Estas funciones de resolución realizan acciones específicas en la fuente de datos y devuelven los datos solicitados.
Una función de resolución de GraphQL acepta cuatro argumentos:
root
:este argumento contiene los resultados de cualquier resolución ejecutada anteriormente.args
:este argumento contiene los parámetros para una consulta de GraphQL.context
:este argumento contiene datos/objetos a los que se puede acceder/compartir entre funciones de resolución.info
:este argumento contiene información sobre la consulta o mutación de GraphQL que se está ejecutando.
El esquema y los resolutores creados deben estar conectados a un servidor para que funcionen. En el src
directorio, cree un index.js
archivo y agregue la siguiente pieza de código al archivo:
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}`);
});
El código anterior importa y crea una instancia del servidor Apollo. El esquema (typeDefs
) y los resolutores también se importan al archivo y se pasan a la instancia del servidor Apollo. Finalmente, listen
de Apollo Server El método inicia el servidor web en el puerto proporcionado o en el puerto 4000 si no se proporciona ningún puerto.
Para ejecutar el servidor, agregue el siguiente script a package.json
archivo ubicado en el directorio raíz:
{
...
"scripts": {
…
"start:dev": "babel-node src/index.js"
},
...
}
El start:dev
el script anterior ejecuta el código en src/index.js
archivo usando el babel-node
paquete. Para ejecutar el script, ejecute el siguiente comando en la ventana de su terminal:
npm run start:dev
El comando anterior inicia el servidor web, que se ejecuta en el puerto 4000. Ejecutar el comando debería devolver la respuesta a continuación:
🚀 Server ready at http://localhost:4000/
Para ver la página de inicio de Apollo Server, visite http://localhost:4000/
en tu navegador. Debería ver una página como la siguiente:
En la página de destino, haga clic en el botón "Consultar su servidor" para ser redirigido a la zona de pruebas del navegador. Debería ver una página como la siguiente, con una consulta GraphQL precompletada:
El arenero consta de tres paneles; el panel izquierdo muestra el esquema de la API de GraphQL con consultas y mutaciones disponibles, el panel central es para escribir y ejecutar consultas, y el panel derecho es para ver los resultados de las consultas. Reemplace la consulta en su sandbox con el siguiente código:
query ExampleQuery {
getMovies {
_id
title
year
rating
}
}
El código anterior agrega campos adicionales a ExampleQuery
consulta. Para ejecutar la consulta, haga clic en el botón "ExampleQuery" para ejecutar la consulta. Deberías ver la respuesta en el panel derecho.
En esta sección, creó un servidor GraphQL con consultas y mutación. En la siguiente sección, conectará el servidor GraphQL a una base de datos MongoDB.
Conectar el servidor GraphQL a la base de datos de Mongo
Las funciones de resolución en el servidor GraphQL actualmente obtienen datos de una fuente de datos codificada en lugar de la base de datos MongoDB creada en la primera sección. En esta sección, conectará el servidor GraphQL a la base de datos MongoDB y también creará un modelo mangosta para representar un documento de película en MongoDB.
Primero, crea un .env
archivo en el directorio raíz del proyecto y agregue el siguiente código al archivo donde <username>
y <password>
represente su usuario de la base de datos MongoDB y su contraseña:
MONGODB_URI="mongodb+srv://<username>:<password>@apollogql-demo.kk9qw.mongodb.net/apollogql-db?retryWrites=true&w=majority"
El código anterior hace que la cadena de conexión de su base de datos MongoDB esté disponible como una variable de entorno. El .env
el archivo no debe enviarse a git ya que contiene datos secretos.
A continuación, reemplace el código en src/index.js
archivo con lo siguiente:
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}`);
});
El código anterior importa el dotenv
config y mongoose
paquete en index.js
expediente. Importando el dotenv
config crea las variables de entorno en .env
archivo accesible a través de process.env
objeto. El valor de MONGODB_URI
Se accede a la variable de entorno a través de process.env
y almacenado en un uri
variable y una función asíncrona main
se declara para crear una conexión a la base de datos de MongoDB usando la mangosta connect
función y el uri
Cadena de conexión. El main()
Luego se llama a la función para abrir una conexión a la base de datos MongoDB.
🎉 connected to database successfully
🚀 Server ready at http://localhost:4000/
Por último, crea un models
carpeta en el src
carpeta y dentro de ella, crea un movie.js
expediente. Agregue el siguiente código al archivo:
import mongoose from "mongoose";
export const Movie = mongoose.model("Movie", {
title: String,
rating: Number,
year: Number,
});
El código anterior crea una Movie
modelo, y sirve como interfaz para crear y manipular documentos en la base de datos MongoDB. Este es el último paso para hacer de la base de datos MongoDB la fuente de datos para el servidor GraphQL. En la siguiente sección, cambiará la fuente de datos del servidor GraphQL de la matriz codificada a su base de datos MongoDB.
Usar MongoDB como fuente de datos de GraphQL
La fuente de datos actual para el servidor GraphQL es una matriz codificada y, en esta sección, la reemplazará con su base de datos MongoDB. Para hacer eso, comience creando un dataSources
carpeta en el src
carpeta. En las dataSources
carpeta, crea un movies.js
archivo y agregue el siguiente código al archivo:
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 });
}
}
El código anterior declara un Movies
clase de fuente de datos que extiende el MongoDataSource
clase proporcionada por apollo-datasource-mongodb
paquete. Las Movies
El origen de datos contiene tres métodos para cada una de las consultas y mutaciones existentes. El getMovies
y createMovie
Los métodos usan el modelo de película creado en la sección anterior para leer e insertar datos en la base de datos de MongoDB, y el getMovie
método utiliza el findOneById
método proporcionado por MongoDataSource
class para obtener un documento de la colección MongoDB que coincida con el id
proporcionado argumento.
A continuación, reemplace el código en src/index.js
archivo con el siguiente código:
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}`);
});
El código actualizado anterior importa la Movie
modelo y las Movies
clase de origen de datos en src/index.js
expediente. Después de conectarse a la base de datos MongoDB, un dataSources
se crea la función. Esta función devuelve un objeto que contiene una instancia de Movies
fuente de datos que recibe la Movie
modelo como parámetro. Las dataSources
Luego, la función se pasa a la instancia del servidor Apollo, lo que hace que Movies
instancia de fuente de datos disponible dentro de cada función de resolución.
Para reemplazar la fuente de datos codificada con la Movie
fuente de datos, reemplace el código en src/resolvers.js
archivo con el siguiente código:
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)
}
}
}
En el código actualizado anterior, las Movies
instancia de fuente de datos pasada a Apollo Server en src/index.js
El archivo está disponible en las funciones de resolución a través de dataSources
propiedad del objeto de contexto compartido. Cada función de resolución llama a su método respectivo en la fuente de datos para llevar a cabo la operación especificada en la base de datos MongoDB.
Cualquier consulta realizada en este punto devolverá un resultado vacío ya que la base de datos MongoDB está actualmente vacía. Reinicie su servidor, luego visite su cuenta de Mongo Atlas en su navegador. En la página "Despliegues de bases de datos" de MongoDB, seleccione el clúster de su base de datos y haga clic en la pestaña "Colecciones". En la pestaña "Colecciones", haga clic en el botón "INSERTAR DOCUMENTO" y agregue tantos documentos de películas como desee.
En su sandbox de Apollo Server, ejecute ExampleQuery
de la sección anterior. Debería obtener una lista de todos los documentos de películas en su colección Mongo DB. En esta sección, utilizó su base de datos MongoDB como fuente de datos para su servidor GraphQL. En la siguiente sección, implementará su servidor GraphQL en línea en Koyeb.
Implementar en Koyeb
El primer paso para implementar el servidor GraphQL en Koyeb es agregar los scripts npm necesarios para compilar el código en producción. Agregue los siguientes scripts a continuación a su package.json
expediente:
"scripts": {
...
"prebuild": "rimraf dist && mkdir dist",
"build": "babel src -d dist",
"start": "node ./dist/index.js"
}
Los tres scripts npm agregados anteriormente incluyen:
- Una
prebuild
secuencia de comandos para asegurarse de que haya undist
vacío directorio antes debuild
se ejecuta el script. - Una
build
script que transpila todo el código en elsrc
directorio a la sintaxis de JavaScript ES5 en eldist
directorio con la ayuda debabel
paquete. - Un
start
script que inicia el servidor.
Luego, cree un repositorio de GitHub para su servidor GraphQL, luego ejecute los siguientes comandos en la ventana de su 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
En tu panel de control de Koyeb, ve a Secrets
pestaña y crea un nuevo secreto. Introduzca MONGODB_URI
como nombre secreto y su cadena de conexión MongoDB como valor. A continuación, vaya a Overview
y haga clic en el botón "Crear aplicación" para iniciar el proceso de creación de la aplicación.
En la página de creación de la aplicación:
- Seleccione GitHub como su método de implementación.
- En el menú desplegable de repositorios, seleccione el repositorio de GitHub para su código.
- Seleccione la rama que desea implementar. P.ej.
main
. - En la sección de variables de entorno, haga clic en el botón Agregar variable de entorno.
- Seleccione el
Secret
escribe, ingresaMONGODB_URI
como clave y seleccioneMONGODB_URI
secreto creado previamente como el valor. - Agregue una variable de entorno de texto sin formato con la clave
PORT
y valor8080
. - Dé un nombre a su aplicación. P.ej.
graphql-apollo-server
y haga clic en el botón "Crear aplicación".
Al crear la aplicación, run
y build
las opciones de comando se omitieron ya que la plataforma Koyeb puede detectar la build
y start
scripts en el package.json
archivarlos y ejecutarlos automáticamente. Al hacer clic en el botón "Crear aplicación", se le redirige a la página de implementación, donde puede monitorear el proceso de implementación de la aplicación. Una vez que se completa la implementación y se han superado todas las comprobaciones de estado necesarias, puede acceder a su URL pública.
Pruebe su API de GraphQL
Usando su herramienta de prueba de API favorita o este patio de recreo GraphiQL en línea, haga un getMovies
Consulta GraphQL a su URL pública. Debería obtener una respuesta de todos los documentos de la película en su base de datos MongoDB.
Conclusión
¡Eso es todo! Ha creado e implementado con éxito un servidor GraphQL con Apollo Server y una fuente de datos MongoDB en Koyeb. Siéntase libre de agregar más consultas y mutaciones a su servidor GraphQL. Dado que implementamos en Koyeb mediante la implementación impulsada por git, se activará e implementará automáticamente una nueva compilación en Koyeb cada vez que envíe sus cambios a su repositorio de GitHub.
Sus cambios se activarán tan pronto como su implementación pase todas las comprobaciones de estado necesarias. En caso de falla durante la implementación, Koyeb mantiene la última implementación funcional en producción para garantizar que su aplicación esté siempre en funcionamiento.
Al implementarse en Koyeb, nuestra aplicación se beneficia del equilibrio de carga global nativo, el escalado automático, la reparación automática y el cifrado HTTPS (SSL) automático sin configuración de nuestra parte.
Si desea ver el código de la aplicación de demostración, puede encontrarlo aquí.