Gin для Go: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Что такое Gin и зачем он нужен?

Gin — это высокопроизводительный веб-фреймворк для языка программирования Go, написанный на чистом Go без внешних зависимостей. Он предоставляет разработчикам минималистичный, но мощный инструментарий для создания REST API, веб-приложений и микросервисов. Основные причины, почему стоит выбрать Gin:

  • Скорость: Gin использует собственный маршрутизатор на основе дерева (Radix tree), что делает его одним из самых быстрых фреймворков для Go. Он в 2-5 раз быстрее стандартного net/http.
  • Простота: API интуитивно понятен, минимальный код для запуска сервера.
  • Middleware: Встроенная поддержка цепочек промежуточного ПО (middleware) для логирования, аутентификации, CORS и т.д.
  • Валидация: Мощная система валидации запросов (binding) с поддержкой структур.
  • Производительность: Низкое потребление памяти и высокая пропускная способность.
  • Сообщество: Огромное комьюнити, множество готовых middleware и плагинов.

Gin идеально подходит для: создания RESTful API, микросервисов, бэкенда для SPA-приложений, прокси-серверов и любых HTTP-приложений, где важна скорость.

Установка

Установка Gin осуществляется через стандартный менеджер пакетов Go. Убедитесь, что у вас установлен Go версии 1.13 или выше.

# Инициализация модуля (если ещё не сделано)
go mod init myapp

# Установка Gin
go get -u github.com/gin-gonic/gin

После выполнения команды Gin будет добавлен в go.mod и go.sum. Теперь вы можете импортировать его в своём коде:

import "github.com/gin-gonic/gin"

Быстрый старт: первый сервер на Gin

Создайте файл main.go и напишите простейший HTTP-сервер:

package main

import (
    "net/http"
    "github.com/gin-gonic/gin"
)

func main() {
    // Создаём роутер с middleware по умолчанию (логгер + recovery)
    r := gin.Default()

    // Определяем маршрут GET /
    r.GET("/", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{
            "message": "Hello, Gin!",
        })
    })

    // Запускаем сервер на порту 8080
    r.Run(":8080")
}

Запустите приложение:

go run main.go

Теперь откройте браузер и перейдите на http://localhost:8080/. Вы увидите JSON-ответ: {"message":"Hello, Gin!"}.

Основные методы и функции Gin

Ниже представлены 10 ключевых методов и функций Gin с подробным описанием и примерами.

1. gin.Default()

Что делает: Создаёт новый экземпляр роутера Gin с двумя встроенными middleware: Logger (логирование запросов) и Recovery (восстановление после паники).

Параметры: Нет.

Пример:

r := gin.Default()

2. r.GET() / r.POST() / r.PUT() / r.DELETE()

Что делает: Определяет обработчик для соответствующего HTTP-метода и пути.

Параметры:

  • relativePath (string) — путь маршрута (например, "/users/:id")
  • handlers (...HandlerFunc) — одна или несколько функций-обработчиков

Пример:

r.GET("/users", func(c *gin.Context) {
    c.JSON(200, gin.H{"users": []string{"Alice", "Bob"}})
})

r.POST("/users", func(c *gin.Context) {
    // Создание пользователя
    c.JSON(201, gin.H{"status": "created"})
})

3. c.JSON()

Что делает: Отправляет клиенту JSON-ответ с указанным HTTP-статусом.

Параметры:

  • code (int) — HTTP статус-код (например, 200, 404)
  • obj (interface{}) — данные для сериализации в JSON

Пример:

c.JSON(http.StatusOK, gin.H{
    "id":   1,
    "name": "John",
})

4. c.BindJSON()

Что делает: Парсит тело запроса (JSON) и связывает его с переданной структурой. Автоматически проверяет Content-Type.

Параметры:

  • obj (interface{}) — указатель на структуру, в которую будут записаны данные

Пример:

type User struct {
    Name  string `json:"name" binding:"required"`
    Email string `json:"email" binding:"required,email"`
}

func createUser(c *gin.Context) {
    var user User
    if err := c.BindJSON(&user); err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }
    c.JSON(200, gin.H{"user": user})
}

5. c.Param()

Что делает: Извлекает значение параметра пути из URL (например, /users/:id).

Параметры:

  • key (string) — имя параметра

Пример:

r.GET("/users/:id", func(c *gin.Context) {
    id := c.Param("id")
    c.JSON(200, gin.H{"user_id": id})
})

6. c.Query()

Что делает: Извлекает значение query-параметра из URL (например, /search?q=golang).

Параметры:

  • key (string) — имя параметра

Пример:

