Опишите процесс взаимодействия со сторонним API в Go

Ответ

Взаимодействие со сторонними API в Go строится на основе стандартного пакета net/http. Для более удобной работы можно использовать сторонние библиотеки, например, resty.

Базовый алгоритм:

  1. Создание HTTP-клиента: Используется http.Client. Рекомендуется настраивать таймаут, чтобы избежать зависания приложения.
  2. Формирование запроса: Создается объект http.Request с помощью http.NewRequest(). Здесь указывается метод (GET, POST и т.д.), URL и тело запроса (если необходимо).
  3. Добавление заголовков: Заголовки (например, Content-Type, Authorization) добавляются к запросу через req.Header.Set().
  4. Отправка запроса: Клиент выполняет запрос с помощью метода client.Do(req).
  5. Обработка ответа:
    • Проверяется статус-код ответа (resp.StatusCode).
    • Тело ответа (resp.Body) читается с помощью io.ReadAll.
    • Тело (чаще всего JSON) десериализуется в структуру Go с помощью json.Unmarshal.

Пример (GET-запрос с таймаутом и заголовком):

package main

import (
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "time"
)

// Структура для парсинга JSON-ответа
type MyStruct struct {
    UserID int    `json:"userId"`
    ID     int    `json:"id"`
    Title  string `json:"title"`
}

func main() {
    // 1. Создаем HTTP-клиент с таймаутом
    client := &http.Client{Timeout: 10 * time.Second}

    // 2. Формируем запрос
    req, err := http.NewRequest("GET", "https://jsonplaceholder.typicode.com/todos/1", nil)
    if err != nil {
        panic(err)
    }

    // 3. Добавляем заголовки
    req.Header.Add("Accept", "application/json")

    // 4. Отправляем запрос
    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    // 5. Обрабатываем ответ
    if resp.StatusCode != http.StatusOK {
        fmt.Println("Error: status code", resp.StatusCode)
        return
    }

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        panic(err)
    }

    var result MyStruct
    if err := json.Unmarshal(body, &result); err != nil {
        panic(err)
    }

    fmt.Printf("Результат: %+vn", result)
}

Продвинутые практики (Production-ready):

  • Context: Использование context.WithTimeout или context.WithCancel для контроля над жизненным циклом запроса.
  • Retry-логика: Реализация повторных запросов при временных сбоях сети или сервера (например, с экспоненциальной задержкой).
  • Circuit Breaker: Использование паттерна "Предохранитель" (например, с библиотекой sony/gobreaker) для предотвращения каскадных сбоев.
  • Логирование: Подробное логирование запросов, ответов и ошибок.
  • Метрики: Сбор метрик (время ответа, количество ошибок) для мониторинга.