Tworzenie interfejsów API REST w Go: Kompletny przewodnik
Twórz gotowe do produkcji API REST z wykorzystaniem solidnego ekosystemu Go
Tworzenie wysokiej wydajności REST API z Go stało się standardowym podejściem do napędzania systemów w Google, Uber, Dropbox i licznych start-upach.
Prosta konstrukcja Go, silna obsługa współbieżności i szybka kompilacja czynią z niego idealny wybór do tworzenia mikroserwisów i rozwoju backendu.
To wspaniałe zdjęcie zostało wygenerowane przez FLUX.1-Kontext-dev: Model AI do Augmentacji Obrazu.
Dlaczego Go do tworzenia API?
Go przynosi wiele przekonujących zalet do tworzenia API:
Wydajność i wydajność: Go kompiluje się do kodu maszynowego, zapewniając wydajność zbliżoną do C bez skomplikowania. Efektywna zarządzanie pamięcią i małe rozmiary binarnej czynią z niego idealny wybór do wdrożeń w kontenerach.
Wbudowana współbieżność: Goroutines i kanały ułatwiają obsługę tysięcy żądań współbieżnych. Można przetwarzać wiele wywołań API jednocześnie bez skomplikowanego kodu wątkowego.
Silna biblioteka standardowa: Pakiet net/http oferuje gotowy do użycia serwer HTTP. Można zbudować pełne API bez żadnych zależności zewnętrznych.
Szybka kompilacja: Szybka kompilacja Go umożliwia szybkie iteracje podczas rozwoju. Duże projekty kompilują się w sekundach, a nie minutach.
Statyczne typowanie z prostotą: System typów Go wykrywa błędy w czasie kompilacji, jednocześnie zachowując przejrzystość kodu. Język ma małą liczbę funkcji, które są szybko do nauczenia.
Metody tworzenia API w Go
Używanie biblioteki standardowej
Biblioteka standardowa Go oferuje wszystko, co jest potrzebne do podstawowego rozwoju API. Oto przykład minimalny:
package main
import (
"encoding/json"
"log"
"net/http"
)
type Response struct {
Message string `json:"message"`
Status int `json:"status"`
}
func healthHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(Response{
Message: "API jest zdrowe",
Status: 200,
})
}
func main() {
http.HandleFunc("/health", healthHandler)
log.Println("Uruchamianie serwera na porcie :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
Ten podejście oferuje pełną kontrolę i zero zależności. Jest idealny do prostych API lub gdy chcesz zrozumieć obsługę HTTP na podstawowym poziomie.
Popularne frameworki webowe w Go
Choć biblioteka standardowa jest potężna, frameworki mogą przyspieszyć rozwój:
Gin: Najpopularniejszy framework webowy w Go, znany z wydajności i łatwości użycia. Oferuje wygodne routing, obsługę middleware i walidację żądań.
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.GET("/users/:id", func(c *gin.Context) {
id := c.Param("id")
c.JSON(http.StatusOK, gin.H{
"user_id": id,
"name": "John Doe",
})
})
r.Run(":8080")
}
Chi: Lekki, idiomiczny router, który czuje się jak rozszerzenie biblioteki standardowej. Jest szczególnie dobry do budowania usług REST z zagnieżdżonym routingiem.
Echo: Wysokowydajny framework z rozszerzoną obsługą middleware i wspaniałą dokumentacją. Jest zoptymalizowany pod kątem prędkości, jednocześnie pozostając przyjaznym dla programistów.
Fiber: Wzorowany na Express.js, zbudowany na Fasthttp. Jest najbardziej szybkim wyborem, ale używa innego implementacji HTTP niż biblioteka standardowa.
Architektura
Pracując z operacjami na bazach danych w Go, musisz rozważyć strategię ORM. Różne projekty porównywały podejścia takie jak GORM, Ent, Bun i sqlc, które oferują różne kompromisy między wydajnością a produktywnością programisty.
Warstwowa architektura
Zorganizuj swój API z jasnym oddzieleniem obowiązków:
// Warstwa Handlera - koncerny HTTP
type UserHandler struct {
service *UserService
}
func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
user, err := h.service.GetByID(r.Context(), id)
if err != nil {
respondError(w, err)
return
}
respondJSON(w, user)
}
// Warstwa Usługi - logika biznesowa
type UserService struct {
repo *UserRepository
}
func (s *UserService) GetByID(ctx context.Context, id string) (*User, error) {
// Walidacja, transformacja, zastosowanie reguł biznesowych
return s.repo.FindByID(ctx, id)
}
// Warstwa Repozytorium - dostęp do danych
type UserRepository struct {
db *sql.DB
}
func (r *UserRepository) FindByID(ctx context.Context, id string) (*User, error) {
// Implementacja zapytania do bazy danych
}
To oddzielenie ułatwia testowanie i utrzymuje kod w utrzymaniu, gdy projekt rośnie.
Projektowanie oparte na domenie
Dla złożonych aplikacji rozważ organizowanie kodu według domeny zamiast technicznych warstw. Każdy pakiet domeny zawiera własne modele, usługi i repozytoria.
Jeśli tworzysz aplikacje wielodostępowe, zrozumienie wzorców baz danych dla wielodostępności staje się kluczowe dla architektury API.
Obsługa żądań i walidacja
Walidacja danych wejściowych
Zawsze waliduj przychodzące dane przed przetwarzaniem:
type CreateUserRequest struct {
Email string `json:"email" validate:"required,email"`
Username string `json:"username" validate:"required,min=3,max=50"`
Age int `json:"age" validate:"gte=0,lte=150"`
}
func (h *UserHandler) CreateUser(w http.ResponseWriter, r *http.Request) {
var req CreateUserRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
respondError(w, NewBadRequestError("Nieprawidłowy JSON"))
return
}
validate := validator.New()
if err := validate.Struct(req); err != nil {
respondError(w, NewValidationError(err))
return
}
// Przetwarzanie poprawnego żądania
}
Pakiet go-playground/validator oferuje szerokie zasady walidacji i walidatory niestandardowe.
Kontekst żądania
Używaj kontekstu dla wartości zakresu żądania i anulowania:
func authMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
userID, err := validateToken(token)
if err != nil {
http.Error(w, "Nieautoryzowany", http.StatusUnauthorized)
return
}
ctx := context.WithValue(r.Context(), "userID", userID)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
Autoryzacja i bezpieczeństwo
Autoryzacja oparta na JWT
JSON Web Tokens oferują bezstanową autoryzację:
import "github.com/golang-jwt/jwt/v5"
func generateToken(userID string) (string, error) {
claims := jwt.MapClaims{
"user_id": userID,
"exp": time.Now().Add(time.Hour * 24).Unix(),
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString([]byte(os.Getenv("JWT_SECRET")))
}
func validateToken(tokenString string) (string, error) {
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
return []byte(os.Getenv("JWT_SECRET")), nil
})
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
return claims["user_id"].(string), nil
}
return "", err
}
Wzorce middleware
Zaimplementuj zagadnienia przekroczne jako middleware:
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
log.Printf("Rozpoczęto %s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
log.Printf("Zakończono w %v", time.Since(start))
})
}
func rateLimitMiddleware(next http.Handler) http.Handler {
limiter := rate.NewLimiter(10, 20) // 10 żądań/sec, wstrzymanie 20
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !limiter.Allow() {
http.Error(w, "Przekroczono limit przepustowości", http.StatusTooManyRequests)
return
}
next.ServeHTTP(w, r)
})
}
Obsługa błędów
Zaimplementuj spójne odpowiedzi na błędy:
type APIError struct {
Code int `json:"code"`
Message string `json:"message"`
Details string `json:"details,omitempty"`
}
func (e *APIError) Error() string {
return e.Message
}
func NewBadRequestError(message string) *APIError {
return &APIError{
Code: http.StatusBadRequest,
Message: message,
}
}
func NewNotFoundError(resource string) *API错误 {
return &APIError{
Code: http.StatusNotFound,
Message: fmt.Sprintf("%s nie znaleziono", resource),
}
}
func respondError(w http.ResponseWriter, err error) {
apiErr, ok := err.(*APIError)
if !ok {
apiErr = &APIError{
Code: http.StatusInternalServerError,
Message: "Wewnętrzny błąd serwera",
}
// Zaloguj rzeczywisty błąd dla debugowania
log.Printf("Nieoczekiwany błąd: %v", err)
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(apiErr.Code)
json.NewEncoder(w).Encode(apiErr)
}
Integracja z bazą danych
Zarządzanie połączeniami
Używaj puli połączeń dla wydajnego dostępu do bazy danych:
func initDB() (*sql.DB, error) {
db, err := sql.Open("postgres", os.Getenv("DATABASE_URL"))
if err != nil {
return nil, err
}
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(5)
db.SetConnMaxLifetime(5 * time.Minute)
return db, db.Ping()
}
Wzorce zapytań
Używaj przygotowanych instrukcji i kontekstu dla bezpiecznych operacji na bazie danych:
func (r *UserRepository) FindByEmail(ctx context.Context, email string) (*User, error) {
query := `SELECT id, email, username, created_at FROM users WHERE email = $1`
var user User
err := r.db.QueryRowContext(ctx, query, email).Scan(
&user.ID,
&user.Email,
&user.Username,
&user.CreatedAt,
)
if err == sql.ErrNoRows {
return nil, ErrUserNotFound
}
return &user, err
}
Strategie testowania
Testowanie handlerów
Testuj handlerów HTTP za pomocą httptest:
func TestGetUserHandler(t *testing.T) {
// Ustawienie
mockService := &MockUserService{
GetByIDFunc: func(ctx context.Context, id string) (*User, error) {
return &User{ID: "1", Username: "testuser"}, nil
},
}
handler := &UserHandler{service: mockService}
// Wykonanie
req := httptest.NewRequest("GET", "/users/1", nil)
w := httptest.NewRecorder()
handler.GetUser(w, req)
// Sprawdzenie
assert.Equal(t, http.StatusOK, w.Code)
var response User
json.Unmarshal(w.Body.Bytes(), &response)
assert.Equal(t, "testuser", response.Username)
}
Testowanie integracji
Testuj pełne scenariusze z użyciem testowej bazy danych:
func TestCreateUserEndToEnd(t *testing.T) {
// Ustawienie testowej bazy danych
db := setupTestDB(t)
defer db.Close()
// Uruchomienie testowego serwera
server := setupTestServer(db)
defer server.Close()
// Wysłanie żądania
body := strings.NewReader(`{"email":"test@example.com","username":"testuser"}`)
resp, err := http.Post(server.URL+"/users", "application/json", body)
require.NoError(t, err)
defer resp.Body.Close()
// Sprawdzenie odpowiedzi
assert.Equal(t, http.StatusCreated, resp.StatusCode)
// Sprawdzenie stanu bazy danych
var count int
db.QueryRow("SELECT COUNT(*) FROM users WHERE email = $1", "test@example.com").Scan(&count)
assert.Equal(t, 1, count)
}
Dokumentacja API
OpenAPI/Swagger
Dokumentuj swój API za pomocą specyfikacji OpenAPI:
// @title User API
// @version 1.0
// @description API do zarządzania użytkownikami
// @host localhost:8080
// @BasePath /api/v1
// @Summary Pobierz użytkownika po ID
// @Description Pobiera informacje o użytkowniku po jego ID
// @Tags użytkownicy
// @Accept json
// @Produce json
// @Param id path string true "ID użytkownika"
// @Success 200 {object} User
// @Failure 404 {object} APIError
// @Router /users/{id} [get]
func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
// Implementacja
}
Użyj swaggo/swag, aby wygenerować interaktywną dokumentację API z tych komentarzy.
Optymalizacja wydajności
Skompresowanie odpowiedzi
Włącz kompresję gzip dla odpowiedzi:
import "github.com/NYTimes/gziphandler"
func main() {
r := chi.NewRouter()
r.Use(gziphandler.GzipHandler)
// Pozostała konfiguracja
}
Caching
Zaimplementuj caching dla często odwiedzanych danych:
import "github.com/go-redis/redis/v8"
type CachedUserRepository struct {
repo *UserRepository
cache *redis.Client
}
func (r *CachedUserRepository) GetByID(ctx context.Context, id string) (*User, error) {
// Spróbuj najpierw cache
cached, err := r.cache.Get(ctx, "user:"+id).Result()
if err == nil {
var user User
json.Unmarshal([]byte(cached), &user)
return &user, nil
}
// Brak w cache - pobierz z bazy danych
user, err := r.repo.FindByID(ctx, id)
if err != nil {
return nil, err
}
// Zapisz w cache
data, _ := json.Marshal(user)
r.cache.Set(ctx, "user:"+id, data, 10*time.Minute)
return user, nil
}
Puli połączeń
Odnawiaj połączenia HTTP dla wywołań do zewnętrznych API:
var httpClient = &http.Client{
Timeout: 10 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
},
}
Rozważenia dotyczące wdrażania
Konteneryzacja za pomocą Docker
Twórz wydajne obrazy Docker za pomocą wielofazowych budów:
# Faza budowania
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o api ./cmd/api
# Faza produkcyjna
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/api .
EXPOSE 8080
CMD ["./api"]
To tworzy minimalny obraz (zwykle poniżej 20MB) z tylko Twoim binarikiem i niezbędnymi certyfikatami.
Zarządzanie konfiguracją
Używaj zmiennych środowiskowych i plików konfiguracyjnych:
type Config struct {
Port string
DatabaseURL string
JWTSecret string
LogLevel string
}
func LoadConfig() (*Config, error) {
return &Config{
Port: getEnv("PORT", "8080"),
DatabaseURL: getEnv("DATABASE_URL", ""),
JWTSecret: getEnv("JWT_SECRET", ""),
LogLevel: getEnv("LOG_LEVEL", "info"),
}, nil
}
func getEnv(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}
Zakończenie pracy w sposób łagodny
Poprawnie obsługuj sygnały zakończenia:
func main() {
server := &http.Server{
Addr: ":8080",
Handler: setupRouter(),
}
// Uruchom serwer w goroutine
go func() {
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("Błąd serwera: %v", err)
}
}()
// Oczekiwanie na sygnał przerwania
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
log.Println("Zamykanie serwera...")
// Daj żądanym żądaniami 30 sekund, aby ukończyć
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
log.Fatalf("Serwer został zmuszony do zakończenia: %v", err)
}
log.Println("Serwer wygasł")
}
Monitorowanie i obserwowalność
Strukturalne logowanie
Używaj strukturalnego logowania dla lepszej przeszukiwalności:
import "go.uber.org/zap"
func setupLogger() (*zap.Logger, error) {
config := zap.NewProductionConfig()
config.OutputPaths = []string{"stdout"}
return config.Build()
}
func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
logger := h.logger.With(
zap.String("method", r.Method),
zap.String("path", r.URL.Path),
zap.String("user_id", r.Context().Value("userID").(string)),
)
logger.Info("Przetwarzanie żądania")
// Logika handlera
}
Zbieranie metryk
Wystaw metryki Prometheus:
import "github.com/prometheus/client_golang/prometheus"
var (
requestDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "Czas trwania żądań HTTP",
},
[]string{"method", "path", "status"},
)
)
func init() {
prometheus.MustRegister(requestDuration)
}
func metricsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
recorder := &statusRecorder{ResponseWriter: w, status: 200}
next.ServeHTTP(recorder, r)
duration := time.Since(start).Seconds()
requestDuration.WithLabelValues(
r.Method,
r.URL.Path,
strconv.Itoa(recorder.status),
).Observe(duration)
})
}
Zaawansowane wzorce
Pracowanie z strukturalnym wyjściem
Gdy budujesz API, które integruje się z LLM, możesz potrzebować ograniczenia odpowiedzi z użyciem strukturalnego wyjścia. To szczególnie przydatne jest dla funkcji AI w Twoim API.
Scraping sieci dla źródeł danych API
Jeśli Twoje API potrzebuje agregacji danych z innych stron internetowych, zrozumienie alternatyw dla Beautiful Soup w Go może pomóc w implementacji solidnej funkcjonalności scrapingu sieci.
Generowanie dokumentów
Wiele API potrzebuje generowania dokumentów. Dla generowania PDF w Go, są kilka bibliotek i podejść, które możesz zintegrować z końcami API.
Semanticzne wyszukiwanie i ponowne rankowanie
Dla API, które zajmują się wyszukiwaniem i odzyskiwaniem tekstu, implementowanie ponownego rankowania z modelami embeddingu może znacząco poprawić relevantność wyników wyszukiwania.
Budowanie serwerów MCP
Jeśli implementujesz API, które przestrzega Model Context Protocol, sprawdź tę wskazówkę dotyczącą implementacji serwerów MCP w Go, która obejmuje specyfikacje protokołu i praktyczne implementacje.
Powszechne pułapki i rozwiązania
Nieprawidłowe używanie kontekstów
Zawsze przekazuj i szanuj kontekst w całym łańcuchu wywołań. To umożliwia właściwe anulowanie i obsługa limitów czasu.
Ignorowanie przecieków goroutines
Upewnij się, że wszystkie goroutines mogą zostać zakończone. Używaj kontekstów z terminami i zawsze masz sposób na sygnalizację zakończenia.
Niewystarczająca obsługa błędów
Nie zwracaj surowych błędów bazy danych do klientów. Ogranicz błędy z kontekstem i zwracaj wyczyścione komunikaty w odpowiedziach API.
Brak walidacji danych wejściowych
Waliduj wszystkie dane wejściowe na granicy. Nigdy nie zaufaj danym klienta, nawet od uwierzytelnionych użytkowników.
Niewystarczające testowanie
Nie testuj tylko przypadków idealnych. Pokryj przypadki błędów, warunki graniczne i scenariusze dostępu współbieżnego.
Podsumowanie najlepszych praktyk
-
Zacznij od prostego: Zacznij od biblioteki standardowej. Dodaj frameworky, gdy złożoność tego wymaga.
-
Warstwuj aplikację: Oddziel obsługę HTTP, logikę biznesową i dostęp do danych dla utrzymanialności.
-
Waliduj wszystko: Sprawdzaj dane wejściowe na granicy. Używaj silnego typowania i bibliotek walidacyjnych.
-
Zachowuj spójną obsługę błędów: Zwracaj strukturalne odpowiedzi na błędy. Loguj błędy wewnętrzne, ale nie wyjawiaj ich.
-
Używaj middleware: Implementuj zagadnienia przekroczne (autoryzacja, logowanie, metryki) jako middleware.
-
Testuj dokładnie: Pisz testy jednostkowe dla logiki, testy integracyjne dla dostępu do danych i testy end-to-end dla scenariuszy.
-
Dokumentuj swój API: Używaj OpenAPI/Swagger do interaktywnej dokumentacji.
-
Monitoruj produkcję: Implementuj strukturalne logowanie, zbieranie metryk i kontrole zdrowia.
-
Optymalizuj ostrożnie: Profiluj przed optymalizacją. Używaj cachingu, puli połączeń i kompresji tam, gdzie to korzystne.
-
Projektuj na łagodne wygaszanie: Obsługuj sygnały zakończenia i poprawnie wygaszaj połączenia.
Lista sprawdzania przygotowania
Dla odniesienia podczas pracy nad projektami w Go, posiadanie kompleksowego arkusza wskazówek Go w rękach może przyspieszyć rozwój i służyć jako szybki odniesienie do składni i typowych wzorców.
Gotowy do budowania swojego pierwszego API w Go? Zacznij od tych kroków:
- ✅ Ustaw środowisko Go i strukturę projektu
- ✅ Wybierz między biblioteką standardową a frameworkiem
- ✅ Zaimplementuj podstawowe punkty końcowe CRUD
- ✅ Dodaj walidację żądań i obsługa błędów
- ✅ Zaimplementuj middleware autoryzacji
- ✅ Dodaj integrację z bazą danych z pulą połączeń
- ✅ Napisz testy jednostkowe i integracyjne
- ✅ Dodaj dokumentację API
- ✅ Zaimplementuj logowanie i metryki
- ✅ Konteneryzuj z użyciem Docker
- ✅ Ustaw pipeline CI/CD
- ✅ Wdróż do produkcji z monitorowaniem
Podsumowanie
Język Go oferuje doskonałą podstawę do tworzenia interfejsów API typu REST, łącząc wydajność, prostotę oraz solidne narzędzia. Niezależnie od tego, czy tworzysz mikroserwisy, narzędzia wewnętrzne czy publiczne API, ekosystem Go ma dojrzałe rozwiązania na każde potrzeby.
Kluczem do sukcesu jest rozpoczęcie od solidnych wzorców architektonicznych, implementacja odpowiedniego obsługi błędów i walidacji od samego początku oraz budowanie kompleksowego pokrycia testów. W miarę rozwoju API, cechy wydajnościowe i silna obsługa współbieżności Go będą Cię wspierać.
Pamiętaj, że rozwój API jest iteracyjny. Zacznij od minimalnej realizacji, zbieraj opinie i doskonal odpowiedź na podstawie rzeczywistych wzorców użycia. Szybkie kompilowanie i proste refaktoryzowanie w Go sprawią, że ten cykl iteracyjny będzie płynny i produktywny.
Przydatne linki
- Go Cheat Sheet
- Porównanie ORM dla PostgreSQL w Go: GORM vs Ent vs Bun vs sqlc
- Wzorce baz danych dla wielodostępnych aplikacji w Go
- Alternatywy dla BeautifulSoup w Go
- Generowanie PDF w Go - biblioteki i przykłady
- Ograniczanie LLM za pomocą strukturalnego wyjścia: Ollama, Qwen3 i Python lub Go
- Ponowne rangowanie dokumentów tekstowych za pomocą Ollama i modelu Qwen3 Embedding w Go
- Protokół Kontekstu Modelu (MCP) oraz uwagi dotyczące implementacji serwera MCP w Go
Zewnętrzne zasoby
Oficjalna dokumentacja
- Oficjalna dokumentacja Go - Oficjalna dokumentacja i tutoriale dla Go
- Pakiet net/http w Go - Dokumentacja standardowej biblioteki HTTP
- Effective Go - Najlepsze praktyki pisania jasnego, idiomaticznego kodu Go
Popularne frameworki i biblioteki
- Framework Gin - Szybki framework HTTP z szerokim zakresem funkcji
- Chi Router - Lekkie, idiomiczne routery do tworzenia usług HTTP w Go
- Framework Echo - Wysokiej wydajności, rozszerzalny, minimalistyczny framework webowy
- Framework Fiber - Framework webowy inspirowany Express, oparty na Fasthttp
- GORM - Fantastyczna biblioteka ORM dla Go
- golang-jwt - Implementacja JWT dla Go
Narzędzia do testowania i rozwoju
- Testify - Narzędzia z częstymi asercjami i mockami
- Pakiet httptest - Narzędzia standardowej biblioteki do testowania HTTP
- Swaggo - Automatyczne generowanie dokumentacji API RESTful
- Air - Live reload dla aplikacji Go podczas rozwoju
Praktyki i wytyczne
- Layout projektu Go - Standardowe layouty projektów Go
- Wytyczne stylu Go od Uber - Kompleksowe wytyczne stylu Go od Uber
- Uwagi dotyczące recenzji kodu Go - Typowe komentarze podczas recenzji kodu Go
- Najlepsze praktyki projektowania API REST - Ogólne zasady projektowania API REST
Bezpieczeństwo i uwierzytelnianie
- OWASP Praktyki kodowania Go - Wytyczne bezpieczeństwa dla aplikacji Go
- OAuth2 dla Go - Implementacja OAuth 2.0
- Pakiet bcrypt - Implementacja hashowania haseł
Wydajność i monitorowanie
- pprof - Wbudowane narzędzie profilowania dla programów Go
- Klient Prometheus - Biblioteka do monitorowania dla Go
- Zap Logger - Szybki, strukturalny, poziomowy logowanie