Пример: HTTP-сервер

Собираем небольшой HTTP-сервер с JSON API на одной только стандартной библиотеке.

Пакет net/http позволяет написать рабочий веб-сервер в несколько строк — без фреймворков. Это показывает, насколько Go заточен под сетевые сервисы.

Сервер «Hello» в десять строк

Минимальный сервер регистрирует обработчик на путь и слушает порт. Обработчик — функция, получающая ResponseWriter (куда писать ответ) и *Request (данные запроса).

package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Привет, %s!", r.URL.Path[1:])
    })

    fmt.Println("слушаю :8080")
    http.ListenAndServe(":8080", nil)
}
go run main.go
# в другом терминале:
curl http://localhost:8080/Go

Вывод:

Привет, Go!

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

JSON API: чуть ближе к реальности

Соберём эндпоинт, который отдаёт JSON. Объединим то, что уже знаем: структуры, теги JSON и encoding/json.

package main

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

type Status struct {
    Service string `json:"service"`
    OK      bool   `json:"ok"`
}

func statusHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    s := Status{Service: "api", OK: true}
    json.NewEncoder(w).Encode(s)
}

func main() {
    http.HandleFunc("/status", statusHandler)
    http.ListenAndServe(":8080", nil)
}
curl http://localhost:8080/status

Вывод:

{"service":"api","ok":true}

Мы выставили заголовок Content-Type и закодировали структуру прямо в поток ответа через json.NewEncoder(w).Encode. Никаких внешних библиотек — всё из стандартной поставки.

Маршрутизация по методам

В реальном API разные HTTP-методы делают разное. Их различают по r.Method. Современный Go (1.22+) умеет даже задавать метод прямо в паттерне: http.HandleFunc("POST /users", ...).

func usersHandler(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case http.MethodGet:
        w.Write([]byte("список пользователей"))
    case http.MethodPost:
        w.WriteHeader(http.StatusCreated)
        w.Write([]byte("пользователь создан"))
    default:
        http.Error(w, "метод не поддерживается", http.StatusMethodNotAllowed)
    }
}

Что дальше с веб-сервисами

Этого достаточно для простых сервисов. Для крупных API берут роутеры (chi, gorilla/mux) или фреймворки (Gin, Echo), но даже они построены поверх того же net/http. Понимание базы делает их освоение лёгким.

Итог

  • Рабочий HTTP-сервер пишется на net/http без фреймворков.
  • Каждый запрос Go обрабатывает в своей горутине — конкурентность встроена.
  • JSON-ответ — связка структуры с тегами и json.NewEncoder(w).Encode.
Проверьте себя
1. Какой пакет нужен для HTTP-сервера в Go без фреймворков?
Anet/http
Bfmt
Cos
Dencoding/json
2. Как Go обрабатывает несколько одновременных HTTP-запросов?
AПо очереди в одном потоке
BКаждый запрос в отдельной горутине автоматически
CОтклоняет лишние
DТребует ручной настройки потоков
3. Как отдать структуру в виде JSON в ответе?
Afmt.Println(s)
Bjson.NewEncoder(w).Encode(s)
Cw.Write(s)
Dreturn s
Поддержать проект