API GraphQL con TypeScript: Tutorial Paso a Paso
GraphQL es un lenguaje de consulta para APIs que permite a los clientes solicitar solo los datos que necesitan. Combinado con TypeScript, el tipado estático ayuda a evitar errores en la etapa de desarrollo y hace que el código sea más predecible. En este tutorial, crearemos una API GraphQL completa usando Apollo Server y TypeScript.
Cubriremos: configuración del proyecto, definición de esquemas y tipos, implementación de resolvers, mutaciones para modificación de datos e integración con base de datos (en memoria para simplificar). Al final del artículo, podrás ejecutar tu propio servidor GraphQL.
1. Preparación del Proyecto e Instalación de Dependencias
Primero, creemos un nuevo proyecto Node.js e instalemos los paquetes necesarios.
mkdir graphql-typescript-tutorial
cd graphql-typescript-tutorial
npm init -y
npm install apollo-server graphql
npm install -D typescript @types/node ts-node nodemon
Creemos el archivo tsconfig.json:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"rootDir": "./src",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
},
"include": ["src/**/*"]
}
La estructura del proyecto será la siguiente:
src/index.ts— punto de entradasrc/schema.ts— esquema GraphQLsrc/resolvers.ts— resolverssrc/types.ts— tipos TypeScript
2. Definición de Tipos GraphQL y Esquema
El esquema GraphQL describe qué datos están disponibles y cómo solicitarlos. Para este ejemplo, crearemos un sistema simple de gestión de usuarios y publicaciones.
Creemos src/types.ts:
export interface User {
id: number;
name: string;
email: string;
}
export interface Post {
id: number;
title: string;
content: string;
authorId: number;
}
export interface CreateUserInput {
name: string;
email: string;
}
export interface CreatePostInput {
title: string;
content: string;
authorId: number;
}
Ahora creemos src/schema.ts con las definiciones de tipos GraphQL:
import { gql } from 'apollo-server';
export const typeDefs = gql`
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
}
type Post {
id: ID!
title: String!
content: String!
author: User!
}
input CreateUserInput {
name: String!
email: String!
}
input CreatePostInput {
title: String!
content: String!
authorId: ID!
}
type Query {
users: [User!]!
user(id: ID!): User
posts: [Post!]!
post(id: ID!): Post
}
type Mutation {
createUser(input: CreateUserInput!): User!
createPost(input: CreatePostInput!): Post!
}
`;
Nota: usamos tipos input para las mutaciones — esta es una práctica estándar en GraphQL.
3. Implementación de Resolvers con TypeScript
Los resolvers son funciones que devuelven datos para cada campo del esquema. Creemos src/resolvers.ts:
import { User, Post, CreateUserInput, CreatePostInput } from './types';
// Base de datos en memoria
let users: User[] = [
{ id: 1, name: 'Alice', email: 'alice@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' },
];
let posts: Post[] = [
{ id: 1, title: 'GraphQL Basics', content: '...', authorId: 1 },
{ id: 2, title: 'TypeScript Guide', content: '...', authorId: 2 },
];
let nextUserId = 3;
let nextPostId = 3;
export const resolvers = {
Query: {
users: (): User[] => users,
user: (_: unknown, args: { id: string }): User | undefined =>
users.find(u => u.id === Number(args.id)),
posts: (): Post[] => posts,
post: (_: unknown,