К основному содержанию
скилл CX Codex

go-graphql — скилл для Claude Code: что делает и как установить

Скилл помогает строить GraphQL-серверы на Go с помощью gqlgen. Он предотвращает проблему N+1, задаёт лимиты сложности запросов и организует тонкие резолверы.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add eduardo-sl/go-agent-skills --skill go-graphql -a claude-code
Открыть на GitHub

Что делает go-graphql

Скилл направляет агента при разработке API на Go через библиотеку gqlgen. Вся работа строится по подходу schema-first: схема .graphql остаётся главным источником истины, а доменные типы привязываются в gqlgen.yml. Инструкция требует держать резолверы тонкими. Они передают выполнение в сервисы и не содержат SQL или бизнес-логику.

Для борьбы с проблемой N+1 запросов скилл настраивает пакетную загрузку через dataloadgen. Загрузчики создаются строго на каждый HTTP-запрос внутри middleware. Общий кэш ведёт к утечкам данных между пользователями. Защита от перегрузок опирается на лимиты сложности (FixedComplexityLimit) и обязательную пагинацию списков.

Для работы требуется Go toolchain и модуль gqlgen. Агенту открыт доступ к вызовам go, gofmt и gqlgen. Скилл не рассчитан на REST или gRPC.

Какие задачи решает

  • Устранить проблему N+1 в резолверах списков с помощью dataloadgen
  • Настроить генерацию кода и привязку доменных структур через gqlgen.yml
  • Ограничить сложность и глубину входящих GraphQL-запросов
  • Изолировать код резолверов от прямого выполнения SQL-запросов
  • Скрыть внутренние ошибки сервера через SetErrorPresenter

Примеры запросов агенту

  • Настрой gqlgen по схеме и свяжи структуры в gqlgen.yml
  • Добавь dataloader через dataloadgen для поля Customer в orderResolver, чтобы убрать N+1
  • Настрой FixedComplexityLimit и обработчик ошибок SetErrorPresenter для GraphQL-сервера

Как установить go-graphql

1Через Skills CLI (Vercel)

npx skills add eduardo-sl/go-agent-skills --skill go-graphql -a claude-code

2Вручную: положить файлы

~/.claude/skills/go-graphql/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/go-graphql/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Вопросы о go-graphql

Как установить go-graphql в Claude Code?

Выполните команду npx skills add eduardo-sl/go-agent-skills --skill go-graphql -a claude-code. Файл навыка сохранится по пути ~/.claude/skills/go-graphql/SKILL.md.

Что делает скилл go-graphql?

Он инструктирует агента по созданию GraphQL-серверов на Go с библиотекой gqlgen. Скилл задаёт правила для тонких резолверов, пакетной загрузки через dataloader, ограничения сложности запросов и безопасной обработки ошибок.

Почему dataloader должен создаваться на каждый запрос?

Если объявить dataloader на весь процесс, кэш начнёт сохранять выборки между запросами разных пользователей. Это приводит к утечке данных между клиентами.

Исходный текст

SKILL.md · MIT
---
name: go-graphql
description: >
  Build GraphQL servers in Go with gqlgen: schema-first generation, resolver
  structure, the N+1 problem and dataloaders, complexity and depth limits,
  error presentation, field-level authorization, and testing resolvers. Use
  when implementing or reviewing a GraphQL API, when a query fans out into
  hundreds of database calls, or when deciding what a resolver may expose.
  Trigger examples: "GraphQL", "gqlgen", "resolver", "N+1 queries",
  "dataloader", "query complexity limit", "GraphQL schema".
  Not for: REST and OpenAPI (go-openapi), gRPC (go-grpc), general HTTP
  middleware and shutdown (go-api-design).
user-invocable: true
license: MIT
compatibility: Designed for Claude Code or similar AI coding agents working on Go projects. Requires the Go toolchain. gqlgen is installed as a module tool.
allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(gofmt:*) Bash(gqlgen:*)
metadata:
  author: eduardo-sl
  version: "1.0.3"
---

# Go GraphQL

GraphQL moves query planning to the client. That is the feature and the
danger: one innocuous query can become ten thousand database round trips, and
one over-permissive field can leak another tenant's data. Both are solved at
the server, not in the schema review.

Detailed reference material, loaded on demand:

- `references/errors-auth-testing.md` — error presenter, field
  authorization directive, client-driven tests with query-count asserts.

Read a reference file only when the summary below is not enough.

## 1. Schema-First with gqlgen

The `.graphql` schema is the source of truth. gqlgen generates models,
resolver stubs, and the execution layer from it.

```bash
go get -tool github.com/99designs/gqlgen
go tool gqlgen init      # once
go tool gqlgen generate  # after every schema change
```

