Тест на вакансию

Использование GraphQL с примером на Node.js

10 сентября 2025 г.
170

GraphQL кардинально меняет подход к работе с API, позволяя клиентам запрашивать именно те данные, которые им нужны. Разберем основные понятия и практическую реализацию на Node.js.

Схема (Schema)

Например, эта схема определяет три основных типа данных (User, Post) и операции, которые можно выполнять (Query для чтения, Mutation для изменения данных):
type User {
  id: ID!
  name: String!
  email: String!
  posts: [Post!]!
}

type Post {
  id: ID!
  title: String!
  content: String!
  author: User!
}

type Query {
  users: [User!]!
  user(id: ID!): User
  posts: [Post!]!
  post(id: ID!): Post
}

type Mutation {
  createUser(name: String!, email: String!): User!
  createPost(title: String!, content: String!, authorId: ID!): Post!
}
Ключевые моменты:
  • ! означает, что поле не может быть null (обязательное)
  • [Post!]! означает: массив не может быть null, и элементы массива тоже не могут быть null

Запросы (Queries)

Простой запрос:
# Запрос
{
  users {
    id
    name
    email
  }
}
# Ответ
{
  "data": {
    "users": [
      {
        "id": "1",
        "name": "Иван Иванов",
        "email": "ivan@mail.ru"
      }
    ]
  }
}
Запрос с параметрами:
# Запрос
{
  user(id: "1") {
    name
    email
    posts {
      title
      content
    }
  }
}
# Ответ
{
  "data": {
    "user": {
      "name": "Иван Иванов",
      "email": "ivan@mail.ru",
      "posts": [
        {
          "title": "Мой первый пост",
          "content": "Содержание поста..."
        }
      ]
    }
  }
}

Мутации (Mutations)

Создание пользователя:
# Запрос
mutation {
  createUser(
    name: "Петр Петров"
    email: "petr@mail.ru"
  ) {
    id
    name
    email
  }
}
# Ответ
{
  "data": {
    "createUser": {
      "id": "2",
      "name": "Петр Петров",
      "email": "petr@mail.ru"
    }
  }
}
Создание поста:
mutation {
  createPost(
    title: "Новый пост"
    content: "Содержание нового поста"
    authorId: "1"
  ) {
    id
    title
    author {
      name
    }
  }
}

Переменные в запросах

# Запрос с переменными
query GetUser($userId: ID!) {
  user(id: $userId) {
    name
    email
  }
}

# Переменные (отдельно)
{
  "userId": "1"
}

Фрагменты (Fragments)

fragment UserDetails on User {
  id
  name
  email
  createdAt
}
{
  user(id: "1") {
    ...UserDetails
    posts {
      title
    }
  }
 
  users {
    ...UserDetails
  }
}

Сервер на Node.js

Установим зависимости:
npm install -D nodemon
npm install graphql apollo-server express
Создадим и отредактируем файл server.js:
const { ApolloServer, gql } = require('apollo-server');
const { v4: uuidv4 } = require('uuid');

// Данные в памяти
let users = [
  { id: '1', name: 'Иван Иванов', email: 'ivan@mail.ru' },
  { id: '2', name: 'Петр Петров', email: 'petr@mail.ru' }
];

let posts = [
  { id: '1', title: 'Первый пост', content: 'Содержание', authorId: '1' },
  { id: '2', title: 'Второй пост', content: 'Еще содержание', authorId: '1' }
];

// Схема GraphQL
const typeDefs = gql`
  type User {
    id: ID!
    name: String!
    email: String!
    posts: [Post!]!
  }
  type Post {
    id: ID!
    title: String!
    content: String!
    author: User!
  }
  type Query {
    users: [User!]!
    user(id: ID!): User
    posts: [Post!]!
    post(id: ID!): Post
  }
  type Mutation {
    createUser(name: String!, email: String!): User!
    createPost(title: String!, content: String!, authorId: ID!): Post!
    deleteUser(id: ID!): Boolean
  }
`;

// Резолверы (функции для обработки запросов)
const resolvers = {
  Query: {
    users: () => users,
    user: (parent, args) => users.find(user => user.id === args.id),
    posts: () => posts,
    post: (parent, args) => posts.find(post => post.id === args.id)
  },

  Mutation: {
    createUser: (parent, args) => {
      const user = {
        id: uuidv4(),
        name: args.name,
        email: args.email
      };
      users.push(user);
      return user;
    },
   
    createPost: (parent, args) => {
      const post = {
        id: uuidv4(),
        title: args.title,
        content: args.content,
        authorId: args.authorId
      };
      posts.push(post);
      return post;
    },
   
    deleteUser: (parent, args) => {
      const index = users.findIndex(user => user.id === args.id);
      if (index === -1) return false;
     
      users.splice(index, 1);
      // Удаляем посты пользователя
      posts = posts.filter(post => post.authorId !== args.id);
      return true;
    }
  },

  // Связи между типами
  User: {
    posts: (parent) => posts.filter(post => post.authorId === parent.id)
  },
  Post: {
    author: (parent) => users.find(user => user.id === parent.authorId)
  }
};

// Запуск сервера
const server = new ApolloServer({ typeDefs, resolvers });
server.listen().then(({ url }) => {
  console.log(`Server ready at ${url}`);
});
Для запуска сервера внесём в package.json:
"scripts": {
    "start": "node server.js",
    "dev": "nodemon server.js"
  }

Примеры запросов к серверу

Получить всех пользователей с их постами:
curl -X POST \
  http://localhost:4000/ \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query { users { id name email posts { id title } } }"
  }'
Найти конкретного пользователя по ID:
curl -X POST \
  http://localhost:4000/ \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query { user(id: \"1\") { id name email posts { title } } }"
  }'
Получить все посты с информацией об авторах:
curl -X POST \
  http://localhost:4000/ \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query { posts { id title content author { id name email } } }"
  }'
Найти конкретный пост по ID:
curl -X POST \
  http://localhost:4000/ \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query { post(id: \"1\") { id title content author { name email } } }"
  }'
Создать нового пользователя (Mutation):
curl -X POST \
  http://localhost:4000/ \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation { createUser(name: \"Евгений\", email: \"eugene@test.ru\") { id name email } }"
  }'
Создать новый пост (Mutation):
curl -X POST \
  http://localhost:4000/ \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation { createPost(title: \"Мой первый пост\", content: \"Содержание поста...\", authorId: \"1\") { id title author { name } } }"
  }'
Комбинированный запрос - получить пользователей и посты вместе:
curl -X POST \
  http://localhost:4000/ \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query { users { name email } posts { title author { name } } }"
  }'
Запрос с переменными:
curl -X POST \
  http://localhost:4000/ \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query GetUser($userId: ID!) { user(id: $userId) { id name posts { title } } }",
    "variables": { "userId": "1" }
  }'
Создание поста с переменными:
curl -X POST \
  http://localhost:4000/ \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation CreatePost($title: String!, $content: String!, $authorId: ID!) { createPost(title: $title, content: $content, authorId: $authorId) { id title author { name } } }",
    "variables": {
      "title": "Post with variables",
      "content": "Content from variables",
      "authorId": "1"
    }
  }'
В итоге, GraphQL в Node.js предлагает гибкий подход к получению данных и ускоряет разработку.
Поделиться: