sql >> Base de Datos >  >> NoSQL >> MongoDB

Implemente una API de GraphQL con MongoDB Atlas y Apollo Server en Koyeb

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:

  1. Cree una base de datos MongoDB usando MongoDB Atlas
  2. Configurar el proyecto
  3. Cree un servidor GraphQL usando Apollo Server
  4. Conecte el servidor GraphQL a la base de datos MongoDB
  5. Usar MongoDB como fuente de datos de GraphQL
  6. 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ás Movie escribir objetos.
  • getMovie :Este campo acepta un ID argumento y devuelve una sola Movie 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 un dist vacío directorio antes de build se ejecuta el script.
  • Una build script que transpila todo el código en el src directorio a la sintaxis de JavaScript ES5 en el dist directorio con la ayuda de babel 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, ingresa MONGODB_URI como clave y seleccione MONGODB_URI secreto creado previamente como el valor.
  • Agregue una variable de entorno de texto sin formato con la clave PORT y valor 8080 .
  • 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í.