логотип PurpleSchool
логотип PurpleSchool

Создание REST API в Go

Автор

Александр Гольцман

REST API — это один из самых популярных способов взаимодействия между клиентом и сервером в веб-приложениях. Он основан на архитектурных принципах REST и использует HTTP-протокол для передачи данных. В этой статье я покажу, как создать REST API на Go: разберём маршрутизацию, обработку запросов, работу с JSON и организацию кода. Кроме того, я объясню основные принципы REST и их применение в Go.

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

REST (Representational State Transfer) — это архитектурный стиль для распределённых систем, который использует стандарты HTTP для обмена данными. Основные принципы REST:

  • Клиент-сервер — сервер и клиент отделены друг от друга и взаимодействуют через HTTP.
  • Отсутствие состояния (stateless) — сервер не хранит состояние клиента между запросами.
  • Кэшируемость — ответы сервера могут кэшироваться для оптимизации производительности.
  • Единообразие интерфейса — использование стандартных HTTP-методов (GET, POST, PUT, DELETE). Подробнее об этом мы говорили в этой статье — HTTP-запросы в Golang.

REST API часто используется для создания веб-сервисов, мобильных приложений и микросервисных архитектур. В Go можно быстро создать REST API благодаря встроенной поддержке HTTP и сторонним библиотекам.

Настройка окружения и зависимостей

Для создания REST API в Go используется стандартный пакет net/http, а также сторонние библиотеки, такие как gorilla/mux или chi для удобной маршрутизации. Давайте установим необходимую библиотеку:

go get github.com/gorilla/mux

Теперь можно приступить к написанию API.

Создание простого REST API

Смотрите, как можно организовать простой сервер с маршрутизацией:

package main

import (
    "encoding/json"
    "net/http"

    "github.com/gorilla/mux"
)

type Response struct {
    Message string `json:"message"`
}

func homeHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(Response{Message: "Добро пожаловать в API"})
}

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/", homeHandler).Methods("GET")

    http.ListenAndServe(":8080", r)
}

Здесь я создал простейший сервер, который обрабатывает GET-запрос на / и возвращает JSON-ответ.

Добавление CRUD-операций

Чаще всего REST API включает операции CRUD (Create, Read, Update, Delete). Давайте реализуем их на примере работы с сущностью User.

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

type User struct {
    ID    string `json:"id"`
    Name  string `json:"name"`
    Email string `json:"email"`
}

var users = []User{}

Создание пользователя (POST)

func createUserHandler(w http.ResponseWriter, r *http.Request) {
    var user User
    json.NewDecoder(r.Body).Decode(&user)
    user.ID = fmt.Sprintf("%d", len(users)+1)
    users = append(users, user)

    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(user)
}

Получение списка пользователей (GET)

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

Обновление пользователя (PUT)

func updateUserHandler(w http.ResponseWriter, r *http.Request) {
    params := mux.Vars(r)
    id := params["id"]

    for i, user := range users {
        if user.ID == id {
            json.NewDecoder(r.Body).Decode(&users[i])
            w.Header().Set("Content-Type", "application/json")
            json.NewEncoder(w).Encode(users[i])
            return
        }
    }

    http.Error(w, "Пользователь не найден", http.StatusNotFound)
}

Удаление пользователя (DELETE)

func deleteUserHandler(w http.ResponseWriter, r *http.Request) {
    params := mux.Vars(r)
    id := params["id"]

    for i, user := range users {
        if user.ID == id {
            users = append(users[:i], users[i+1:]...)
            w.WriteHeader(http.StatusNoContent)
            return
        }
    }

    http.Error(w, "Пользователь не найден", http.StatusNotFound)
}

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

Теперь добавим маршруты в main:

func main() {
    r := mux.NewRouter()

    r.HandleFunc("/", homeHandler).Methods("GET")
    r.HandleFunc("/users", createUserHandler).Methods("POST")
    r.HandleFunc("/users", getUsersHandler).Methods("GET")
    r.HandleFunc("/users/{id}", updateUserHandler).Methods("PUT")
    r.HandleFunc("/users/{id}", deleteUserHandler).Methods("DELETE")

    http.ListenAndServe(":8080", r)
}

Теперь у нас есть полноценное REST API для работы с пользователями.

Добавление middleware

Middleware помогает обрабатывать запросы до того, как они попадут в основной обработчик. Например, можно добавить логирование:

