Skip to main content Skills Marketplace コミュニティが作成したAIスキルを発見・探索
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
直接コマンドでは確認用 Prompt が省略されます。実行前にソースを確認してください。
npx skills add https://github.com/bobmatnyc/claude-mpm-skills --skill golang-http-frameworksコマンドは1行のまま表示されます。コピー前に横へスクロールして全体を確認してください。
ローカルで確認しますか?SkillsMP が現在取得できるファイルをダウンロードできます。
Zipをダウンロード ダウンロード中... このリポジトリの他の Skills LinkedIn automation via the Linked API CLI - fetch profiles, search people and companies, send messages, manage connections, create posts, react, comment, and run Sales Navigator and custom workflows. Use when the user wants to interact with LinkedIn.
Xquik X data automation API - Use REST or MCP for tweet search, user lookup, follower exports, media downloads, monitors, webhooks, giveaway draws, and confirmation-gated X actions.
MCP (Model Context Protocol) - Build AI-native servers with tools, resources, and prompts. TypeScript/Python SDKs for Claude Desktop integration.
name golang-http-frameworks description Go HTTP API development with net/http, Chi, Gin, Echo, and Fiber frameworks user-invocable false disable-model-invocation true version 1.1.0 updated 2026-06-15 category toolchain author Claude MPM Team license MIT progressive_disclosure {"entry_point":{"summary":"Master Go HTTP frameworks from stdlib net/http to Chi, Gin, Echo, and Fiber for building production-ready REST APIs with middleware, validation, and client patterns","when_to_use":"Building RESTful APIs, choosing HTTP framework, implementing authentication middleware, designing REST endpoints, testing HTTP handlers, optimizing API performance","quick_start":"1. Choose framework (stdlib, Chi, Gin, Echo, Fiber) 2. Structure routes and middleware 3. Implement request validation 4. Design error handling 5. Test with httptest"},"references":["go-idioms-quality.md"],"token_estimate":{"entry":160,"full":5000}} context_limit 700 tags ["http","golang","chi","gin","echo","fiber","rest-api","middleware"] requires_tools []
Go HTTP Frameworks & REST APIs
Overview
Go provides exceptional HTTP capabilities starting with the standard library's net/http package. Go 1.22+ introduced enhanced pattern routing in ServeMux, making stdlib viable for many applications. For more complex needs, frameworks like Chi, Gin, Echo, and Fiber offer additional features while maintaining Go's simplicity and performance.
Key Features:
🌐 net/http : Production-ready standard library with Go 1.22+ routing
🎯 Chi : Lightweight, stdlib-compatible router with middleware chains
⚡ Gin : High-performance framework with binding and validation
🛡️ Echo : Type-safe, enterprise framework with OpenAPI support
🚀 Fiber : Express.js-inspired framework with WebSocket support
🔧 Middleware : Composable request/response processing
✅ Validation : Struct tag-based request validation
🧪 Testing : httptest.Server for comprehensive integration tests
When to Use This Skill
Activate this skill when:
Building RESTful APIs or web services
Choosing appropriate HTTP framework for project requirements
Implementing authentication or authorization middleware
Designing REST endpoint patterns and validation
Testing HTTP handlers and middleware chains
Optimizing API performance and response times
Migrating between HTTP frameworks
Framework Selection Guide
net/http (Standard Library) - Go 1.22+
Use When:
Building simple to moderate complexity APIs
Avoiding external dependencies is priority
Need maximum compatibility and long-term stability
Team prefers explicit over implicit patterns
Strengths:
Zero dependencies, part of Go standard library
Go 1.22+ pattern routing with path parameters
Excellent performance and stability
Extensive ecosystem compatibility
No framework lock-in
Limitations:
More verbose middleware composition
Manual request validation
No built-in binding or rendering
Example:
package main
import (
"encoding/json"
"net/http"
"log"
)
func main () {
mux := http.NewServeMux()
mux.HandleFunc("GET /users/{id}" , getUserHandler)
mux.HandleFunc("POST /users" , createUserHandler)
mux.HandleFunc("GET /users" , listUsersHandler)
handler := loggingMiddleware(mux)
log.Fatal(http.ListenAndServe(":8080" , handler))
}
func getUserHandler (w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id" )
user := User{ID: id, Name: "John Doe" }
w.Header().Set("Content-Type" , "application/json" )
json.NewEncoder(w).Encode(user)
}
func loggingMiddleware (next http.Handler) http.Handler {
return http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) {
log.Printf("%s %s" , r.Method, r.URL.Path)
next.ServeHTTP(w, r)
})
}
type User struct {
ID string `json:"id"`
Name string `json:"name"`
}
Chi - Lightweight Router
Want stdlib-compatible router with better ergonomics
Need clean middleware composition
Prefer explicit over magic patterns
Building moderate to complex routing structures
100% compatible with net/http
Excellent middleware ecosystem
Route grouping and nesting
Context-based parameter passing
Minimal performance overhead
go get -u github.com/go-chi/chi/v5
package main
import (
"encoding/json"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
func main () {
r := chi.NewRouter()
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
r.Use(middleware.RequestID)
r.Route("/api/v1" , func (r chi.Router) {
r.Route("/users" , func (r chi.Router) {
r.Get("/" , listUsers)
r.Post("/" , createUser)
r.Route("/{userID}" , func (r chi.Router) {
r.Use(UserContext)
r.Get("/" , getUser)
r.Put("/" , updateUser)
r.Delete("/" , deleteUser)
})
})
})
http.ListenAndServe(":8080" , r)
}
func UserContext (next http.Handler) http.Handler {
return http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) {
userID := chi.URLParam(r, "userID" )
ctx := context.WithValue(r.Context(), "user" , userID)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func getUser (w http.ResponseWriter, r *http.Request) {
userID := r.Context().Value("user" ).(string )
json.NewEncoder(w).Encode(map [string ]string {"id" : userID})
}
Gin - High Performance Framework
Need maximum performance (8x faster than most frameworks)
Want batteries-included experience
Require built-in validation and binding
Building JSON APIs with minimal boilerplate
Extremely fast (fastest Go framework in benchmarks)
Built-in JSON binding and validation
Middleware ecosystem
Group-based routing
Custom error handling
go get -u github.com/gin-gonic/gin
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
type CreateUserRequest struct {
Name string `json:"name" binding:"required,min=3"`
Email string `json:"email" binding:"required,email"`
Age int `json:"age" binding:"required,gte=18"`
}
func main () {
r := gin.Default()
api := r.Group("/api/v1" )
{
users := api.Group("/users" )
{
users.GET("" , listUsers)
users.POST("" , createUser)
users.GET("/:id" , getUser)
users.PUT("/:id" , updateUser)
users.DELETE("/:id" , deleteUser)
}
}
r.Run(":8080" )
}
func createUser (c *gin.Context) {
var req CreateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error" : err.Error()})
return
}
user := User{
ID: generateID(),
Name: req.Name,
Email: req.Email,
Age: req.Age,
}
c.JSON(http.StatusCreated, user)
}
func getUser (c *gin.Context) {
id := c.Param("id" )
c.JSON(http.StatusOK, gin.H{
"id" : id,
"name" : "John Doe" ,
})
}
Echo - Enterprise Framework
Building enterprise applications
Need OpenAPI/Swagger integration
Want comprehensive middleware library
Require type-safe routing and binding
Type-safe routing with automatic parameter binding
Built-in middleware for common patterns
OpenAPI/Swagger generation support
Excellent error handling middleware
WebSocket support
go get -u github.com/labstack/echo/v4
package main
import (
"net/http"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
func main () {
e := echo.New()
e.Use(middleware.Logger())
e.Use(middleware.Recover())
e.Use(middleware.CORS())
e.GET("/users/:id" , getUser)
e.POST("/users" , createUser)
e.PUT("/users/:id" , updateUser)
e.DELETE("/users/:id" , deleteUser)
e.Logger.Fatal(e.Start(":8080" ))
}
func getUser (c echo.Context) error {
id := c.Param("id" )
user := User{ID: id, Name: "John Doe" }
return c.JSON(http.StatusOK, user)
}
func createUser (c echo.Context) error {
var user User
if err := c.Bind(&user); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
if err := c.Validate(&user); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
return c.JSON(http.StatusCreated, user)
}
func customErrorHandler (err error , c echo.Context) {
code := http.StatusInternalServerError
message := "Internal Server Error"
if he, ok := err.(*echo.HTTPError); ok {
code = he.Code
message = he.Message.(string )
}
c.JSON(code, map [string ]string {"error" : message})
}
Fiber - Express.js Style
Team familiar with Express.js patterns
Need WebSocket support out of the box
Building real-time applications
Want fastest route matching performance
Express.js-inspired API (easy for Node.js developers)
Fastest route matching (uses fasthttp)
Built-in WebSocket support
Template engine support
File upload handling
Uses fasthttp instead of net/http (less ecosystem compatibility)
Not compatible with standard http.Handler interface
Slightly less mature ecosystem
go get -u github.com/gofiber/fiber/v2
package main
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gofiber/fiber/v2/middleware/cors"
)
func main () {
app := fiber.New()
app.Use(logger.New())
app.Use(cors.New())
api := app.Group("/api/v1" )
users := api.Group("/users" )
users.Get("/" , listUsers)
users.Post("/" , createUser)
users.Get("/:id" , getUser)
users.Put("/:id" , updateUser)
users.Delete("/:id" , deleteUser)
app.Listen(":8080" )
}
func getUser (c *fiber.Ctx) error {
id := c.Params("id" )
return c.JSON(fiber.Map{
"id" : id,
"name" : "John Doe" ,
})
}
func createUser (c *fiber.Ctx) error {
var user User
if err := c.BodyParser(&user); err != nil {
return c.Status(400 ).JSON(fiber.Map{"error" : err.Error()})
}
return c.Status(201 ).JSON(user)
}
Common HTTP Patterns
Request Validation import "github.com/go-playground/validator/v10"
type CreateUserRequest struct {
Name string `json:"name" validate:"required,min=3,max=50"`
Email string `json:"email" validate:"required,email"`
Age int `json:"age" validate:"required,gte=18,lte=120"`
Password string `json:"password" validate:"required,min=8"`
}
var validate = validator.New()
func validateRequest (req interface {}) error {
return validate.Struct(req)
}
func createUser (w http.ResponseWriter, r *http.Request) {
var req CreateUserRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid JSON" , http.StatusBadRequest)
return
}
if err := validateRequest(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
}
import "github.com/go-playground/validator/v10"
var validate = validator.New()
func init () {
validate.RegisterValidation("username" , validateUsername)
}
func validateUsername (fl validator.FieldLevel) bool {
username := fl.Field().String()
return len (username) >= 3 && isAlphanumeric(username)
}
type SignupRequest struct {
Username string `validate:"required,username"`
Email string `validate:"required,email"`
}
Middleware Patterns Authentication Middleware:
func AuthMiddleware (next http.Handler) http.Handler {
return http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization" )
if token == "" {
http.Error(w, "Unauthorized" , http.StatusUnauthorized)
return
}
userID, err := validateToken(token)
if err != nil {
http.Error(w, "Invalid token" , http.StatusUnauthorized)
return
}
ctx := context.WithValue(r.Context(), "userID" , userID)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
Rate Limiting Middleware:
import (
"golang.org/x/time/rate"
"sync"
)
type RateLimiter struct {
limiters map [string ]*rate.Limiter
mu sync.RWMutex
rate rate.Limit
burst int
}
func NewRateLimiter (r rate.Limit, b int ) *RateLimiter {
return &RateLimiter{
limiters: 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.limiters[ip]
if !exists {
limiter = rate.NewLimiter(rl.rate, rl.burst)
rl.limiters[ip] = limiter
}
return limiter
}
func (rl *RateLimiter) Middleware(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() {
http.Error(w, "Rate limit exceeded" , http.StatusTooManyRequests)
return
}
next.ServeHTTP(w, r)
})
}
func CORSMiddleware (next http.Handler) http.Handler {
return http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin" , "*" )
w.Header().Set("Access-Control-Allow-Methods" , "GET, POST, PUT, DELETE, OPTIONS" )
w.Header().Set("Access-Control-Allow-Headers" , "Content-Type, Authorization" )
if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
return
}
next.ServeHTTP(w, r)
})
}
Error Handling Strategies 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 (msg string ) *APIError {
return &APIError{Code: http.StatusBadRequest, Message: msg}
}
func NewNotFoundError (msg string ) *APIError {
return &APIError{Code: http.StatusNotFound, Message: msg}
}
func NewInternalError (msg string ) *APIError {
return &APIError{Code: http.StatusInternalServerError, Message: msg}
}
Error Response Middleware:
type APIHandler func (w http.ResponseWriter, r *http.Request) error
func ErrorHandlerMiddleware (h APIHandler) http.Handler {
return http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) {
err := h(w, r)
if err == nil {
return
}
var apiErr *APIError
if errors.As(err, &apiErr) {
w.Header().Set("Content-Type" , "application/json" )
w.WriteHeader(apiErr.Code)
json.NewEncoder(w).Encode(apiErr)
return
}
log.Printf("Internal error: %v" , err)
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(APIError{
Code: http.StatusInternalServerError,
Message: "Internal server error" ,
})
})
}
func getUserHandler (w http.ResponseWriter, r *http.Request) error {
id := r.PathValue("id" )
user, err := db.GetUser(id)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return NewNotFoundError("User not found" )
}
return fmt.Errorf("database error: %w" , err)
}
w.Header().Set("Content-Type" , "application/json" )
return json.NewEncoder(w).Encode(user)
}
mux.Handle("GET /users/{id}" , ErrorHandlerMiddleware(getUserHandler))
REST API Design Patterns Resource Naming Conventions:
GET /api/v1/users
POST /api/v1/users
GET /api/v1/users/{id}
PUT /api/v1/users/{id}
PATCH /api/v1/users/{id}
DELETE /api/v1/users/{id}
GET /api/v1/users/{id}/posts
POST /api/v1/users/{id}/posts
GET /api/v1/users/{id}/posts/{pid}
type PaginationParams struct {
Page int `json:"page" validate:"gte=1"`
PageSize int `json:"page_size" validate:"gte=1,lte=100"`
}
type PaginatedResponse struct {
Data interface {} `json:"data"`
Page int `json:"page"`
PageSize int `json:"page_size"`
TotalCount int `json:"total_count"`
TotalPages int `json:"total_pages"`
}
func listUsers (w http.ResponseWriter, r *http.Request) {
page, _ := strconv.Atoi(r.URL.Query().Get("page" ))
if page < 1 {
page = 1
}
pageSize, _ := strconv.Atoi(r.URL.Query().Get("page_size" ))
if pageSize < 1 || pageSize > 100 {
pageSize = 20
}
users, totalCount := db.GetUsers(page, pageSize)
totalPages := (totalCount + pageSize - 1 ) / pageSize
response := PaginatedResponse{
Data: users,
Page: page,
PageSize: pageSize,
TotalCount: totalCount,
TotalPages: totalPages,
}
w.Header().Set("Content-Type" , "application/json" )
json.NewEncoder(w).Encode(response)
}
Query Parameter Filtering:
type UserFilter struct {
Status string `json:"status"`
Role string `json:"role"`
CreatedAt string `json:"created_at"`
Search string `json:"search"`
}
func parseFilters (r *http.Request) UserFilter {
return UserFilter{
Status: r.URL.Query().Get("status" ),
Role: r.URL.Query().Get("role" ),
CreatedAt: r.URL.Query().Get("created_at" ),
Search: r.URL.Query().Get("search" ),
}
}
func listUsers (w http.ResponseWriter, r *http.Request) {
filters := parseFilters(r)
users := db.GetUsersWithFilters(filters)
w.Header().Set("Content-Type" , "application/json" )
json.NewEncoder(w).Encode(users)
}
HTTP Client Patterns Production-Ready HTTP Client:
import (
"context"
"net/http"
"time"
)
func NewHTTPClient () *http.Client {
return &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 100 ,
MaxIdleConnsPerHost: 10 ,
IdleConnTimeout: 90 * time.Second,
DisableKeepAlives: false ,
},
}
}
func fetchUser (ctx context.Context, userID string ) (*User, error ) {
client := NewHTTPClient()
req, err := http.NewRequestWithContext(
ctx,
"GET" ,
fmt.Sprintf("https://api.example.com/users/%s" , userID),
nil ,
)
if err != nil {
return nil , fmt.Errorf("create request: %w" , err)
}
req.Header.Set("Accept" , "application/json" )
req.Header.Set("Authorization" , "Bearer " +getToken())
resp, err := client.Do(req)
if err != nil {
return nil , fmt.Errorf("execute request: %w" , err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil , fmt.Errorf("unexpected status: %d" , resp.StatusCode)
}
var user User
if err := json.NewDecoder(resp.Body).Decode(&user); err != nil {
return nil , fmt.Errorf("decode response: %w" , err)
}
return &user, nil
}
Retry Logic with Exponential Backoff:
import (
"context"
"math"
"time"
)
type RetryConfig struct {
MaxRetries int
BaseDelay time.Duration
MaxDelay time.Duration
}
func DoWithRetry (ctx context.Context, cfg RetryConfig, fn func () error ) error {
var err error
for attempt := 0 ; attempt <= cfg.MaxRetries; attempt++ {
err = fn()
if err == nil {
return nil
}
if attempt < cfg.MaxRetries {
delay := time.Duration(math.Pow(2 , float64 (attempt))) * cfg.BaseDelay
if delay > cfg.MaxDelay {
delay = cfg.MaxDelay
}
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(delay):
}
}
}
return fmt.Errorf("max retries exceeded: %w" , err)
}
err := DoWithRetry(ctx, RetryConfig{
MaxRetries: 3 ,
BaseDelay: 100 * time.Millisecond,
MaxDelay: 2 * time.Second,
}, func () error {
return makeAPIRequest()
})
Testing HTTP Handlers import (
"net/http"
"net/http/httptest"
"testing"
)
func TestGetUser (t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(getUserHandler))
defer ts.Close()
resp, err := http.Get(ts.URL + "/users/123" )
if err != nil {
t.Fatal(err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Errorf("expected status 200, got %d" , resp.StatusCode)
}
var user User
if err := json.NewDecoder(resp.Body).Decode(&user); err != nil {
t.Fatal(err)
}
if user.ID != "123" {
t.Errorf("expected user ID 123, got %s" , user.ID)
}
}
func TestAuthMiddleware (t *testing.T) {
handler := http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) {
userID := r.Context().Value("userID" )
if userID == nil {
t.Error("userID not found in context" )
}
w.WriteHeader(http.StatusOK)
})
wrapped := AuthMiddleware(handler)
tests := []struct {
name string
token string
wantStatus int
}{
{"Valid token" , "valid-token-123" , http.StatusOK},
{"Missing token" , "" , http.StatusUnauthorized},
{"Invalid token" , "invalid" , http.StatusUnauthorized},
}
for _, tt := range tests {
t.Run(tt.name, func (t *testing.T) {
req := httptest.NewRequest("GET" , "/test" , nil )
if tt.token != "" {
req.Header.Set("Authorization" , tt.token)
}
rr := httptest.NewRecorder()
wrapped.ServeHTTP(rr, req)
if rr.Code != tt.wantStatus {
t.Errorf("expected status %d, got %d" , tt.wantStatus, rr.Code)
}
})
}
}
Performance Optimization import (
"compress/gzip"
"io"
"net/http"
"strings"
)
type gzipResponseWriter struct {
io.Writer
http.ResponseWriter
}
func (w gzipResponseWriter) Write(b []byte ) (int , error ) {
return w.Writer.Write(b)
}
func GzipMiddleware (next http.Handler) http.Handler {
return http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) {
if !strings.Contains(r.Header.Get("Accept-Encoding" ), "gzip" ) {
next.ServeHTTP(w, r)
return
}
w.Header().Set("Content-Encoding" , "gzip" )
gz := gzip.NewWriter(w)
defer gz.Close()
gzw := gzipResponseWriter{Writer: gz, ResponseWriter: w}
next.ServeHTTP(gzw, r)
})
}
Connection Pooling Configuration:
import (
"net"
"net/http"
"time"
)
func NewProductionHTTPClient () *http.Client {
return &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
ForceAttemptHTTP2: true ,
MaxIdleConns: 100 ,
MaxIdleConnsPerHost: 10 ,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
},
}
}
Decision Tree Building HTTP API in Go?
│
├─ Simple API, few dependencies? → net/http (stdlib)
│ ├─ Go 1.22+? → Use new ServeMux pattern routing
│ └─ Go < 1.22? → Consider Chi for better routing
│
├─ Need stdlib compatibility + better ergonomics? → Chi
│ └─ Great for: Middleware chains, route grouping
│
├─ Maximum performance priority? → Gin
│ └─ Great for: JSON APIs, high throughput services
│
├─ Enterprise app with OpenAPI? → Echo
│ └─ Great for: Type safety, comprehensive middleware
│
└─ Team knows Express.js + need WebSockets? → Fiber
└─ Note: Uses fasthttp, not stdlib-compatible
Common Pitfalls Pitfall 1: Not Closing Response Bodies
resp, _ := http.Get(url)
body, _ := io.ReadAll(resp.Body)
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
Pitfall 2: Not Using Context for Timeouts
resp, _ := http.Get(url)
ctx, cancel := context.WithTimeout(context.Background(), 5 *time.Second)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, "GET" , url, nil )
resp, err := client.Do(req)
Pitfall 3: Ignoring HTTP Status Codes
resp, _ := http.Get(url)
defer resp.Body.Close()
json.NewDecoder(resp.Body).Decode(&result)
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("unexpected status: %d" , resp.StatusCode)
}
Pitfall 4: Not Reusing HTTP Clients
func makeRequest () {
client := &http.Client{}
resp, _ := client.Get(url)
}
var httpClient = &http.Client{
Timeout: 30 * time.Second,
}
func makeRequest () {
resp, _ := httpClient.Get(url)
}
Go Idiomatic Quality Rules Small, high-frequency Go idioms worth enforcing in handler/service code:
Use := for locals with an initial value — reserve var for zero values and
package-level declarations.
Don't name an unused method receiver — func (*Server) Foo() makes it clear the
receiver is irrelevant.
Initialize struct pointers with &T{}, not new(T) — consistent with composite
literals and lets you set fields inline.
Handle (don't discard) returned errors — a dropped error from Decode/Write/a
repository call turns a failure into a silent success.
See go-idioms-quality.md for non-idiomatic vs
idiomatic examples and how to test/lint each. Most are enforced by gofmt -s,
staticcheck, errcheck, and revive under golangci-lint.
Derived from CAST Highlight Go-tagged code-quality indicators
(https://doc.casthighlight.com/ ), which reference Effective Go and the Go Code Review
Comments wiki as primary sources.
Related Skills
golang-testing-strategies : Testing HTTP handlers and middleware
golang-database-patterns : Integrating databases with HTTP APIs
toolchains-typescript-frameworks-nodejs-backend : Comparison with Node.js patterns
References