```yaml
# gqlgen.yml — bind generated types to your own models
models:
  User:
    model: github.com/myorg/app/internal/domain.User
  ID:
    model:
      - github.com/99designs/gqlgen/graphql.ID
      - github.com/99designs/gqlgen/graphql.Int64
```

Bind domain types explicitly. Left to itself gqlgen generates a parallel set
of anaemic structs, and every resolver becomes a mapping function.

Commit generated code, and fail CI when it is stale:

```bash
go tool gqlgen generate && git diff --exit-code
```

Never edit `generated.go` or `models_gen.go`. `resolver.go` and the
`*.resolvers.go` files are yours.

## 2. Resolvers Stay Thin

A resolver translates a GraphQL request into a service call. It contains no
business logic and no SQL.

```go
func (r *queryResolver) User(ctx context.Context, id string) (*domain.User, error) {
    u, err := r.users.Find(ctx, id)
    if errors.Is(err, domain.ErrNotFound) {
        return nil, nil // nullable field: absent, not an error
    }
    if err != nil {
        return nil, fmt.Errorf("find user %s: %w", id, err)
    }
    return u, nil
}
```

Inject dependencies through the `Resolver` struct, never through package
globals:

```go
type Resolver struct {
    users  UserService
    orders OrderService
    loader *Loaders
}
```

Always propagate `ctx`. It carries the request deadline, the authenticated
principal, and the per-request dataloaders.

## 3. The N+1 Problem — the one that matters

A field resolver on a list type runs once per element.

```go
// ❌ 1 query for the orders, then N queries for the users
func (r *orderResolver) Customer(ctx context.Context, obj *domain.Order) (*domain.User, error) {
    return r.users.Find(ctx, obj.CustomerID)
}
```

Batch with a dataloader. It collects the keys requested within a short window
and issues one query.

```go
import "github.com/vikstrous/dataloadgen"

type Loaders struct {
    UserByID *dataloadgen.Loader[string, *domain.User]
}

func NewLoaders(s UserService) *Loaders {
    return &Loaders{
        UserByID: dataloadgen.NewLoader(func(ctx context.Context, ids []string) ([]*domain.User, []error) {
            return s.FindMany(ctx, ids) // ONE query for all ids
        }, dataloadgen.WithWait(time.Millisecond)),
    }
}

// ✅ 1 query for the orders, 1 for all customers
func (r *orderResolver) Customer(ctx context.Context, obj *domain.Order) (*domain.User, error) {
    return loadersFrom(ctx).UserByID.Load(ctx, obj.CustomerID)
}
```

Loaders are **per request**, installed by middleware. A process-wide loader
caches across users and leaks data between them.

```go
func withLoaders(svc UserService, next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        ctx := context.WithValue(r.Context(), loadersKey{}, NewLoaders(svc))
        next.ServeHTTP(w, r.WithContext(ctx))
    })
}
```

The batch function must return results **in the order of the keys it was
given**, with a nil entry and an error per missing key. Returning a shorter
slice silently misaligns every result.

## 4. Bound Every Query

A public GraphQL endpoint without limits is a denial-of-service endpoint.

```go
srv := handler.New(generated.NewExecutableSchema(cfg))
srv.AddTransport(transport.POST{})
srv.SetQueryCache(lru.New[*ast.QueryDocument](1000))
srv.Use(extension.FixedComplexityLimit(300))
srv.Use(extension.AutomaticPersistedQuery{Cache: lru.New[string](100)})
```

- **Complexity limit** — assign a cost per field, higher for list fields with
  a large `first`. Start at a number your slowest legitimate query fits under,
  then measure.
- **Depth** — recursive types (`user { orders { customer { orders ... } } }`)
  must be bounded. gqlgen has no built-in depth limit; enforce it in an
  operation middleware.
- **Pagination is mandatory** on every list field. A field returning an
  unbounded list is a schema bug.
- **Introspection** is only enabled if you install `extension.Introspection`.
  Do not install it in production, or gate it behind an authenticated role.
- **Persisted queries** let a public client send a hash instead of a document,
  so the server executes only queries you shipped.

Set `srv.AroundOperations` to enforce a per-operation timeout, and always run
behind an `http.Server` with `ReadTimeout` and `WriteTimeout` set.

## 5. Errors

GraphQL returns 200 with an `errors` array. Never leak internals into it.

Install `srv.SetErrorPresenter`: map known domain errors (validation,
not found) to their message plus a stable `extensions.code`, and log
everything else server-side while returning `internal server error` with
code `INTERNAL`. Example: `references/errors-auth-testing.md`.

Use `srv.SetRecoverFunc` to convert a resolver panic into an error instead of
killing the connection, and log it with the stack.