func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Println("Запрос:", r.Method, r.URL.Path)
        next.ServeHTTP(w, r)
    })
}

Затем подключите middleware в main:

r.Use(loggingMiddleware)

Работа с базой данных

В реальном проекте данные хранятся не в памяти, а в базе данных. Для работы с PostgreSQL можно использовать gorm (подробнее об этом мы говорили в статье по PostgreSQL):

go get gorm.io/gorm
go get gorm.io/driver/postgres

Пример подключения:

db, err := gorm.Open(postgres.Open("host=localhost user=postgres dbname=mydb sslmode=disable"), &gorm.Config{})
if err != nil {
    log.Fatal("Ошибка подключения к базе данных")
}

Дальше можно использовать db.Create(&user), db.Find(&users) и другие методы для работы с данными.

Заключение

Создание REST API в Go — это относительно простой процесс благодаря стандартной библиотеке net/http и сторонним маршрутизаторам, таким как gorilla/mux. Давайте подведём итоги:

  • REST API строится на принципах REST и использует HTTP-протокол.
  • Маршрутизация в Go может быть реализована через стандартный net/http или gorilla/mux.
  • Для работы с JSON используются встроенные методы encoding/json.
  • CRUD-операции — основа любого API. Мы реализовали их для пользователей.
  • Middleware позволяют добавлять к API новые возможности, такие как логирование или аутентификация.
  • Для хранения данных вместо массива в памяти лучше использовать базу данных, например PostgreSQL с gorm.

Смотрите, где REST API может быть полезен в вашем проекте, и используйте его для создания надёжных и масштабируемых веб-приложений.

Стрелочка влевоВеб-фреймворк Echo в GolangПаттерн Builder в GolangСтрелочка вправо

Все гайды по Golang

Работа с YAML в GolangПреобразование типов в GolangКонвертация структур в JSON в GolangStrconv в GolangИспользование пакета SQLx для работы с базами данных в GolangРазбираемся с SQL в GolangРазделение строк с помощью функции split в GolangSort в GoПоиск и замена строк в Go - GolangИспользование пакета reflect в GolangРабота с PostgreSQL в GoPointers в GolangПарсинг в GoРабота со списками (list) в GolangПреобразование int в string в GolangРабота с числами с плавающей точкой в GolangРабота с полями в GolangИспользование enum в GolangОбработка JSON в GoЧтение и запись CSV-файлов в GolangРабота с cookie в GolangРегистры в GoКэширование данных в GolangПреобразование byte в string в GolangByte в GoИспользование bufio для работы с потоками данных в GolangДобавление данных и элементов (add) в Go
Логирование в Golang. Zap, Logrus, Loki, GrafanaРабота с Docker-контейнерами в GoИспользование pprof в GolangМеханизмы синхронизации в GolangРабота с пакетом S3 в GolangМониторинг Golang приложений с помощью PrometheusОптимизация проектов на GoПаттерны проектирования в GolangМиграции базы данных в GolangОркестрация контейнеров Go с Kubernetes + DockerGjGo Playground и компилятор GolangИспользование go mod init для создания модулей GolangРабота с переменными окружения (env) в GolangКоманда go build в GolangАвтоматизация Golang проектов — CI/CD с GitLab CI и JenkinsОтладка кода в GolangЧтение и использование конфигурации в приложениях на GolangКомпиляция в GolangКак развернуть Go-приложение на облаке AWSАутентификация в Golang
Сетевые протоколы в GoПеременные в GolangЗначения в GolangДженерик %T и его применение в GolangТипы данных в GolangИспользование tls в GolangИспользование tag в структурах GolangSwitch в GoСтроки в GolangРабота с потоками (stream) в GolangSelect в GoРуны в GoРабота с пакетом params в GolangКонвертация строк в числа в GolangNull, Nil, None, 0 в GoНаименования переменных, функций и структур в GoInt в GolangУстановка GolangЧтение и установка HTTP заголовков в GolangMethods в GolangGoLand — IDE для разработки на Golang от JetBrainsОбработка «not found» в GolangFloat в GolangФлаги командной строки в Go (Golang)Запуск внешних команд в GolangОбработка ошибок в GoИспользование defer в GolangЗначения default в GolangГенерация кода в GoФорматирование кода в GolangЧистая архитектура в GolangКаналы (channels) в GolangПолучение body из HTTP запроса в Golang
Открыть базу знаний