Как написать REST API на Go за 30 минут: пошаговое руководство

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

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

Начать курс

Введение: почему Go идеален для REST API?

Go (Golang) — это современный компилируемый язык программирования, созданный в Google. Он сочетает в себе высокую производительность C++ и простоту Python. Если вам нужно быстро написать REST API, Go — один из лучших выборов. В этой статье мы создадим полноценный REST API на Go за 30 минут, используя только стандартную библиотеку net/http. Вы увидите, как просто можно обрабатывать HTTP-запросы, маршрутизировать их и возвращать JSON-ответы.

К концу статьи вы сможете написать собственный API, который можно развернуть на сервере. Мы не будем использовать сторонние фреймворки — только чистый Go, что делает код легковесным и быстрым.

Шаг 1: Установка Go и создание проекта

Установка Go

Если у вас ещё не установлен Go, скачайте последнюю версию с официального сайта. Следуйте инструкциям для вашей операционной системы. После установки проверьте версию в терминале:

go version

Вы должны увидеть что-то вроде go version go1.22.0 linux/amd64.

Создание проекта

Создайте новую директорию для проекта и инициализируйте модуль Go:

mkdir go-rest-api
cd go-rest-api
go mod init go-rest-api

Теперь структура проекта готова. Мы будем писать весь код в одном файле main.go, чтобы не усложнять пример.

Шаг 2: Простой HTTP-сервер на Go

Начнём с базового HTTP-сервера. Откройте файл main.go и добавьте следующий код:

package main

import (
    "fmt"
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello, REST API on Go!")
    })

    log.Println("Сервер запущен на порту 8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

Запустите сервер командой go run main.go и откройте браузер по адресу http://localhost:8080. Вы увидите приветственное сообщение. Поздравляю — ваш первый HTTP-сервер на Go работает!

Разбор кода

  • http.HandleFunc — регистрирует обработчик для маршрута "/".
  • http.ListenAndServe — запускает сервер на порту 8080.
  • log.Fatal — выводит ошибку, если сервер не запустился.

Шаг 3: Добавляем маршрутизацию и обработку JSON

Теперь добавим поддержку REST-стиля: GET, POST, PUT, DELETE. Мы создадим простую "базу данных" в памяти (срез структур) и будем управлять списком задач (todo list).

Структура данных

Добавьте в main.go описание структуры Task и глобальный срез:

type Task struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
}

var tasks []Task
var nextID int = 1

Обработчики маршрутов

Создадим главный обработчик, который будет анализировать метод HTTP и вызывать нужную функцию:

func tasksHandler(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case http.MethodGet:
        getTasks(w, r)
    case http.MethodPost:
        createTask(w, r)
    default:
        http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
    }
}

func taskHandler(w http.ResponseWriter, r *http.Request) {
    // Извлекаем ID из URL
    idStr := strings.TrimPrefix(r.URL.Path, "/tasks/")
    id, err := strconv.Atoi(idStr)
    if err != nil {
        http.Error(w, "Invalid task ID", http.StatusBadRequest)
        return
    }

    switch r.Method {
    case http.MethodGet:
        getTask(w, r, id)
    case http.MethodPut:
        updateTask(w, r, id)
    case http.MethodDelete:
        deleteTask(w, r, id)
    default:
        http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
    }
}

Не забудьте добавить импорты: "encoding/json", "strconv", "strings".

Реализация CRUD-операций

Напишем функции для работы с задачами. Вот полный код обработчиков:

func getTasks(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(tasks)
}

func createTask(w http.ResponseWriter, r *http.Request) {
    var newTask Task
    if err := json.NewDecoder(r.Body).Decode(&newTask); err != nil {
        http.Error(w, "Invalid JSON", http.StatusBadRequest)
        return
    }
    newTask.ID = nextID
    nextID++
    tasks = append(tasks, newTask)
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(newTask)
}

func getTask(w http.ResponseWriter, r *http.Request, id int) {
    for _, task := range tasks {
        if task.ID == id {
            w.Header().Set("Content-Type", "application/json")
            json.NewEncoder(w).Encode(task)
            return
        }
    }
    http.Error(w, "Task not found", http.StatusNotFound)
}

func updateTask(w http.ResponseWriter, r *http.Request, id int) {
    var updatedTask Task
    if err := json.NewDecoder(r.Body).Decode(&updatedTask); err != nil {
        http.Error(w, "Invalid JSON", http.StatusBadRequest)
        return
    }
    for i, task := range tasks {
        if task.ID == id {
            tasks[i].Name = updatedTask.Name
            w.Header().Set("Content-Type", "application/json")
            json.NewEncoder(w).Encode(tasks[i])
            return
        }
    }
    http.Error(w, "Task not found", http.StatusNotFound)
}

func deleteTask(w http.ResponseWriter, r *http.Request, id int) {
    for i, task := range tasks {
        if task.ID == id {
            tasks = append(tasks[:i], tasks[i+1:]...)
            w.WriteHeader(http.StatusNoContent)
            return
        }
    }
    http.Error(w, "Task not found", http.StatusNotFound)
}

Регистрация маршрутов в main()

Измените функцию main():

func main() {
    http.HandleFunc("/tasks", tasksHandler)
    http.HandleFunc("/tasks/", taskHandler)

    log.Println("REST API запущен на                

Блоги

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