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

fiber — правило для Cursor: как писать на Go-фреймворке Fiber

Правило Cursor для проектов на Fiber в Go: задаёт работу с fiber.Ctx, структуру проекта, безопасность и обработку ошибок.

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

Что делает fiber

Это MDC-правило с globs: **/*.go, поэтому Cursor подхватывает его в любом Go-файле проекта. Главный пункт — краткость жизни fiber.Ctx: значения из c.Params, c.Query и c.Body нельзя хранить после выхода из обработчика, потому что контекст переиспользуется между запросами. Данные копируют, например через utils.CopyString, иначе горутина или фоновая задача получит чужие значения.

Внутри ещё раскладка по слоям от cmd/api/main.go до internal/handlers, services и repository. Отдельный блок про безопасность: recover, helmet, cors, csrf с настройками cookie, limiter и compress подключаются глобально через app.Use. Ошибки сводятся к своему типу AppError и одному GlobalErrorHandler в fiber.Config.

Правило рассчитано на Fiber v2 — импорты и middleware берутся из github.com/gofiber/fiber/v2. В проекте на другой версии пути не совпадут, так что фреймворк должен быть нужной ветки.

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

  • хранить параметры запроса после возврата из обработчика
  • разложить Fiber-приложение по слоям handlers, services и repository
  • включить helmet, cors и csrf до первых маршрутов
  • свести ответы об ошибках к одному формату
  • ограничить частоту запросов через limiter

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

  • Добавь правило fiber и проверь, что в обработчиках c.Params копируется перед записью в структуру
  • Разложи текущий main.go по слоям из правила fiber
  • Настрой GlobalErrorHandler и AppError, как требует правило fiber

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

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

.cursor/rules/fiber.mdc

Во frontmatter: description, globs, alwaysApply

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

Вопросы о fiber

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

Создайте файл .cursor/rules/fiber.mdc в проекте и вставьте туда содержимое правила. Cursor читает MDC-файлы из .cursor/rules автоматически.

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

Задаёт агенту набор соглашений для Fiber: копирование данных из контекста, слоистая структура, глобальные middleware безопасности и централизованная обработка ошибок.

Для какой версии Fiber оно написано?

На Fiber v2: в примерах импорты идут из github.com/gofiber/fiber/v2, middleware — из подпакетов middleware/*.

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

fiber.mdc · CC0-1.0
---
description: Definitive guidelines for writing high-performance, secure, and maintainable Fiber applications in Go. Focuses on context immutability, robust error handling, and modular design.
globs: **/*.go
---
# Fiber Best Practices

Fiber is a high-performance, Express-inspired web framework for Go, built on `fasthttp`. These rules ensure we leverage Fiber's speed and maintainability while avoiding common pitfalls.

## 1. Core Principle: `fiber.Ctx` Immutability

**NEVER** retain references to `fiber.Ctx` or any data extracted from it (like `c.Params`, `c.Query`, `c.Body`) after the handler returns. `fiber.Ctx` values are reused across requests, making their contents ephemeral. Always copy data if you need to store it.

❌ BAD: Retaining ephemeral data

```go
package handlers

import (
	"github.com/gofiber/fiber/v2"
	"log"
)

// This struct will hold a reference to the ephemeral string
type UserRequest struct {
	UserID string
}

func GetUserBad(c *fiber.Ctx) error {
	// DANGER: c.Params("id") returns an ephemeral string.
	// Storing it directly will lead to data corruption in future requests.
	req := &UserRequest{
		UserID: c.Params("id"),
	}

	// Simulating async processing or storage
	go func() {
		// By the time this goroutine runs, c.Params("id") might have changed
		log.Printf("Processing user ID: %s", req.UserID) // Will likely be wrong
	}()

	return c.SendString("Request received (bad example)")
}
```

✅ GOOD: Copying ephemeral data

```go
package handlers

import (
	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/utils" // Use Fiber's utility for efficient copying
	"log"
)

// This struct holds a safe copy of the string
type UserRequest struct {
	UserID string
}

func GetUserGood(c *fiber.Ctx) error {
	// ALWAYS copy data from c.Params, c.Query, c.Body, etc.
	userID := utils.CopyString(c.Params("id"))
	req := &UserRequest{
		UserID: userID,
	}

	// Simulating async processing or storage
	go func() {
		// This is safe; userID is a distinct copy
		log.Printf("Processing user ID: %s", req.UserID) // Will always be correct
	}()

	return c.SendString("Request received (good example)")
}
```

