10 сентября 2025 г.
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 предлагает гибкий подход к получению данных и ускоряет разработку.