К основному содержанию
правило

graphql — правило для Cursor: схема и установка

Правило задаёт соглашения для GraphQL-схем и операций: от именования полей до пагинации, валидации и защиты запросов. Пригодится, если хотите привести API к единым требованиям.

Установить в Cursor · Вручную: положить файлы Все способы и платформы ↓
.cursor/rules/graphql.mdc
Открыть на GitHub

Что делает graphql

Правило применяется к файлам *.graphql и *.gql. Оно рекомендует именовать типы в PascalCase, поля и аргументы в camelCase, а значения enum — в SCREAMING_SNAKE_CASE. Для мутаций предлагаются названия с глаголом, а для входных и выходных типов — суффиксы Input и Payload или Response.

Для списков, которые могут расти, правило предлагает курсорную пагинацию Relay с типами Connection, Edge и PageInfo вместо offset и limit. Также оно описывает глобальные ID через интерфейс Node, явную nullability и серверную проверку бизнес-правил. Это правило для схем и операций, а не настройка серверных резолверов.

В рекомендациях по серверу отдельно упомянуты DataLoader для группировки загрузок, ограничения глубины и сложности запросов и лимитирование частоты обращений. Если проект использует offset-пагинацию, её придётся менять в схеме и запросах, чтобы следовать совету о курсорах.

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

  • переименовать поля запросов без префиксов get и list
  • заменить пагинацию через offset и limit на курсорную
  • оформить входные и выходные типы мутаций по соглашению
  • разделить обязательные и допускающие null поля
  • снизить риск N+1 при загрузке связанных данных

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

  • Проверь схему в schema.graphql по правилам именования GraphQL.
  • Переделай список пользователей с offset и limit на курсорную пагинацию с UserConnection.
  • Посмотри, где в резолверах загрузка связанных данных может создавать проблему N+1.

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

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

.cursor/rules/graphql.mdc

Во frontmatter: description, globs, alwaysApply

По шагам, с командами для каждой платформы: Cursor rules: файлы .mdc, четыре режима и замена .cursorrules

Вопросы о graphql

Как установить graphql в Cursor?

Добавьте файл правила по пути .cursor/rules/graphql.mdc. Затем поместите в него текст правила.

Что делает правило graphql?

Оно задаёт соглашения для GraphQL-схем и операций: именование, типы мутаций, пагинацию и обработку null. Также содержит рекомендации по серверной валидации и защите запросов.

Какую пагинацию рекомендует graphql?

Для списков, которые могут увеличиваться, правило рекомендует курсорную пагинацию Relay с Connection, Edge и PageInfo. Пагинацию через offset и limit оно предлагает заменить.

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