## 2. Code Organization and Structure

Organize your application into logical layers: `main`, `config`, `router`, `middleware`, `handlers`, `services`, `repository`, `models`, `utils`.

```
.
├── cmd/api/main.go          # Application entry point
├── config/config.go         # Application configuration loading
├── internal/
│   ├── handlers/            # HTTP request handlers
│   │   └── user_handler.go
│   ├── middleware/          # Global and route-specific middleware
│   │   └── security.go
│   ├── models/              # Data structures (structs for DB, JSON, etc.)
│   │   └── user.go
│   ├── repository/          # Database interaction logic
│   │   └── user_repo.go
│   ├── router/              # Centralized route definitions
│   │   └── router.go
│   └── services/            # Business logic layer
│       └── user_service.go
└── pkg/
    └── utils/               # Reusable utility functions
        └── response.go
```

## 3. Security Best Practices

Always apply essential security middleware globally.

```go
package middleware

import (
	"time"

	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/compress"
	"github.com/gofiber/fiber/v2/middleware/cors"
	"github.com/gofiber/fiber/v2/middleware/csrf"
	"github.com/gofiber/fiber/v2/middleware/helmet"
	"github.com/gofiber/fiber/v2/middleware/limiter"
	"github.com/gofiber/fiber/v2/middleware/logger"
	"github.com/gofiber/fiber/v2/middleware/recover"
	"github.com/gofiber/fiber/v2/utils"
)

// FiberMiddleware provides essential security and utility middleware.
func FiberMiddleware(app *fiber.App) {
	app.Use(
		// Recover from panics to prevent server crashes
		recover.New(),
		// Add security headers
		helmet.New(),
		// Enable CORS for frontend integration
		cors.New(),
		// Protect against CSRF attacks
		csrf.New(csrf.Config{
			KeyLookup:      "header:X-Csrf-Token",
			CookieName:     "__Host-csrf_",
			CookieSameSite: "Strict",
			Expiration:     3 * time.Hour,
			KeyGenerator:   utils.UUID,
		}),
		// Rate limit requests to prevent abuse
		limiter.New(limiter.Config{
			Max:        20,
			Expiration: 30 * time.Second,
			// KeyGenerator: func(c *fiber.Ctx) string { return c.IP() }, // Customize if needed
		}),
		// Compress responses
		compress.New(),
		// Request logging
		logger.New(),
	)
}
```

## 4. Error Handling

Implement a centralized error handler and use custom error types for clarity.

❌ BAD: Inconsistent error responses

```go
// handler.go
func GetUser(c *fiber.Ctx) error {
	id := c.Params("id")
	if id == "" {
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "ID is required"})
	}
	// ... database error
	return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Database error"})
}
```

✅ GOOD: Centralized error handling with custom errors

```go
package utils

import "github.com/gofiber/fiber/v2"

// AppError represents a custom application error
type AppError struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
	Err     error  `json:"-"` // Original error for logging, not exposed to client
}

func (e *AppError) Error() string {
	if e.Err != nil {
		return e.Message + ": " + e.Err.Error()
	}
	return e.Message
}

// NewAppError creates a new AppError
func NewAppError(code int, message string, err error) *AppError {
	return &AppError{
		Code:    code,
		Message: message,
		Err:     err,
	}
}

// GlobalErrorHandler handles all errors in the application
func GlobalErrorHandler(c *fiber.Ctx, err error) error {
	// Default error response
	code := fiber.StatusInternalServerError
	message := "Internal Server Error"

	if e, ok := err.(*AppError); ok {
		code = e.Code
		message = e.Message
		// Log the original error for debugging
		if e.Err != nil {
			c.App().Logger().Errorf("AppError: %s, Original: %v", e.Message, e.Err)
		}
	} else if e, ok := err.(*fiber.Error); ok {
		code = e.Code
		message = e.Message
	} else {
		// Log unexpected errors
		c.App().Logger().Errorf("Unhandled error: %v", err)
	}

	return c.Status(code).JSON(fiber.Map{
		"code":    code,
		"message": message,
	})
}
```

