GraphQL API с TypeScript: пошаговый туториал на практике

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение

GraphQL — это язык запросов для API, который позволяет клиентам получать только необходимые данные. В сочетании с TypeScript он становится мощным инструментом для создания типобезопасных, масштабируемых и документированных API. В этом пошаговом туториале мы на практике создадим полноценный GraphQL API на TypeScript с использованием Apollo Server и TypeGraphQL.

Вы узнаете:

  • Как настроить проект с TypeScript и Apollo Server
  • Как определить схему GraphQL с помощью декораторов TypeGraphQL
  • Как написать резолверы с полной типизацией
  • Как подключить базу данных и выполнять запросы

Этот материал будет полезен как новичкам, так и разработчикам, уже знакомым с REST API, но желающим освоить современный подход к построению API.

1. Настройка проекта и установка зависимостей

Начнем с инициализации проекта. Убедитесь, что у вас установлены Node.js (версия 16+) и npm/yarn.

mkdir graphql-ts-tutorial
cd graphql-ts-tutorial
npm init -y

Установите необходимые пакеты:

npm install apollo-server graphql reflect-metadata type-graphql class-validator
npm install -D typescript @types/node ts-node

Создайте файл tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "lib": ["ES2020"],
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "strict": true,
    "esModuleInterop": true,
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src/**/*"]
}

Обратите внимание на флаги experimentalDecorators и emitDecoratorMetadata — они необходимы для работы TypeGraphQL.

2. Определение схемы и типов с помощью TypeGraphQL

Создадим папку src и файл src/types/User.ts. Здесь мы опишем модель пользователя.

import { ObjectType, Field, ID, InputType } from "type-graphql";

@ObjectType()
export class User {
  @Field(() => ID)
  id!: number;

  @Field()
  name!: string;

  @Field()
  email!: string;

  @Field()
  createdAt!: Date;
}

Объяснение:

  • @ObjectType() — помечает класс как тип GraphQL.
  • @Field() — указывает, какие поля будут доступны в API.
  • @Field(() => ID) — для скалярного типа ID.

Теперь создадим InputType для мутаций (создание пользователя):

@InputType()
export class CreateUserInput {
  @Field()
  name!: string;

  @Field()
  email!: string;
}

Этот тип будет использоваться в резолверах для валидации входных данных.

3. Написание резолверов

Создадим файл src/resolvers/UserResolver.ts. Здесь мы реализуем логику запросов и мутаций.

import { Resolver, Query, Mutation, Arg } from "type-graphql";
import { User, CreateUserInput } from "../types/User";

// Имитация базы данных
let users: User[] = [
  { id: 1, name: "Иван Иванов", email: "ivan@example.com", createdAt: new Date() },
  { id: 2, name: "Мария Петрова", email: "maria@example.com", createdAt: new Date() }
];

let nextId = 3;

@Resolver()
export class UserResolver {
  @Query(() => [User])
  async users(): Promise<User[]> {
    return users;
  }

  @Query(() => User, { nullable: true })
  async user(@Arg("id") id: number): Promise<User | undefined> {
    return users.find(u => u.id === id);
  }

  @Mutation(() => User)
  async createUser(@Arg("data") data: CreateUserInput): Promise<User> {
    const newUser: User = {
      id: nextId++,
      name: data.name,
      email: data.email,
      createdAt: new Date()
    };
    users.push(newUser);
    return newUser;
  }
}

Ключевые моменты:

  • @Query — декоратор для запросов (GET).
  • @Mutation — для изменений данных (POST/PUT/DELETE).
  • @Arg — извлекает аргументы из запроса.
  • Тип возвращаемого значения строго задается в дженерике @Query(() => [User]).

4. Сборка сервера и запуск

Создадим главный файл src/index.ts:

import "reflect-metadata";
import { ApolloServer } from "apollo-server";
import { buildSchema } from "type-graphql";
import { UserResolver } from "./resolvers/UserResolver";

async function bootstrap() {
  const schema = await buildSchema({
    resolvers: [UserResolver],
    emitSchemaFile: true // генерирует schema.graphql
  });

  const server = new ApolloServer({ schema });

  const { url } = await server.listen(4000);
  console.log(`🚀 Сервер запущен на ${url}`);
}

bootstrap();

Добавьте скрипт в package.json:

"scripts": {
  "start": "ts-node src/index.ts",
  "build": "tsc"
}

Запустите сервер:

npm start

Теперь откройте http://localhost:4000 — вы увидите GraphQL Playground. Попробуйте выполнить запрос:

query {
  users {
    id
    name
    email
  }
}

И мутацию для создания пользователя:

mutation {
  createUser(data: { name: "Алексей", email: "alex@example.com" }) {
    id
    name
  }
}

5. Дополнительные возможности и лучшие практики

Чтобы сделать ваш API более промышленным, добавьте:

  • Валидацию — используйте class-validator с декораторами @IsEmail(), @Length() в InputType.
  • Авторизацию — через middleware или декоратор @Authorized

Блоги

Рекомендаций по книгам