Другая сторона API
Программы на Go бывают не только серверами — они и сами обращаются к API: получают данные, общаются с сервисами, интегрируют сторонние системы. Клиентская сторона net/http — это три привычки:
1. отправить запрос (http.Get, http.Post или http.NewRequest для полного контроля),
2. всегда писать defer resp.Body.Close(),
3. проверить код состояния, прежде чем доверять телу ответа.
Примеры ниже обращаются к локальному тестовому серверу, поэтому вывод стабилен — а клиентский код именно такой, какой вы направили бы на настоящий URL.
GET и декодирование
Повседневная задача: выполнить GET по URL, проверить статус и декодировать JSON прямо из тела ответа в структуры с помощью json.NewDecoder(resp.Body).Decode(&value) — промежуточная строка не нужна.
Получаем список в структуры
Тело ответа декодируется прямо в []User, а дальше это обычные данные Go — их перебирают в цикле и печатают поле за полем.
Вывод: программа на Go и захваченный вывод
package main
import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
func main() {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
fmt.Fprint(w, `[{"id": 1, "name": "Ana"}, {"id": 2, "name": "Ben"}]`)
}))
defer server.Close()
resp, err := http.Get(server.URL + "/users")
if err != nil {
fmt.Println("запрос не удался:", err)
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
fmt.Println("неожиданный статус:", resp.Status)
return
}
var users []User
if err := json.NewDecoder(resp.Body).Decode(&users); err != nil {
fmt.Println("некорректный JSON:", err)
return
}
for _, u := range users {
fmt.Printf("пользователь %d: %s\n", u.ID, u.Name)
}
}
POST с телом в формате JSON
Отправка данных — зеркальное отражение: сериализуем структуру, оборачиваем байты в reader, отправляем POST с правильным типом содержимого — а затем декодируем ответ сервера, который здесь несёт присвоенный сервером id.
Отправляем структуру, читаем ответ
Структура уходит в виде JSON, а созданная запись возвращается уже с новым id — полный путь записи данных для клиента API в одной маленькой программе.
Вывод: программа на Go и захваченный вывод
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
func main() {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var u User
json.NewDecoder(r.Body).Decode(&u)
u.ID = 7 // сервер присваивает id
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(u)
}))
defer server.Close()
payload, _ := json.Marshal(User{Name: "Cleo"})
resp, err := http.Post(server.URL+"/users", "application/json",
bytes.NewReader(payload))
if err != nil {
fmt.Println("запрос не удался:", err)
return
}
defer resp.Body.Close()
var created User
json.NewDecoder(resp.Body).Decode(&created)
fmt.Println("статус: ", resp.Status)
fmt.Printf("создан: %+v\n", created)
}