```go
// In your main.go or router setup:
app := fiber.New(fiber.Config{
	ErrorHandler: utils.GlobalErrorHandler,
})

// In your handler:
func GetUser(c *fiber.Ctx) error {
	id := c.Params("id")
	if id == "" {
		return utils.NewAppError(fiber.StatusBadRequest, "User ID is required", nil)
	}
	// Simulate a service call that might return an error
	user, err := userService.GetUserByID(id)
	if err != nil {
		// Wrap service errors into AppError for consistent client response
		return utils.NewAppError(fiber.StatusInternalServerError, "Failed to retrieve user", err)
	}
	return c.JSON(user)
}
```

## 5. API Design: RESTful & Consistent Responses

Design your APIs following REST principles and ensure consistent JSON response structures.

❌ BAD: Inconsistent response formats

```go
// GET /users/:id
// Success: {"id": "123", "name": "John Doe"}
// Error: "User not found" (plain text)

// POST /users
// Success: "User created" (plain text)
// Error: {"message": "Invalid input"} (JSON)
```

✅ GOOD: Standardized JSON responses

```go
package utils

// SuccessResponse for successful API calls
type SuccessResponse struct {
	Status  int         `json:"status"`
	Message string      `json:"message"`
	Data    interface{} `json:"data,omitempty"`
}

// SendSuccess sends a standardized success response
func SendSuccess(c *fiber.Ctx, status int, message string, data interface{}) error {
	return c.Status(status).JSON(SuccessResponse{
		Status:  status,
		Message: message,
		Data:    data,
	})
}
```

```go
// In your handler:
func GetUser(c *fiber.Ctx) error {
	id := c.Params("id")
	user, err := userService.GetUserByID(id)
	if err != nil {
		// Error handling via GlobalErrorHandler
		return utils.NewAppError(fiber.StatusNotFound, "User not found", err)
	}
	return utils.SendSuccess(c, fiber.StatusOK, "User retrieved successfully", user)
}

func CreateUser(c *fiber.Ctx) error {
	user := new(models.User)
	if err := c.BodyParser(user); err != nil {
		return utils.NewAppError(fiber.StatusBadRequest, "Invalid request body", err)
	}
	// ... validation and service call
	createdUser, err := userService.CreateUser(user)
	if err != nil {
		return utils.NewAppError(fiber.StatusInternalServerError, "Failed to create user", err)
	}
	return utils.SendSuccess(c, fiber.StatusCreated, "User created successfully", createdUser)
}
```

## 6. Testing Approaches

Use `httptest` and Fiber's test utilities for robust, table-driven unit tests. Inject dependencies to enable easy mocking.

```go
package handlers_test

import (
	"bytes"
	"encoding/json"
	"errors"
	"net/http/httptest"
	"testing"

	"github.com/gofiber/fiber/v2"
	"github.com/stretchr/testify/assert"

	"your_module/internal/handlers"
	"your_module/internal/models"
	"your_module/internal/services" // Mock this
	"your_module/pkg/utils"
)

// MockUserService implements the UserService interface for testing
type MockUserService struct {
	GetUserByIDFunc func(id string) (*models.User, error)
	CreateUserFunc  func(user *models.User) (*models.User, error)
}

func (m *MockUserService) GetUserByID(id string) (*models.User, error) {
	return m.GetUserByIDFunc(id)
}
func (m *MockUserService) CreateUser(user *models.User) (*models.User, error) {
	return m.CreateUserFunc(user)
}

func TestGetUser(t *testing.T) {
	app := fiber.New(fiber.Config{
		ErrorHandler: utils.GlobalErrorHandler, // Use global error handler for consistency
	})

	// Setup mock service
	mockService := &MockUserService{}
	userHandler := handlers.NewUserHandler(mockService) // Inject mock service

	app.Get("/users/:id", userHandler.GetUser)

	tests := []struct {
		name           string
		userID         string
		mockReturnUser *models.User
		mockReturnErr  error
		expectedStatus int
		expectedBody   string
	}{
		{
			name:           "Success",
			userID:         "1",
			mockReturnUser: &models.User{ID: "1", Name: "Test User"},
			mockReturnErr:  nil,
			expectedStatus: fiber.StatusOK,
			expectedBody:   `{"status":200,"message":"User retrieved successfully","data":{"id":"1","name":"Test User"}}`,
		},
		{
			name:           "Not Found",
			userID:         "2",
			mockReturnUser: nil,
			mockReturnErr:  errors.New("user not found"),
			expectedStatus: fiber.StatusNotFound,
			expectedBody:   `{"code":404,"message":"User not found"}`,
		},
		{
			name:           "Invalid ID",
			userID:         "", // Handled by handler logic
			mockReturnUser: nil,
			mockReturnErr:  nil, // This won't be called if ID is empty
			expectedStatus: fiber.StatusBadRequest,
			expectedBody:   `{"code":400,"message":"User ID is required"}`,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			mockService.GetUserByIDFunc = func(id string) (*models.User, error) {
				assert.Equal(t, tt.userID, id) // Ensure correct ID is passed
				return tt.mockReturnUser, tt.mockReturnErr
			}

			req := httptest.NewRequest(fiber.MethodGet, "/users/"+tt.userID, nil)
			resp, _ := app.Test(req, -1) // -1 disables request latency

			assert.Equal(t, tt.expectedStatus, resp.StatusCode)

			body, _ := io.ReadAll(resp.Body)
			assert.JSONEq(t, tt.expectedBody, string(body))
		})
	}
}
```

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

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

