graphql skill
GraphQL을 통해 API Platform 리소스를 노출하며, 쿼리, 뮤테이션, 커스텀 리졸버 및 Relay 커서 페이지네이션을 지원합니다.
- GitHub 스타
- 29
- 파일
- 1
- 마지막 커밋
- 2026년 10월 22일
- 라이선스
- —
- 허용된 도구
- —
graphql skill은 무엇을 하나요?
graphql은(는) agent skill입니다. GraphQL을 통해 API Platform 리소스를 노출하며, 쿼리, 뮤테이션, 커스텀 리졸버 및 Relay 커서 페이지네이션을 지원합니다.
skill의 SKILL.md에서 생성된 요약입니다.
graphql skill 정보
GraphQL 엔드포인트를 통해 API Platform 리소스를 노출하면 필드 선택 및 라운드 트립 감소와 같은 클라이언트의 특정 요구 사항을 충족할 수 있습니다. 이 SKILL은 단일 요청으로 복잡한 데이터 구조를 탐색해야 하는 Relay 또는 Apollo 프런트엔드를 구축할 때 사용하도록 설계되었습니다. 사용자가 GraphQL 작업을 구현하거나, 커스텀 리졸버를 관리하거나, 기존 리소스에 Relay 커서 페이지네이션을 구성해야 할 때 에이전트가 이 SKILL을 로드해야 합니다.
사용자는 전용 메타데이터 클래스를 사용하여 Query, QueryCollection, Mutation, DeleteMutation과 같은 특정 작업을 정의할 수 있습니다. 이 도구는 데이터 보강 또는 커스텀 페칭을 허용하는 QueryItemResolverInterface 및 MutationResolverInterface와 같은 리졸버 인터페이스를 통해 커스텀 로직을 지원합니다. Symfony에서 Relay 스타일의 커넥션 및 Mercure 기반 구독과 같은 고급 기능을 제공하지만, 특히 HTTP 캐싱과 예측 가능한 작업 비용이 우선순위인 경우 REST를 대체하기보다는 보완하도록 설계되었습니다.
agent가 수행할 수 있는 작업
- 1GraphQL 작업 구현리소스 클래스에 대해 뮤테이션 및 쿼리와 같은 특정 GraphQL 작업을 생성합니다.
- 2커스텀 데이터 로직 구성단순한 ID 페칭 이상의 복잡한 쿼리를 처리하기 위한 커스텀 리졸버를 개발합니다.
skill의 SKILL.md를 기반으로 작성되었습니다. 모든 사용 사례는 해당 문서의 인용구와 대조 확인되었습니다.
graphql skill 설치 방법
각 명령은 skill 폴더를 클라이언트의 skills 디렉터리에 복사합니다. 클라이언트를 재시작하거나 새 세션을 시작하여 로드하세요.플러그인에 graphql skill 설치
/plugin marketplace add api-platform/skillset /plugin install api-platform@api-platform-skillset
Claude Code에 graphql skill 설치
~/.claude/skills/graphql/SKILL.md
$ npx degit api-platform/skillset/skills/graphql ~/.claude/skills/graphqlClaude Code (project)에 graphql skill 설치
.claude/skills/graphql/SKILL.md
$ npx degit api-platform/skillset/skills/graphql .claude/skills/graphqlCodex에 graphql skill 설치
~/.agents/skills/graphql/SKILL.md
$ npx degit api-platform/skillset/skills/graphql ~/.agents/skills/graphqlGemini CLI에 graphql skill 설치
~/.gemini/skills/graphql/SKILL.md
$ npx degit api-platform/skillset/skills/graphql ~/.gemini/skills/graphqlClaude.ai에 graphql skill 설치
npx degit api-platform/skillset/skills/graphql graphql && zip -r graphql.zip graphql # claude.ai → Customize → Skills → + → Create skill → Upload a skill → graphql.zip
SKILL.md
GitHub에서 보기GraphQL
Default to REST. GraphQL trades away things API Platform gives you for free over REST: HTTP cache semantics (ETag, Cache-Control, invalidation), one URL per resource, simple CDN/proxy caching, and predictable per-operation cost. A single GraphQL query can fan out into arbitrarily deep/expensive resolution. Reach for GraphQL when it is a hard client requirement (e.g. a Relay/Apollo frontend, or clients that genuinely need to select fields and avoid round-trips) — not as a default. The same resource class can serve both; you don't have to choose globally.
Enabling GraphQL
Install api-platform/graphql (composer require api-platform/graphql), then it's
on. A /graphql endpoint and the GraphiQL playground (/graphql/graphiql) appear.
Disable globally or per resource as needed:
# config/packages/api_platform.yaml
api_platform:
graphql:
enabled: true
graphiql:
enabled: true
Declaring GraphQL operations
GraphQL operations live in graphQlOperations and are separate classes from the
REST ones, under ApiPlatform\Metadata\GraphQl\. A resource with no
graphQlOperations still gets a default set (item query, collection query, create /
update / delete mutations) once GraphQL is enabled.
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\GraphQl\DeleteMutation;
use ApiPlatform\Metadata\GraphQl\Mutation;
use ApiPlatform\Metadata\GraphQl\Query;
use ApiPlatform\Metadata\GraphQl\QueryCollection;
#[ApiResource(graphQlOperations: [
new Query(),
new QueryCollection(),
new Mutation(name: 'create'),
new Mutation(name: 'update'),
new DeleteMutation(name: 'delete'),
])]
class Book {}
Mutation and DeleteMutation require a name — it becomes the GraphQL field
name (createBook, updateBook, deleteBook). Query and QueryCollection only
need a name when you declare more than one of the same kind (e.g. a custom query
alongside the default).
Security on GraphQL operations
Same ExpressionLanguage as REST (see operations), set per GraphQl operation:
new Query(security: "is_granted('ROLE_USER')")
new Mutation(name: 'update', security: "object.getOwner() == user")
new Mutation(name: 'update', securityPostDenormalize: "object.getOwner() == user")
Because one GraphQL query can traverse relations, securing only the top-level operation is not enough — guard the related resources' operations too, or a nested field becomes an unguarded read path.
Custom resolvers
Use a resolver when a query/mutation needs logic beyond fetch-by-id. Resolvers are services implementing one of:
QueryItemResolverInterface—__invoke(?object $item, array $context): objectQueryCollectionResolverInterface—__invoke(iterable $collection, array $context): iterableMutationResolverInterface—__invoke(?object $item, array $context): ?object
Query arguments arrive in $context['args'].
use ApiPlatform\GraphQl\Resolver\QueryItemResolverInterface;
final class BookResolver implements QueryItemResolverInterface
{
public function __invoke(?object $item, array $context): object
{
// $item is the fetched Book (or null if read: false); enrich or replace it
return $item;
}
}
With Symfony autoconfiguration the resolver is wired automatically. Without it, tag
the service api_platform.graphql.query_resolver (or ..._mutation_resolver). Then
reference it by class name on the operation, and set read: false when the
resolver should fetch the data itself rather than receiving a hydrated item:
new Query(name: 'recommended', resolver: BookResolver::class, read: false)
new Query(
name: 'search',
resolver: BookResolver::class,
args: [
'query' => ['type' => 'String!', 'description' => 'Full-text search'],
'limit' => ['type' => 'Int'],
],
)
args overrides the auto-generated argument set — define it when the query takes
parameters that aren't resource fields.
Relations and the N+1 trap
GraphQL embeds related resources by selecting nested fields:
{
book(id: "/books/1") {
title
author { name }
}
}
Relations resolve through the same providers as REST. A deeply nested query can trigger many small queries (the classic N+1). API Platform mitigates common cases, but verify against real queries and add Doctrine joins / a custom collection provider where a hot path fans out. This open-ended cost is the main reason REST is the safer default for cache-sensitive APIs.
Pagination: Relay cursor connections
Collection queries return Relay-style cursor connections by default
(edges { node { ... } cursor }, pageInfo, totalCount), driven by first/
after/last/before arguments:
{
books(first: 10, after: "endCursor") {
totalCount
edges { node { title } cursor }
pageInfo { endCursor hasNextPage }
}
}
To use simple page-based pagination instead, set paginationType: 'page' on the
resource or the QueryCollection:
use ApiPlatform\Metadata\GraphQl\QueryCollection;
#[ApiResource(graphQlOperations: [
new QueryCollection(paginationType: 'page'),
])]
class Book {}
All the pagination* controls from pagination (items per page, max, partial)
apply to GraphQL collections too.
Real-time subscriptions
When a resource has mercure: true, GraphQL subscription operations push updates
through the Mercure hub — see mercure.
Laravel
GraphQL is supported on Laravel. The operation classes (Query, QueryCollection,
Mutation, DeleteMutation), security expressions, Relay connections,
paginationType, custom resolvers and the N+1 caveats are all the same. Differences:
- Install
composer require api-platform/graphql, then enable it inconfig/api-platform.phpundergraphql('enabled' => true) — not YAML. Depth/ complexity limits andgraphiqllive in the same config block. - Resolvers implement the same
QueryItemResolverInterface/QueryCollectionResolverInterface/MutationResolverInterfaceand are referenced by class-string on the operation; Laravel's container resolves them — there are noapi_platform.graphql.*_resolvertags to apply. - Real-time
subscriptionoperations depend on Mercure, which has no Laravel integration (see mercure), so GraphQL subscriptions are effectively Symfony-only.
Checklist
- GraphQL chosen for a real client requirement, not as a REST default
- Every
Mutation/DeleteMutationhas aname -
securityset on nested resources, not just the entry-point operation - Custom resolvers tagged (or autoconfigured) and referenced by class name
-
read: falseset when the resolver fetches its own data - Deep/nested queries checked for N+1; joins added on hot paths
-
paginationType: 'page'set only if the client doesn't want Relay connections
이 스킬의 파일
1graphql skill 질문
Claude Code에 graphql skill을 어떻게 설치하나요?
npx degit api-platform/skillset/skills/graphql ~/.claude/skills/graphql를 실행합니다. Claude Code는 ~/.claude/skills(모든 프로젝트) 또는 .claude/skills(한 프로젝트)에서 skills를 로드하며, 설명이 작업과 일치할 때 skill을 사용합니다.
graphql skill을 사용할 수 있는 클라이언트는 무엇인가요?
Agent Skills 형식을 읽는 모든 클라이언트(Claude Code, Codex, Gemini CLI, claude.ai(ZIP으로 업로드))가 사용할 수 있습니다. skill 내 스크립트는 클라이언트가 코드 실행을 허용하는 경우에만 실행됩니다.
API Platform에서 GraphQL을 어떻게 활성화하나요?
composer require api-platform/graphql 명령어로 패키지를 설치한 후, 설정 파일(Symfony의 경우 YAML, Laravel의 경우 PHP)에서 활성화합니다.
API Platform에서 GraphQL과 REST의 차이점은 무엇인가요?
REST는 내장된 HTTP 캐시 시맨틱, 예측 가능한 작업 비용, 간단한 CDN 캐싱을 제공하는 반면, GraphQL은 클라이언트가 특정 필드를 선택할 수 있게 해주지만 비용이 많이 드는 깊은 리졸루션 쿼리로 이어질 수 있습니다.
GraphQL 작업에 커스텀 로직을 사용할 수 있나요?
네, QueryItemResolverInterface, QueryCollectionResolverInterface 또는 MutationResolverInterface를 구현하는 서비스를 생성하여 커스텀 리졸버를 구현할 수 있습니다.