Remember the nullability rule: an error on a non-null field nulls out its
nearest nullable ancestor. Make a field non-null only when it can never
legitimately be absent.

## 6. Authorization Belongs on the Field

Object-level checks are not enough — a client can reach an object through
several paths.

Declare a `@hasRole` (or similar) directive on sensitive fields and
implement it as a check against the principal in the context; return
`access denied` without detail. Example: `references/errors-auth-testing.md`.

Authenticate in HTTP middleware, before the GraphQL handler. Authorize in the
directive or the resolver, using the principal from the context — never from
a query argument.

## 7. Testing

Drive the real schema through gqlgen's test `client` and assert on the
decoded response. For every resolver behind a dataloader, also assert the
query count — that is the only way an N+1 regression fails a build rather
than a dashboard. Examples: `references/errors-auth-testing.md`.

## Verification Checklist

1. Schema is the source of truth; generated files are committed and CI-checked
2. Generated types bind to domain models via `gqlgen.yml`
3. Resolvers contain no business logic and always propagate `ctx`
4. Every list-field resolver that fetches by ID goes through a dataloader
5. Dataloaders are constructed per request, never shared across requests
6. Batch functions return one result per key, in key order
7. A complexity limit and a depth bound are configured and tested
8. Every list field is paginated
9. Introspection is disabled or role-gated in production
10. An error presenter strips internal errors; a recover func is installed
11. Authorization is enforced per field, from the context principal
12. A test asserts the query count for at least one batched field

© eduardo-sl · MIT · eduardo-sl/go-agent-skills

Похожие скиллы

Все скиллы по теме «Бэкенд и API» →
mcp-builder официальный anthropics Скилл проводит через создание MCP-сервера на TypeScript или Python: от изучения протокола до тестов и оценки качества. 130 949установок claude-api официальный anthropics Справочник по Anthropic SDK и API Claude для генерации кода без устаревших параметров и выдуманных методов. 74 198установок lark-im larksuite Скилл подключает Lark IM к агенту: он отправляет сообщения, ищет историю, управляет чатами и файлами. Подойдёт для задач вокруг командных коммуникаций. CX Codex +1 472 900установок lark-event larksuite Слушает события Lark/Feishu и отдаёт их потоком NDJSON. Подходит для ботов, обработчиков сообщений и долгих подписчиков. CX Codex +1 466 800установок caveman-discover JuliusBrussee Находит точки вызова LLM в репозитории и размечает их воркфлоу для Caveman Cloud, чтобы расходы на токены не сливались в одну общую кучу. CX Codex +1 104 400установок migration JuliusBrussee Скилл задаёт правила безопасных миграций схем, данных и API с обязательным откатом. Пригодится при изменениях, где нельзя терять данные или ломать совместимость. CX Codex +1 103 900установок

Из того же набора34

go-project-layout Подсказывает, как разложить новый Go-проект по папкам: cmd/, internal/, плоская раскладка для мелких утилит. Пригодится в самом начале, когда структура ещё не сложилась. CX Codex +1 ★ 83звёзд репо go-openapi Настраивает подход spec-first для REST API на Go: генерирует интерфейсы через oapi-codegen, подключает middleware валидации и отслеживает ломающие изменения схемы. CX Codex +1 ★ 83звёзд репо go-interface-design Скилл помогает проектировать интерфейсы Go, разделять зависимости и проверять контракты на этапе компиляции. Пригодится при рефакторинге и подготовке к тестированию. CX Codex +1 ★ 83звёзд репо go-grpc Скилл для ИИ-агента, который ведёт разработку gRPC-сервисов на Go: proto-контракты, коды ошибок, дедлайны, интерцепторы и стриминг. CX Codex +1 ★ 83звёзд репо go-design-patterns Скилл помогает выбрать идиоматичный паттерн Go для создания объектов, смены поведения и обработки сбоев. Пригодится, когда нужно решить, как структурировать код. CX Codex +1 ★ 83звёзд репо go-dependency-injection Скилл учит агента внедрять зависимости в Go через конструкторы и собирать всё в main. Пригодится, когда в проекте завёлся глобальный синглтон или код тяжело тестировать. CX Codex +1 ★ 83звёзд репо go-cli Направляет агента при разработке консольных утилит на Go: от парсинга флагов и кодов возврата до интеграции с Cobra. CX Codex +1 ★ 83звёзд репо go-architecture-review Скилл проверяет структуру пакетов, направление зависимостей и границы модулей в Go-проекте. Пригодится для ревью архитектуры или плана рефакторинга. CX Codex +1 ★ 83звёзд репо

Спонсоры проекта

Компании, которые помогают держать аналитику открытой