graphql.mdc · CC0-1.0
---
description: Enforce modern, performant, and secure GraphQL schema design and operation best practices for maintainable and scalable APIs.
globs: **/*.{graphql,gql}
---
# GraphQL Best Practices

This guide outlines the definitive best practices for designing, implementing, and operating GraphQL APIs. Adhere to these rules to ensure your schemas are consistent, performant, secure, and developer-friendly.

## 1. Schema Design & Naming Conventions

Consistency is paramount. Follow standard GraphQL naming conventions strictly.

### 1.1 Casing Rules

*   **Types (Object, Input, Enum, Interface, Union, Scalar)**: `PascalCase`
*   **Fields, Arguments, Directives**: `camelCase`
*   **Enum Values**: `SCREAMING_SNAKE_CASE`

❌ **BAD**
```graphql
type user { # Type name not PascalCase
  firstName: String!
  getProducts(productId: ID): [product] # Field name has verb, arg not camelCase
}

enum UserRole { # Enum value not SCREAMING_SNAKE_CASE
  admin
  guest
}
```

✅ **GOOD**
```graphql
type User {
  id: ID!
  firstName: String!
  products(limit: Int): [Product!]! # No verb, arg is camelCase
  role: UserRole!
}

enum UserRole {
  ADMIN
  GUEST
}
```

### 1.2 Query Field Naming

Avoid verb prefixes (`get`, `list`, `fetch`) on query (read) fields. This maintains consistency with nested fields.

❌ **BAD**
```graphql
type Query {
  getUsers: [User!]!
  listProducts: [Product!]!
}

query MyQuery {
  getUsers {
    id
    getProducts { # Inconsistent with root field
      name
    }
  }
}
```

✅ **GOOD**
```graphql
type Query {
  users: [User!]!
  products: [Product!]!
}

query MyQuery {
  users {
    id
    products { # Consistent with root field
      name
    }
  }
}
```

### 1.3 Mutation Field Naming

Start mutation fields with an imperative verb (e.g., `create`, `update`, `delete`).

❌ **BAD**
```graphql
type Mutation {
  userCreate(input: CreateUserInput!): CreateUserPayload!
}
```

✅ **GOOD**
```graphql
type Mutation {
  createUser(input: CreateUserInput!): CreateUserPayload!
  updateUser(input: UpdateUserInput!): UpdateUserPayload!
  deleteUser(input: DeleteUserInput!): DeleteUserPayload!
}
```

### 1.4 Input & Payload Types

*   **Input Types**: Suffix with `Input`.
*   **Mutation Payload Types**: Suffix with `Payload` or `Response`. These should typically include the created/updated object and a `success` boolean or `errors` array.

❌ **BAD**
```graphql
input UserData { # Generic name
  name: String!
}

type Mutation {
  createUser(data: UserData!): User! # Returns raw object, no success/errors
}
```

✅ **GOOD**
```graphql
input CreateUserInput {
  name: String!
  email: String!
}

type CreateUserPayload {
  success: Boolean!
  user: User
  errors: [Error!] # Custom error type for detailed feedback
}

type Mutation {
  createUser(input: CreateUserInput!): CreateUserPayload!
}
```

## 2. Global Object Identification & Pagination

Implement Relay-style global object identification and cursor-based pagination for robust caching and efficient data fetching.

### 2.1 Global Object ID

Every object that can be refetched or cached independently MUST implement the `Node` interface and expose a globally unique `id: ID!`.

```graphql
interface Node {
  id: ID!
}

type User implements Node {
  id: ID! # Global ID
  username: String!
  email: String!
}

type Query {
  node(id: ID!): Node
  user(id: ID!): User # Specific fetch for convenience
}
```

### 2.2 Cursor-Based Pagination

Always use cursor-based pagination (Relay Connection Specification) for lists that can grow large. Avoid offset-based pagination.

❌ **BAD**
```graphql
type Query {
  users(offset: Int = 0, limit: Int = 10): [User!]! # Offset-based pagination
}
```

✅ **GOOD**
```graphql
type Query {
  users(first: Int, after: String, last: Int, before: String): UserConnection!
}

type UserConnection {
  edges: [UserEdge!]!
  pageInfo: PageInfo!
}

type UserEdge {
  node: User!
  cursor: String!
}

type PageInfo {
  hasNextPage: Boolean!
  hasPreviousPage: Boolean!
  startCursor: String
  endCursor: String
}
```

## 3. Nullability & Input Validation

Be explicit about nullability and always validate inputs server-side.

### 3.1 Explicit Nullability

Use `!` for non-nullable fields when the data is always expected. Default to nullable if the field might legitimately be null.

❌ **BAD**
```graphql
type User {
  name: String # Is name always present?
  email: String!
}
```

✅ **GOOD**
```graphql
type User {
  id: ID!
  name: String! # Name is always required
  email: String # Email might be null if user hasn't provided it
}
```

### 3.2 Server-Side Input Validation

GraphQL's type system provides basic validation, but complex business logic validation MUST occur in resolvers. Return specific errors in the `errors` array.

```graphql
input CreateUserInput {
  name: String! # GraphQL ensures it's a string and non-null
  email: String!
}

type CreateUserPayload {
  success: Boolean!
  user: User
  errors: [Error!] # Custom error type for detailed feedback
}

type Error {
  message: String!
  code: String! # e.g., "INVALID_EMAIL", "NAME_TOO_SHORT"
  path: [String!] # Field path where error occurred
}
```

## 4. Performance Considerations

Prevent N+1 query problems and optimize data fetching.

### 4.1 DataLoader for N+1 Problems

Always use `DataLoader` (or equivalent batching/caching mechanism) within your resolvers to prevent N+1 query issues when fetching related data. This is a server-side implementation detail but critical for GraphQL API performance.

❌ **BAD** (Conceptual - direct resolver calls)
```javascript
// In a resolver for User.products
user.productIds.map(productId => db.products.findById(productId)); // N+1 query
```

✅ **GOOD** (Conceptual - using DataLoader)
```javascript
// In a resolver for User.products
dataLoaders.productLoader.loadMany(user.productIds); // Batches and caches
```

## 5. Security

Implement robust security measures to protect your API from common attack vectors.

### 5.1 Query Depth and Complexity Limiting

Configure your GraphQL server to limit the maximum depth and complexity of incoming queries. This prevents malicious or accidental denial-of-service (DoS) attacks.

```graphql
# This is a server-side configuration, not schema.
# Example: Max depth 10, max complexity 1000.
# If exceeded, the server rejects the query before execution.
```

### 5.2 Rate Limiting

Implement rate limiting at the HTTP layer to prevent abuse and DoS attacks. This should be applied to all API endpoints, including your GraphQL endpoint.

## 6. Error Handling

Provide consistent and informative error responses.

### 6.1 Standardized Error Responses

Return errors in the `errors` array of the GraphQL response. Use the `extensions` field for custom error codes, details, and stack traces (in development environments only).

❌ **BAD**
```json
{
  "data": null,
  "httpStatus": 400,
  "customError": {
    "code": "INVALID_INPUT",
    "details": "Email is malformed"
  }
}
```

✅ **GOOD**
```json
{
  "data": null,
  "errors": [
    {
      "message": "Invalid input for field 'email'",
      "locations": [{ "line": 2, "column": 3 }],
      "path": ["createUser", "input", "email"],
      "extensions": {
        "code": "BAD_USER_INPUT",
        "validationErrors": [
          {
            "field": "email",
            "message": "Email address is not valid."
          }
        ]
      }
    }
  ]
}
```

## 7. Request/Response Patterns (HTTP)

Adhere to the "GraphQL Over HTTP" specification.

### 7.1 HTTP Method and Content-Type

Always use `POST` requests for GraphQL queries and mutations. The `Content-Type` header MUST be `application/json`.

❌ **BAD**
```
GET /graphql?query={users{id}}
```

✅ **GOOD**
```
POST /graphql
Content-Type: application/json

{
  "query": "query { users { id name } }",
  "variables": {},
  "operationName": null
}
```

### 7.2 HTTP Status Codes

A GraphQL server MUST respond with `200 OK` for all well-formed GraphQL requests, even if the GraphQL response contains errors in the `errors` array. Only use `4xx` or `5xx` status codes for HTTP-level errors (e.g., malformed request, authentication failure *before* GraphQL execution, server unavailable).

❌ **BAD**
```json
// HTTP Status: 400 Bad Request
{
  "errors": [{ "message": "User not found" }]
}
```

✅ **GOOD**
```json
// HTTP Status: 200 OK
{
  "data": { "user": null },
  "errors": [{ "message": "User not found" }]
}
```

## 8. Testing Approaches

Implement a comprehensive testing strategy covering schema, resolvers, and operations.

### 8.1 Schema Stability

Use snapshot testing for your GraphQL schema to catch unintended or breaking changes early in the development cycle. Integrate schema diff tools into your CI/CD pipeline.

```javascript
// Example using Jest and jest-serializer-graphql-schema
import { buildSchema } from 'graphql';
import { lexicographicSortSchema } from 'graphql/utilities';

const schema = buildSchema(`
  type User {
    id: ID!
    name: String!
  }
  type Query {
    users: [User!]!
  }
`);

test('schema should not change unexpectedly', () => {
  expect(lexicographicSortSchema(schema)).toMatchSnapshot();
});
```

### 8.2 Resolver Unit Tests

Unit test individual resolvers, especially those containing complex business logic, authorization checks, or data transformations. Mock external dependencies.

### 8.3 Operation Integration Tests

Write integration tests that execute full GraphQL operations (queries, mutations) against your server. These tests validate the end-to-end flow, including resolver composition and data fetching.

```javascript
// Example using Apollo Server's test utility
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';

const typeDefs = `...`; // Your schema
const resolvers = { ... }; // Your resolvers

const server = new ApolloServer({ typeDefs, resolvers });

test('fetches users correctly', async () => {
  const { url } = await startStandaloneServer(server, { listen: { port: 0 } });
  const response = await fetch(url, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      query: `query { users { id name } }`,
    }),
  });
  const { data } = await response.json();
  expect(data.users).toEqual(expect.arrayContaining([
    { id: '1', name: 'Alice' },
  ]));
});
```

### 8.4 Schema Linting

Use schema linting tools (e.g., `graphql-schema-linter`, `@graphql-eslint/eslint-plugin`) in your CI/CD to enforce naming conventions, descriptions, and deprecation patterns.

© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc

Похожие правила IDE

Все правила IDE по теме «Бэкенд и API» →
golang-graphql samber Помогает проектировать схемы GraphQL и писать резолверы на Go через gqlgen или graphql-go. Пригодится при настройке серверов, батчинге запросов и защите от N+1. CX Codex +1 37 000установок public-graphql-api-design Samuel Berthe Скилл помогает спроектировать публичный GraphQL API для сторонних разработчиков. Он задаёт правила схемы, пагинацию через Relay, лимиты сложности и границы доверия в федерации. CX Codex +1 7 600установок graphql-schema apollographql Скилл обучает проектированию схем GraphQL SDL по практикам Apollo. Помогает при создании schema.graphql, добавлении мутаций или настройке пагинации. CX Codex +1 4 100установок graphql-architect https://github.com/Jeffallan Помогает проектировать схемы GraphQL, настраивать подграфы Apollo Federation 2.5+ и устранять проблему N+1 с помощью DataLoader. CX Codex +1 4 000установок graphql-and-hidden-parameters yaklang Плейбук по тестированию GraphQL и скрытых параметров: интроспекция, батчинг, недокументированные поля и дыры в авторизации. CX Codex +1 3 600установок graphql-operations apollographql Скилл для написания GraphQL-операций: запросы, мутации, подписки и фрагменты по правилам проекта. Пригодится, когда агент сочиняет операции наугад. CX Codex +1 3 600установок

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

Весь набор →
htmx Набор инструкций для Cursor по работе с htmx. Задаёт правила декларативной вёрстки, частичных ответов сервера и запрещает лишний JavaScript для сетевых запросов. ★ 3 580звёзд репо heroku Правило подсказывает, как организовать приложение для Heroku: настроить процессы и переменные окружения, хранить состояние вне файловой системы dyno и выносить долгие задачи в фоновые процессы. ★ 3 580звёзд репо hardhat Правило для Cursor задаёт стандарты проекта на Hardhat 3: конфиг на TypeScript, тесты на Solidity и TypeScript, деплой через Ignition. ★ 3 580звёзд репо guzzle Задаёт стандарты работы с Guzzle в PHP: фабрики клиентов с таймаутами, middleware для повторов и совместимость с PSR-18. ★ 3 580звёзд репо grafana Правило задаёт команде единый стиль работы с дашбордами, алертами и источниками данных Grafana в виде кода: структура, визуальные стандарты, оптимизация запросов. ★ 3 580звёзд репо gradle Направляет ИИ на современные стандарты Gradle в проектах на Java и Android. Помогает перейти на Kotlin DSL и навести порядок в каталоге версий. ★ 3 580звёзд репо google-maps-js Правило задаёт рекомендации по работе с Google Maps JavaScript API в файлах JavaScript и JSX. Пригодится для настройки карты, загрузки библиотек и обработки событий. ★ 3 580звёзд репо godot Правило для Cursor задаёт агенту стиль разработки на Godot 4.x: композиция сцен вместо наследования, сигналы вместо прямых вызовов, аккуратная работа с ресурсами. ★ 3 580звёзд репо

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

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