В прошлом уроке данные лежали в массивах и пропадали при перезапуске сервера. Теперь подключим настоящую базу — PostgreSQL через Prisma — и заодно разберёмся, как GraphQL вызывает резолверы. Представьте конвейер: на каждой станции рабочий получает деталь от предыдущей. Первый собирает список постов, следующие дорабатывают каждый пост — добавляют автора, комментарии. То, что передала предыдущая станция, и есть parent.
Сигнатура резолвера
Любой резолвер — функция (parent, args, contextValue, info):
| Параметр | Что это |
|---|---|
parent | то, что вернул резолвер родительского поля (в Post.author — объект поста) |
args | аргументы поля из запроса ({ id: '1' } для user(id: "1")) |
contextValue | общий объект запроса из функции context (например, { prisma }) |
info | служебные данные: имя поля, путь, схема; нужен редко |
Резолвер возвращает значение, null или Promise. Если вернулся объект или массив объектов, Apollo запускает резолверы их вложенных полей — и так до самых простых значений.
Дерево резолверов
Запрос выполняется как дерево. Разберём { posts { title author { name } } }:
Query.postsвызывается один раз и возвращает список постов.- Для каждого поста вызываются
Post.titleиPost.author: для 10 постовPost.authorсработает 10 раз — запомните это для урока про N+1. - Для каждого автора вызывается
User.name; егоparent— пользователь, которого вернулPost.author. - Дочерний резолвер ждёт родителя, а поля одного уровня Apollo запускает независимо друг от друга.
Резолверы по умолчанию
Резолвер для каждого поля не нужен. Если его нет, GraphQL берёт у parent свойство с именем поля, а если это функция — вызывает её. Поэтому Post.title, Post.body и User.name работают сами: такие свойства уже есть в строке из базы. Число Post.id превратит в строку "1" сам скаляр ID. Свой резолвер нужен в трёх случаях:
- корневые поля (
Query.*): у них нет родителя, данные берём из базы; - связи (
Post.author,User.posts,Post.comments): в строке толькоauthorIdили вовсе ничего; - поля с другим форматом (
Post.createdAt): в базеDate, а в схемеString.
Prisma в context
Prisma ORM 7 вы настраивали в разделе про базы данных. Создайте новую базу blog_graphql в том же контейнере PostgreSQL и инициализируйте Prisma:
npm install @prisma/client@7 @prisma/adapter-pg@7 pg
npm install -D prisma@7 dotenv
npx prisma init --datasource-provider postgresql --output ../src/generated/prisma --no-skillsОпишите в prisma/schema.prisma модели — те же сущности, что и в схеме GraphQL (атрибуты @map для краткости опущены), — а затем выполните npx prisma migrate dev --name init и npx prisma generate:
model User {
id Int @id @default(autoincrement())
name String
email String @unique
posts Post[]
comments Comment[]
}