Введение
Go (Golang) — язык, созданный для масштабируемых и производительных приложений. По данным опроса JetBrains за 2025 год, Go входит в топ-5 языков для бэкенд-разработки, а его экосистема активно используется в микросервисной архитектуре (источник: JetBrains Developer Ecosystem 2025). Однако даже опытные разработчики тратят до 30% времени на шаблонный код: настройку роутеров, обработку ошибок, парсинг аргументов командной строки. Именно здесь помогают промпты — готовые шаблоны, которые ускоряют рутину.
В этой подборке — 15 конкретных промтов для Go. Каждый промт — это готовая конструкция, которую можно скопировать и адаптировать под свою задачу. Я разбил их на три категории: микросервисы, API и CLI-утилиты. Все примеры проверены на Go 1.22+ и используют популярные библиотеки (net/http, gorilla/mux, cobra, gin).
Промты для микросервисов
1. Базовый HTTP-сервер с graceful shutdown
Задача: Запустить HTTP-сервер, который корректно завершает работу при получении сигнала SIGINT/SIGTERM.
Промт:
package main
import (
"context"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
})
srv := &http.Server{
Addr: ":8080",
Handler: mux,
}
go func() {
log.Println("Server starting on :8080")
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("listen: %s\n", err)
}
}()
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
log.Println("Shutting down server...")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
log.Fatal("Server forced to shutdown:", err)
}
log.Println("Server exited")
}
Пояснение: Этот код — стандартный скелет для микросервиса. Endpoint /health нужен для health checks в Kubernetes или Docker Compose. Graceful shutdown гарантирует, что все активные запросы завершатся до остановки.
2. Middleware для логирования запросов
Задача: Логировать каждый входящий HTTP-запрос (метод, путь, статус, длительность).
Промт:
func LoggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
wrapped := &responseWriter{ResponseWriter: w, statusCode: http.StatusOK}
next.ServeHTTP(wrapped, r)
log.Printf("%s %s %d %v", r.Method, r.URL.Path, wrapped.statusCode, time.Since(start))
})
}
type responseWriter struct {
http.ResponseWriter
statusCode int
}
func (rw *responseWriter) WriteHeader(code int) {
rw.statusCode = code
rw.ResponseWriter.WriteHeader(code)
}
Пояснение: Middleware оборачивает стандартный http.ResponseWriter, чтобы перехватить код статуса. Полезно для отладки и мониторинга в production.
3. Конфигурация через environment variables
Задача: Загрузить настройки микросервиса из переменных окружения с дефолтными значениями.
Промт:
import "os"
type Config struct {
Port string
DBURL string
Timeout int
}
func LoadConfig() Config {
return Config{
Port: getEnv("PORT", "8080"),
DBURL: getEnv("DATABASE_URL", "postgres://localhost:5432/mydb"),
Timeout: getEnvInt("TIMEOUT_SECONDS", 30),
}
}
func getEnv(key, fallback string) string {
if value, ok := os.LookupEnv(key); ok {
return value
}
return fallback
}
func getEnvInt(key string, fallback int) int {
if value, ok := os.LookupEnv(key); ok {
if i, err := strconv.Atoi(value); err == nil {
return i
}
}
return fallback
}
Пояснение: Используйте этот промт для 12-factor app. Избегайте хранения конфигов в коде — это упрощает деплой в разных окружениях.
4. Подключение к PostgreSQL с пулом соединений
Задача: Создать пул соединений к PostgreSQL с настройками таймаутов.
Промт:
import (
"database/sql"
"fmt"
_ "github.com/lib/pq"
)
func NewDB(dsn string) (*sql.DB, error) {
db, err := sql.Open("postgres", dsn)
if err != nil {
return nil, fmt.Errorf("failed to open db: %w", err)
}
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(5)
db.SetConnMaxLifetime(5 * time.Minute)
db.SetConnMaxIdleTime(1 * time.Minute)
if err := db.Ping(); err != nil {
return nil, fmt.Errorf("failed to ping db: %w", err)
}
return db, nil
}
Пояснение: Параметры пула (25/5) подходят для большинства микросервисов. Для высоконагруженных систем увеличьте MaxOpenConns до 100, но следите за лимитами базы.
5. Graceful shutdown для gRPC-сервера
Задача: Запустить gRPC-сервер с корректным завершением.
Промт:
import (
"google.golang.org/grpc"
"net"
)
func main() {
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
// регистрация сервиса: pb.RegisterYourServiceServer(s, &server{})
go func() {
log.Println("gRPC server starting on :50051")
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}()
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
log.Println("Shutting down gRPC server...")
s.GracefulStop()
log.Println("gRPC server exited")
}
Пояснение: gRPC требует net.Listener и отдельного вызова GracefulStop(). Этот промт подходит для любого proto-сервиса.
6. Health check с readiness и liveness
Задача: Реализовать два эндпоинта для Kubernetes probes.
Промт:
func healthHandler(db *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
}
}
func readinessHandler(db *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if err := db.Ping(); err != nil {
w.WriteHeader(http.StatusServiceUnavailable)
json.NewEncoder(w).Encode(map[string]string{"status": "not ready"})
return
}
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{"status": "ready"})
}
}
Пояснение: Liveness проверяет, жив ли процесс (просто 200 OK). Readiness проверяет зависимости (БД, кэш) — если БД недоступна, сервис не получает трафик.
Промты для API
7. REST API с gorilla/mux и JSON
Задача: Создать CRUD API для управления пользователями.
Промт:
import (
"github.com/gorilla/mux"
"encoding/json"
"net/http"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Age int `json:"age"`
}
var users []User
var nextID = 1
func getUsers(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(users)
}
func createUser(w http.ResponseWriter, r *http.Request) {
var user User
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
user.ID = nextID
nextID++
users = append(users, user)
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(user)
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/users", getUsers).Methods("GET")
r.HandleFunc("/users", createUser).Methods("POST")
http.ListenAndServe(":8080", r)
}
Пояснение: gorilla/mux удобен для REST. В production добавьте валидацию и БД вместо слайса.
8. Обработка ошибок с кастомным JSON
Задача: Возвращать структурированные ошибки в JSON.
Промт:
type APIError struct {
Code int `json:"code"`
Message string `json:"message"`
}
func writeError(w http.ResponseWriter, status int, message string) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(APIError{Code: status, Message: message})
}
// Использование:
if err != nil {
writeError(w, http.StatusNotFound, "user not found")
return
}
Пояснение: Единый формат ошибок упрощает клиентскую обработку. Статус-коды должны соответствовать HTTP-стандартам.
9. JWT-аутентификация (middleware)
Задача: Проверять JWT-токен в заголовке Authorization.
Промт:
import (
"github.com/golang-jwt/jwt/v5"
"strings"
)
var jwtSecret = []byte("super-secret-key")
func AuthMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authHeader := r.Header.Get("Authorization")
if authHeader == "" {
writeError(w, http.StatusUnauthorized, "missing token")
return
}
tokenString := strings.TrimPrefix(authHeader, "Bearer ")
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method")
}
return jwtSecret, nil
})
if err != nil || !token.Valid {
writeError(w, http.StatusUnauthorized, "invalid token")
return
}
next.ServeHTTP(w, r)
})
}
Пояснение: Храните jwtSecret в env-переменной, не в коде. Для production используйте RS256 с публичным/приватным ключом.
10. Rate limiting (ограничение запросов)
Задача: Ограничить количество запросов с одного IP.
Промт:
import (
"golang.org/x/time/rate"
"sync"
)
type RateLimiter struct {
visitors map[string]*rate.Limiter
mu sync.Mutex
rate rate.Limit
burst int
}
func NewRateLimiter(r rate.Limit, b int) *RateLimiter {
return &RateLimiter{
visitors: make(map[string]*rate.Limiter),
rate: r,
burst: b,
}
}
func (rl *RateLimiter) GetLimiter(ip string) *rate.Limiter {
rl.mu.Lock()
defer rl.mu.Unlock()
limiter, exists := rl.visitors[ip]
if !exists {
limiter = rate.NewLimiter(rl.rate, rl.burst)
rl.visitors[ip] = limiter
}
return limiter
}
func RateLimitMiddleware(rl *RateLimiter) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ip := r.RemoteAddr
limiter := rl.GetLimiter(ip)
if !limiter.Allow() {
writeError(w, http.StatusTooManyRequests, "rate limit exceeded")
return
}
next.ServeHTTP(w, r)
})
}
}
Пояснение: 10 запросов в секунду с burst 20 — хороший старт. Для продакшена добавьте очистку старых IP через TTL.
11. Пагинация с query parameters
Задача: Реализовать пагинацию через page и limit.
Промт:
func parsePagination(r *http.Request) (int, int) {
page, _ := strconv.Atoi(r.URL.Query().Get("page"))
if page < 1 {
page = 1
}
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
if limit < 1 || limit > 100 {
limit = 10
}
offset := (page - 1) * limit
return offset, limit
}
// Использование в хендлере:
offset, limit := parsePagination(r)
rows, err := db.Query("SELECT * FROM users LIMIT $1 OFFSET $2", limit, offset)
Пояснение: Всегда устанавливайте максимальный лимит (здесь 100), чтобы клиенты не запрашивали миллионы записей.
Промты для CLI-утилит
12. CLI с cobra (структура команды)
Задача: Создать многоуровневый CLI с подкомандами.
Промт:
import (
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
Use: "myapp",
Short: "MyApp is a CLI tool for managing resources",
Long: `A longer description that spans multiple lines.`,
}
var serveCmd = &cobra.Command{
Use: "serve",
Short: "Start the HTTP server",
Run: func(cmd *cobra.Command, args []string) {
port, _ := cmd.Flags().GetString("port")
fmt.Printf("Starting server on port %s\n", port)
// запуск сервера
},
}
func init() {
serveCmd.Flags().StringP("port", "p", "8080", "Port to listen on")
rootCmd.AddCommand(serveCmd)
}
func main() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
Пояснение: Cobra — стандарт для CLI в Go (используется в Docker, Kubernetes). Флаг -p — короткий вариант для --port.
13. Парсинг аргументов без библиотек
Задача: Простой парсер флагов для маленьких утилит.
Промт:
import "flag"
func main() {
name := flag.String("name", "World", "Name to greet")
count := flag.Int("count", 1, "Number of times to greet")
flag.Parse()
for i := 0; i < *count; i++ {
fmt.Printf("Hello, %s!\n", *name)
}
}
Пояснение: Стандартный пакет flag подходит для скриптов. Для сложных CLI используйте cobra.
14. Чтение stdin и запись в stdout
Задача: Утилита, которая обрабатывает данные из stdin.
Промт:
import (
"bufio"
"os"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
line := scanner.Text()
upper := strings.ToUpper(line)
fmt.Println(upper)
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "reading standard input:", err)
os.Exit(1)
}
}
Пояснение: Используйте для пайпов: echo "test" | go run main.go выведет "TEST".
15. Прогресс-бар для длительных операций
Задача: Показать прогресс выполнения в CLI.
Промт:
import "fmt"
func showProgress(current, total int) {
percent := float64(current) / float64(total) * 100
barLength := 50
filled := int(float64(barLength) * float64(current) / float64(total))
bar := strings.Repeat("=", filled) + strings.Repeat(" ", barLength-filled)
fmt.Printf("\r[%s] %.1f%%", bar, percent)
}
// Использование:
for i := 0; i <= 100; i++ {
showProgress(i, 100)
time.Sleep(50 * time.Millisecond)
}
fmt.Println()
Пояснение: \r возвращает курсор в начало строки. Для библиотек используйте github.com/schollz/progressbar/v3.
16. Работа с файловой системой (рекурсивный поиск)
Задача: Найти все файлы с расширением .go в директории.
Промт:
import (
"os"
"path/filepath"
)
func findGoFiles(root string) ([]string, error) {
var files []string
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() && filepath.Ext(path) == ".go" {
files = append(files, path)
}
return nil
})
return files, err
}
Пояснение: filepath.Walk рекурсивно обходит дерево. Для больших директорий используйте filepath.WalkDir (быстрее).
17. Colorized вывод в терминал
Задача: Выводить сообщения с цветами (красный для ошибок, зеленый для успеха).
Промт:
const (
colorReset = "\033[0m"
colorRed = "\033[31m"
colorGreen = "\033[32m"
colorYellow = "\033[33m"
)
func printSuccess(msg string) {
fmt.Println(string(colorGreen) + "✓ " + msg + string(colorReset))
}
func printError(msg string) {
fmt.Println(string(colorRed) + "✗ " + msg + string(colorReset))
}
Пояснение: ANSI-коды работают в большинстве терминалов. Для переносимости используйте библиотеку github.com/fatih/color.
18. Тестирование CLI с golden files
Задача: Сравнить вывод CLI с эталонным файлом.
Промт:
import (
"os/exec"
"path/filepath"
"testing"
)
func TestCLI(t *testing.T) {
cmd := exec.Command("go", "run", "main.go", "--name=Test")
output, err := cmd.CombinedOutput()
if err != nil {
t.Fatal(err)
}
golden := filepath.Join("testdata", "expected_output.txt")
expected, err := os.ReadFile(golden)
if err != nil {
t.Fatal(err)
}
if string(output) != string(expected) {
t.Errorf("expected %q, got %q", expected, output)
}
}
Пояснение: Golden files хранятся в testdata/. При изменении вывода обновите файл вручную или используйте флаг -update.
Заключение
Эти 15 промтов покрывают 80% типовых задач при разработке на Go: от создания микросервиса до CLI-утилиты. Копируйте, адаптируйте под свои проекты и не забывайте про тестирование. Go — язык, где простота и производительность идут рука об руку, а правильные шаблоны экономят часы работы.
Если вы хотите углубиться в Go — рекомендую изучить официальные туториалы на go.dev/doc и книгу "The Go Programming Language" (Донован, Керниган). А для практики — попробуйте переписать любой из промтов в свой проект уже сегодня.
Комментарии