Все правила IDE по теме «Бэкенд и API» →
htmx-go-fiber-cursorrules-prompt-file PatrickJS Правило Cursor для проектов на Go с Fiber и HTMX: задаёт структуру папок, роутинг и работу с шаблонами, чтобы агент не изобретал своё. ★ 41 028звёзд репо domain-web actionbook Скилл задаёт правила проектирования веб-сервисов на Rust: от async-обработчиков до состояния, ошибок и middleware. Нужен при работе с Cargo-проектом. CX Codex +1 3 100установок web-development Mindrally Скилл с правилами веб-разработки: сетка Bootstrap, вьюхи и модели Django, атрибуты HTMX. Пригодится, когда агент пишет шаблоны и бэкенд в одном проекте. CX Codex +1 815установок Fiber AI fiber-ai MCP-сервер подключает агента к инструментам Fiber AI для поиска компаний и обогащения контактов. Подключение пригодится, когда нужно выполнять такие запросы прямо из редактора. CX Codex +1 react-three-fiber freshtechbro Скилл обучает агента строить декларативные 3D-сцены в React через Three.js, настраивать хуки рендера и загружать модели через Suspense. CX Codex +1 3 800установок golang-design-patterns samber Скилл подсказывает идиоматичные Go-паттерны для API, жизненного цикла ресурсов, graceful shutdown и архитектуры. Пригодится при проектировании и ревью кода. CX Codex +1 42 100установок

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

Весь набор →
flask Задаёт стандарты архитектуры Flask в Cursor: шаблоны фабрики приложений, синтаксис Blueprints и запуск через WSGI или ASGI. ★ 3 580звёзд репо flask-restful Правило задаёт структуру Flask-RESTful API и рекомендует Pydantic для проверки входных данных и сериализации ответов. Пригодится при создании или рефакторинге Python API. ★ 3 580звёзд репо flake8 Правило для Cursor задаёт, как настроить flake8 и какие проверки включить. Пригодится, если в проекте есть Python и хочется ловить стилевые ошибки и баги до коммита. ★ 3 580звёзд репо firebase Задаёт стандарты безопасности для Firebase в проекте. Помогает настроить App Check и закрыть доступ к базе через Security Rules. ★ 3 580звёзд репо ffmpeg Правило для Cursor, которое задаёт агенту порядок работы с FFmpeg: вызовы через libav*, двухпроходное кодирование и закреплённые сборки в CI. ★ 3 580звёзд репо fastapi Задаёт стандарты разработки на FastAPI: доменную структуру файлов, валидацию через Pydantic и асинхронные зависимости. ★ 3 580звёзд репо fabric-js Правило задаёт практики для fabric-js в JavaScript и TypeScript: модульные импорты, выбор типа canvas и приёмы ускорения рендера. ★ 3 580звёзд репо express Правило для Cursor задаёт структуру Express.js-проекта: слои, конфиг через .env, async/await, валидацию ввода и защитные middleware. ★ 3 580звёзд репо

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

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