Введение в GraphQL API с TypeScript
GraphQL — это современный язык запросов для API, который позволяет клиентам запрашивать только те данные, которые им действительно нужны. В сочетании с TypeScript, который добавляет строгую типизацию, разработка становится более предсказуемой и безопасной. В этом пошаговом туториале мы создадим полноценный GraphQL API на TypeScript, используя популярные инструменты и лучшие практики.
Почему стоит выбрать GraphQL с TypeScript? Во-первых, вы получаете автодополнение и проверку типов на этапе компиляции. Во-вторых, GraphQL позволяет объединять несколько запросов в один, уменьшая количество сетевых запросов. В-третьих, TypeScript идеально подходит для описания сложных графовых структур данных.
Настройка проекта и установка зависимостей
Для начала создадим новый проект и установим необходимые пакеты. Мы будем использовать Apollo Server — самый популярный сервер для GraphQL, и TypeGraphQL для удобной интеграции с TypeScript.
mkdir graphql-ts-tutorial
cd graphql-ts-tutorial
npm init -y
npm install apollo-server graphql reflect-metadata class-validator
npm install typescript type-graphql @types/node --save-dev
npx tsc --init
После установки настроим tsconfig.json. Убедитесь, что включены следующие опции:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["ES2020"],
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true
}
}
Создадим структуру папок:
src/
├── index.ts
├── resolvers/
│ └── user.resolver.ts
├── schemas/
│ └── user.schema.ts
└── data/
└── users.ts
Создание схемы и типов данных
В TypeGraphQL типы данных описываются с помощью декораторов. Создадим модель пользователя и тип входных данных для мутации.
// src/schemas/user.schema.ts
import { ObjectType, Field, ID, InputType } from "type-graphql";
@ObjectType()
export class User {
@Field(() => ID)
id!: number;
@Field()
name!: string;
@Field()
email!: string;
@Field({ nullable: true })
age?: number;
}
@InputType()
export class CreateUserInput {
@Field()
name!: string;
@Field()
email!: string;
@Field({ nullable: true })
age?: number;
}
Обратите внимание на использование @ObjectType() для описания возвращаемых типов и @InputType() для входных параметров. Это позволяет TypeGraphQL автоматически генерировать GraphQL-схему.
Реализация резолверов
Резолверы — это функции, которые обрабатывают запросы и возвращают данные. Создадим простой in-memory массив для хранения пользователей.
// src/data/users.ts
import { User } from "../schemas/user.schema";
export const users: User[] = [
{ id: 1, name: "Иван Петров", email: "ivan@example.com", age: 28 },
{ id: 2, name: "Мария Сидорова", email: "maria@example.com", age: 32 },
];
Теперь напишем резолверы для запросов и мутаций:
// src/resolvers/user.resolver.ts
import { Resolver, Query, Mutation, Arg, Int } from "type-graphql";
import { User, CreateUserInput } from "../schemas/user.schema";
import { users } from "../data/users";
@Resolver()
export class UserResolver {
@Query(() => [User])
async getAllUsers(): Promise<User[]> {
return users;
}
@Query(() => User, { nullable: true })
async getUserById(
@Arg("id", () => Int) id: number
): Promise<User | undefined> {
return users.find(user => user.id === id);
}
@Mutation(() => User)
async createUser(
@Arg("input") input: CreateUserInput
): Promise<User> {
const newUser: User = {
id: users.length + 1,
...input,
};
users.push(newUser);
return newUser;
}
}
Декораторы @Query и @Mutation указывают тип операции. @Arg используется для привязки аргументов запроса к параметрам функции. TypeGraphQL автоматически валидирует типы на основе декораторов.
Настройка сервера и запуск
Соберём всё вместе в главном файле index.ts:
// src/index.ts
import "reflect-metadata";
import { ApolloServer } from "apollo-server";
import { buildSchema } from "type-graphql";
import { UserResolver } from "./resolvers/user.resolver";
async function startServer() {
const schema = await buildSchema({
resolvers: [UserResolver],
emitSchemaFile: true, // генерирует schema.graphql
});
const server = new ApolloServer({
schema,
playground: true, // включает GraphQL Playground для тестирования
});
const { url } = await server.listen(4000);
console.log(`🚀 Сервер запущен на ${url}`);
}
startServer().catch(console.error);
После запуска (npx ts-node src/index.ts) сервер будет доступен по адресу http://localhost:4000/graphql. Откройте GraphQL Playground и выполните тестовый запрос:
query {
getAllUsers {
id
name
email
age
}
}
Вы должны получить список всех пользователей. Попробуйте мутацию для создания нового пользователя:
mutation {
createUser(input: {
name: "Алексей Кузнецов"
email: "alex@example.com"
age: 25
}) {
id
name
email
}
}
Расширение функциональности
Теперь, когда базовая структура готова, можно добавить более сложные возможности:
- Пагинация — добавьте аргументы
skipиtakeв запросgetAllUsers - Фильтрация — реализуйте поиск пользователей по имени или email
- Валидация — используйте
class-validatorдля проверки email формата - Подписки — добавьте real-time обновления через WebSocket
Пример добавления пагинации:
@Query