r.GET("/search", func(c *gin.Context) {
    query := c.Query("q")
    page := c.DefaultQuery("page", "1") // со значением по умолчанию
    c.JSON(200, gin.H{"query": query, "page": page})
})

7. r.Use()

Что делает: Добавляет middleware (промежуточное ПО) ко всем маршрутам роутера или группы.

Параметры:

  • middleware (...HandlerFunc) — одна или несколько middleware-функций

Пример:

func Logger() gin.HandlerFunc {
    return func(c *gin.Context) {
        t := time.Now()
        c.Next()
        latency := time.Since(t)
        log.Printf("Request %s took %v", c.Request.URL.Path, latency)
    }
}

r.Use(Logger())

8. r.Group()

Что делает: Создаёт группу маршрутов с общим префиксом и/или middleware.

Параметры:

  • relativePath (string) — префикс для всех маршрутов группы
  • handlers (...HandlerFunc) — middleware для группы (опционально)

Пример:

api := r.Group("/api")
{
    api.GET("/users", getUsers)
    api.POST("/users", createUser)
}

admin := r.Group("/admin", gin.BasicAuth(gin.Accounts{
    "admin": "secret",
}))
{
    admin.GET("/dashboard", dashboardHandler)
}

9. c.Set() / c.Get()

Что делает: Позволяет сохранять и извлекать произвольные данные в контексте запроса. Полезно для передачи данных между middleware и обработчиками.

Параметры:

  • key (string) — ключ
  • value (interface{}) — значение (только для Set)

Пример:

func AuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        token := c.GetHeader("Authorization")
        if token == "valid-token" {
            c.Set("user_id", 123)
            c.Next()
        } else {
            c.AbortWithStatusJSON(401, gin.H{"error": "unauthorized"})
        }
    }
}

r.GET("/profile", AuthMiddleware(), func(c *gin.Context) {
    userID, _ := c.Get("user_id")
    c.JSON(200, gin.H{"user_id": userID})
})

10. c.Redirect()

Что делает: Выполняет HTTP-редирект (перенаправление) на другой URL.

Параметры:

  • code (int) — статус-код редиректа (301, 302, 307 и т.д.)
  • location (string) — целевой URL

Пример:

r.GET("/old-page", func(c *gin.Context) {
    c.Redirect(http.StatusMovedPermanently, "/new-page")
})

Реальный практический пример: REST API для управления задачами

Создадим полноценное приложение для управления списком задач (Todo API) с использованием Gin.

package main

import (
    "net/http"
    "strconv"
    "github.com/gin-gonic/gin"
)

// Модель задачи
type Todo struct {
    ID    int    `json:"id"`
    Title string `json:"title" binding:"required"`
    Done  bool   `json:"done"`
}

// Хранилище в памяти
var todos = []Todo{
    {ID: 1, Title: "Изучить Gin", Done: false},
    {ID: 2, Title: "Написать API", Done: false},
}

var nextID = 3

func main() {
    r := gin.Default()

    // Группа маршрутов для API
    api := r.Group("/api")
    {
        api.GET("/todos", getTodos)
        api.GET("/todos/:id", getTodoByID)
        api.POST("/todos", createTodo)
        api.PUT("/todos/:id", updateTodo)
        api.DELETE("/todos/:id", deleteTodo)
    }

    r.Run(":8080")
}

// GET /api/todos — получить все задачи
func getTodos(c *gin.Context) {
    c.JSON(http.StatusOK, todos)
}

// GET /api/todos/:id — получить задачу по ID
func getTodoByID(c *gin.Context) {
    id, err := strconv.Atoi(c.Param("id"))
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
        return
    }

    for _, todo := range todos {
        if todo.ID == id {
            c.JSON(http.StatusOK, todo)
            return
        }
    }
    c.JSON(http.StatusNotFound, gin.H{"error": "todo not found"})
}

// POST /api/todos — создать новую задачу
func createTodo(c *gin.Context) {
    var newTodo Todo
    if err := c.BindJSON(&newTodo); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    newTodo.ID = nextID
    nextID++
    todos = append(todos, newTodo)

    c.JSON(http.StatusCreated, newTodo)
}

// PUT /api/todos/:id — обновить задачу
func updateTodo(c *gin.Context) {
    id, err := strconv.Atoi(c.Param("id"))
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
        return
    }

    var updatedTodo Todo
    if err := c.BindJSON(&updatedTodo); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    for i, todo := range todos {
        if todo.ID == id {
            updatedTodo.ID = id
            todos[i] = updatedTodo
            c.JSON(http.StatusOK, updatedTodo)
            return
        }
    }                    

Рекомендаций