13. Variables и Arguments

Variables и Arguments — способы передавать динамические данные в GraphQL запросы.
Arguments — аргументы полей
Заголовок раздела «Arguments — аргументы полей»Каждое поле в схеме может принимать аргументы:
type Query { user(id: ID!): User posts( limit: Int = 20 offset: Int = 0 status: PostStatus orderBy: String order: SortOrder = DESC ): PostConnection! search(query: String!, types: [SearchType!]): [SearchResult!]!}
type User { posts(limit: Int = 10, published: Boolean = true): [Post!]! avatar(size: Int = 200): String! # Аргумент на обычном поле}Variables — переменные операции
Заголовок раздела «Variables — переменные операции»Variables позволяют параметризировать запросы:
# Объявляем переменные в сигнатуре операцииquery GetUser($id: ID!) { user(id: $id) { name }}
# Аргументы с дефолтными значениямиquery GetPosts($limit: Int = 10, $offset: Int = 0, $status: PostStatus) { posts(limit: $limit, offset: $offset, status: $status) { items { id title } total }}Передача переменных (отдельный JSON объект):
{ "id": "user-123"}Почему не интерполяция?
# ❌ Никогда так не делай (XSS, инъекции)query { user(id: "${userId}") { name }}
# ✅ Правильно — переменныеquery GetUser($id: ID!) { user(id: $id) { name }}Типы переменных
Заголовок раздела «Типы переменных»query Examples( $id: ID! # Скаляр, обязательный $name: String # Скаляр, необязательный (null) $count: Int = 10 # Скаляр с дефолтом $ids: [ID!]! # Список обязательных ID $input: UserInput! # Input объект $role: UserRole # Enum) { ...}Variables в Apollo Client
Заголовок раздела «Variables в Apollo Client»// useQuery с переменнымиconst { data, loading } = useQuery(GET_POSTS, { variables: { limit: 10, offset: 0, status: 'PUBLISHED', },});
// useMutation с переменнымиconst [createPost] = useMutation(CREATE_POST);
const handleSubmit = () => { createPost({ variables: { input: { title: 'My Post', body: 'Content...', }, }, });};Динамические переменные
Заголовок раздела «Динамические переменные»function PostFilter() { const [filters, setFilters] = useState({ status: 'PUBLISHED', orderBy: 'createdAt', order: 'DESC', });
const { data, loading } = useQuery(GET_POSTS, { variables: filters, // При изменении variables Apollo автоматически делает новый запрос });
return ( <div> <select value={filters.status} onChange={e => setFilters({ ...filters, status: e.target.value })} > <option value="PUBLISHED">Опубликованные</option> <option value="DRAFT">Черновики</option> </select>
<select value={filters.order} onChange={e => setFilters({ ...filters, order: e.target.value })} > <option value="DESC">Сначала новые</option> <option value="ASC">Сначала старые</option> </select>
{loading ? <Spinner /> : data?.posts.items.map(/* ... */)} </div> );}Input объекты как переменные
Заголовок раздела «Input объекты как переменные»input CreateUserInput { name: String! email: String! password: String! role: UserRole = READER}
mutation CreateUser($input: CreateUserInput!) { createUser(input: $input) { id name email }}// Передача input объектаawait createUser({ variables: { input: { name: 'Иван Иванов', password: 'securePass123', role: 'EDITOR', }, },});Вложенные аргументы
Заголовок раздела «Вложенные аргументы»query ComplexQuery( $userId: ID! $postLimit: Int = 5 $postStatus: PostStatus $commentLimit: Int = 3) { user(id: $userId) { name posts(limit: $postLimit, status: $postStatus) { title comments(limit: $commentLimit) { body author { name } } } }}Аргументы в resolvers
Заголовок раздела «Аргументы в resolvers»const resolvers = { Query: { posts: async (_, args, { db }) => { const { limit = 20, offset = 0, status, orderBy = 'createdAt', order = 'DESC', filters = {}, } = args;
const where = {}; if (status) where.status = status; if (filters.authorId) where.authorId = filters.authorId; if (filters.tag) where.tags = { contains: filters.tag };
const [items, total] = await Promise.all([ db.posts.findMany({ where, take: limit, skip: offset, orderBy: { [orderBy]: order.toLowerCase() }, }), db.posts.count({ where }), ]);
return { items, total, hasMore: offset + limit < total }; }, },
User: { // Аргумент на поле объекта avatar: (parent, { size = 200 }) => { return `https://cdn.example.com/avatars/${parent.id}?size=${size}`; },
posts: (parent, { limit = 10, published = true }, { db }) => { return db.posts.findMany({ where: { authorId: parent.id, ...(published ? { status: 'PUBLISHED' } : {}), }, take: limit, }); }, },};Проверка переменных
Заголовок раздела «Проверка переменных»GraphQL валидирует переменные автоматически:
query BadQuery($id: ID!) { user(id: $id) { name }}Если передать переменные:
{ "id": null } # ❌ Ошибка: ID! не может быть null{ } # ❌ Ошибка: ID! обязателен{ "id": "123" } # ✅ OKПрактика
Заголовок раздела «Практика»- Напиши запрос с 5 разными переменными разных типов
- Создай аргумент
avatar(width: Int, height: Int)на типе User - Реализуй фильтрацию продуктов с переменными (цена, категория, в наличии)
- Создай форму с фильтрами, где изменение любого поля запускает новый запрос
- Напиши resolver, который принимает сложный input объект и фильтрует БД
- Arguments — параметры полей в схеме
- Variables — параметры операции (передаются отдельно от запроса)
- Всегда используй переменные для динамических данных
- GraphQL автоматически валидирует типы переменных
- Input объекты — для сложных аргументов
Следующий урок → Directives →