Creación de API de GraphQL con Node
Publicado: 2022-12-20GraphQL es la nueva palabra de moda en el desarrollo de API. Si bien las API RESTful siguen siendo la forma más popular de exponer datos de aplicaciones, vienen con muchas limitaciones que GraphQL pretende resolver.
GraphQL es un lenguaje de consulta creado por Facebook, que se convirtió en un proyecto de código abierto en 2015. Ofrece una sintaxis intuitiva y flexible para describir y acceder a datos en una API.
Esta guía explorará cómo construir un proyecto GraphQL Node.js. Usaremos GraphQL para crear una aplicación Todo en el marco web Express.js para Node.
¿Qué es GraphQL?
De la documentación oficial: “GraphQL es un lenguaje de consulta para API y un tiempo de ejecución para cumplir con esas consultas con sus datos existentes. GraphQL brinda una descripción completa y comprensible de los datos en su API, brinda a los clientes el poder de solicitar exactamente lo que necesitan y nada más, facilita la evolución de las API con el tiempo y habilita herramientas poderosas para desarrolladores”.
GraphQL es un tiempo de ejecución del lado del servidor para ejecutar consultas utilizando el sistema de tipos que definió para sus datos. Además, GraphQL no está vinculado a ninguna base de datos o motor de almacenamiento específico. En cambio, está respaldado por su código existente y almacén de datos. Puede obtener una comparación detallada de estas tecnologías con la guía GraphQL vs. RESTful API.
Para crear un servicio GraphQL, comienza definiendo tipos de esquema y creando campos usando esos tipos. A continuación, proporciona una función de resolución para que se ejecute en cada campo y escriba cada vez que el lado del cliente solicite datos.
Terminología de GraphQL
El sistema de tipos GraphQL se usa para describir qué datos se pueden consultar y qué datos se pueden manipular. Es el núcleo de GraphQL. Analicemos las diferentes formas en que podemos describir y manipular datos en GraphQ.
Tipos
Los tipos de objetos de GraphQL son modelos de datos que contienen campos fuertemente tipados. Debería haber un mapeo 1 a 1 entre sus modelos y los tipos de GraphQL. A continuación se muestra un ejemplo de tipo GraphQL:
type User { id: ID! # The "!" means required firstname: String lastname: String email: String username: String todos: [Todo] # Todo is another GraphQL type }
Consultas
GraphQL Query define todas las consultas que un cliente puede ejecutar en la API de GraphQL. Debe definir un RootQuery que contendrá todas las consultas existentes por convención.
A continuación, definimos y asignamos las consultas a la API RESTful correspondiente:
type RootQuery { user(id: ID): User # Corresponds to GET /api/users/:id users: [User] # Corresponds to GET /api/users todo(id: ID!): Todo # Corresponds to GET /api/todos/:id todos: [Todo] # Corresponds to GET /api/todos }
Mutaciones
Si las consultas de GraphQL son solicitudes GET , las mutaciones son solicitudes POST , PUT , PATCH y DELETE que manipulan la API de GraphQL.
Pondremos todas las mutaciones en una sola RootMutation para demostrar:
type RootMutation { createUser(input: UserInput!): User # Corresponds to POST /api/users updateUser(id: ID!, input: UserInput!): User # Corresponds to PATCH /api/users removeUser(id: ID!): User # Corresponds to DELETE /api/users createTodo(input: TodoInput!): Todo updateTodo(id: ID!, input: TodoInput!): Todo removeTodo(id: ID!): Todo }
Notaste el uso de tipos de entrada para las mutaciones como UserInput , TodoInput . Siempre es una buena práctica definir siempre los tipos de entrada para crear y actualizar sus recursos.
Puede definir los tipos de entrada como el siguiente:
input UserInput { firstname: String! lastname: String email: String! username: String! }
Resolutores
Los solucionadores le dicen a GraphQL qué hacer cuando se solicita cada consulta o mutación. Es una función básica que hace el trabajo duro de acceder a la capa de la base de datos para realizar las operaciones CRUD (crear, leer, actualizar, eliminar), acceder a un punto final interno de API RESTful o llamar a un microservicio para cumplir con la solicitud del cliente.
Puede crear un nuevo archivo resolvers.js y agregar el siguiente código:
import sequelize from '../models'; export default function resolvers () { const models = sequelize.models; return { // Resolvers for Queries RootQuery: { user (root, { id }, context) { return models.User.findById(id, context); }, users (root, args, context) { return models.User.findAll({}, context); } }, User: { todos (user) { return user.getTodos(); } }, } // Resolvers for Mutations RootMutation: { createUser (root, { input }, context) { return models.User.create(input, context); }, updateUser (root, { id, input }, context) { return models.User.update(input, { ...context, where: { id } }); }, removeUser (root, { id }, context) { return models.User.destroy(input, { ...context, where: { id } }); }, // ... Resolvers for Todos go here } }; }
Esquema
El esquema de GraphQL es lo que GraphQL expone al mundo. Por lo tanto, los tipos, consultas y mutaciones se incluirán dentro del esquema para ser expuestos al mundo.
A continuación se muestra cómo exponer tipos, consultas y mutaciones al mundo:
schema { query: RootQuery mutation: RootMutation }
En el script anterior, incluimos RootQuery y RootMutation que creamos anteriormente para exponerlos al mundo.
¿Cómo funciona GraphQL con Nodejs y Expressjs?
GraphQL proporciona una implementación para todos los principales lenguajes de programación y Node.js no está exento. En el sitio web oficial de GraphQL, hay una sección para compatibilidad con JavaScript, y también hay otras implementaciones de GraphQL para simplificar la escritura y la codificación en GraphQL.
GraphQL Apollo proporciona una implementación para Node.js y Express.js y facilita comenzar con GraphQL.
En la siguiente sección, aprenderá cómo crear y desarrollar su primera aplicación GraphQL en Nodes.js y Express.js backend framework usando GraphQL Apollo.
Configuración de GraphQL con Express.js
Comenzar a construir un servidor API GraphQL con Express.js es sencillo. En esta sección, exploraremos cómo construir un servidor GraphQL.
Inicializar proyecto con Express
Primero, debe instalar y configurar un nuevo proyecto Express.js.
Cree una carpeta para su proyecto e instale Express.js usando este comando:
cd <project-name> && npm init -y npm install express
El comando anterior crea un nuevo archivo package.json e instala la biblioteca Express.js en su proyecto.
A continuación, estructuraremos nuestro proyecto como se muestra en la imagen de abajo. Contendrá diferentes módulos para las características del proyecto, como usuarios, todos, etc.
Inicializar GraphQL
Comencemos instalando las dependencias de GraphQL Express.js. Ejecute el siguiente comando para instalar:
npm install apollo-server-express graphql @graphql-tools/schema --save
Creación de esquemas y tipos
A continuación, crearemos un archivo index.js dentro de la carpeta de módulos y agregaremos el siguiente fragmento de código:
const { gql } = require('apollo-server-express'); const users = require('./users'); const todos = require('./todos'); const { GraphQLScalarType } = require('graphql'); const { makeExecutableSchema } = require('@graphql-tools/schema'); const typeDefs = gql` scalar Time type Query { getVersion: String! } type Mutation { version: String! } `; const timeScalar = new GraphQLScalarType({ name: 'Time', description: 'Time custom scalar type', serialize: (value) => value, }); const resolvers = { Time: timeScalar, Query: { getVersion: () => `v1`, }, }; const schema = makeExecutableSchema({ typeDefs: [typeDefs, users.typeDefs, todos.typeDefs], resolvers: [resolvers, users.resolvers, todos.resolvers], }); module.exports = schema;
Tutorial de código
Analicemos el fragmento de código y desglosémoslo:
Paso 1
Primero, importamos las bibliotecas requeridas y creamos tipos de consulta y mutación predeterminados. La consulta y la mutación solo establecen la versión de la API de GraphQL por ahora. Sin embargo, ampliaremos la consulta y la mutación para incluir otros esquemas a medida que avancemos.
Paso 2:
Luego, creamos un nuevo tipo escalar para el tiempo y nuestro primer solucionador para la consulta y la mutación creadas anteriormente. Además, también generamos un esquema utilizando la función makeExecutableEchema .
El esquema generado incluye todos los demás esquemas que importamos y también incluirá más cuando los creemos e importemos.
El fragmento de código anterior muestra que importamos diferentes esquemas a la función makeExecutableEchema. Este enfoque nos ayuda a estructurar la aplicación para la complejidad. A continuación, vamos a crear los esquemas Todo y Usuario que importamos.
Creación de un esquema Todo
El esquema Todo muestra operaciones CRUD simples que pueden realizar los usuarios de la aplicación. A continuación se muestra el esquema que implementa la operación Todo CRUD.
const { gql } = require('apollo-server-express'); const createTodo = require('./mutations/create-todo'); const updateTodo = require('./mutations/update-todo'); const removeTodo = require('./mutations/delete-todo'); const todo = require('./queries/todo'); const todos = require('./queries/todos'); const typeDefs = gql` type Todo { id: ID! title: String description: String user: User } input CreateTodoInput { title: String! description: String isCompleted: Boolean } input UpdateTodoInput { title: String description: String isCompleted: Boolean } extend type Query { todo(id: ID): Todo! todos: [Todo!] } extend type Mutation { createTodo(input: CreateTodoInput!): Todo updateTodo(id: ID!, input: UpdateTodoInput!): Todo removeTodo(id: ID!): Todo } `; // Provide resolver functions for your schema fields const resolvers = { // Resolvers for Queries Query: { todo, todos, }, // Resolvers for Mutations Mutation: { createTodo, updateTodo, removeTodo, }, }; module.exports = { typeDefs, resolvers };
Tutorial de código
Analicemos el fragmento de código y desglosémoslo:
Paso 1:
Primero, creamos un esquema para nuestro Todo usando GraphQL type , input y extend . La palabra clave extend se usa para heredar y agregar nuevas consultas y mutaciones a la consulta raíz y la mutación existentes que creamos anteriormente.
Paso 2:
A continuación, creamos un resolver, que se usa para recuperar los datos correctos cuando se llama a una consulta o mutación en particular.
Con la función de resolución en su lugar, podemos crear métodos individuales para la lógica empresarial y la manipulación de la base de datos como se muestra en el ejemplo de create-todo.js .
Cree un archivo create-user.js en la carpeta <code>./mutations</code> y agregue la lógica comercial para crear un Todo nuevo en su base de datos.
const models = require('../../../models'); module.exports = async (root, { input }, context) => { return models.todos.push({ ...input }); };
El fragmento de código anterior es una forma simplificada de crear un Todo nuevo en nuestra base de datos utilizando el ORM Sequelize. Puede obtener más información sobre Sequelize y cómo configurarlo con Node.js.
Puede seguir el mismo paso para crear muchos esquemas según su aplicación o puede clonar el proyecto completo desde GitHub.
A continuación, configuraremos el servidor con Express.js y ejecutaremos la aplicación Todo recién creada con GraphQL y Node.js.
Configuración y ejecución del servidor
Por último, configuraremos nuestro servidor utilizando la biblioteca apollo-server-express que instalamos anteriormente y lo configuraremos.
El apollo-server-express es un contenedor simple de Apollo Server para Express.js. Se recomienda porque se ha desarrollado para adaptarse al desarrollo de Express.js.
Usando los ejemplos que discutimos anteriormente, configuremos el servidor Express.js para que funcione con el apollo-server-express recién instalado.
Cree un archivo server.js en el directorio raíz y pegue el siguiente código:
const express = require('express'); const { ApolloServer } = require('apollo-server-express'); const schema = require('./modules'); const app = express(); async function startServer() { const server = new ApolloServer({ schema }); await server.start(); server.applyMiddleware({ app }); } startServer(); app.listen({ port: 3000 }, () => console.log(`Server ready at http://localhost:3000`) );
En el código anterior, ha creado con éxito su primer servidor CRUD GraphQL para Todos y Usuarios. Puede iniciar su servidor de desarrollo y acceder al área de juegos usando http://localhost:3000/graphql. Si todo es exitoso, se le debe presentar la siguiente pantalla:
Resumen
GraphQL es una tecnología moderna respaldada por Facebook que simplifica el tedioso trabajo que implica la creación de API a gran escala con patrones de arquitectura RESTful.
Esta guía ha aclarado GraphQL y demostrado cómo desarrollar su primera API de GraphQL con Express.js.
Háganos saber lo que crea con GraphQL.