go-web-apis

📁 pluginagentmarketplace/custom-plugin-go 📅 14 days ago
2
总安装量
2
周安装量
#66303
全站排名
安装命令
npx skills add https://github.com/pluginagentmarketplace/custom-plugin-go --skill go-web-apis

Agent 安装分布

amp 2
gemini-cli 2
claude-code 2
github-copilot 2
codex 2
kimi-cli 2

Skill 文档

Go Web APIs Skill

Build production-ready REST APIs with Go’s net/http and popular frameworks.

Overview

Complete guide for building secure, performant web APIs including routing, middleware, authentication, and best practices.

Parameters

Parameter Type Required Default Description
framework string no “stdlib” Framework: “stdlib”, “gin”, “echo”, “chi”
auth_type string no “jwt” Auth method: “jwt”, “api-key”, “oauth”
include_openapi bool no false Generate OpenAPI spec

Core Topics

HTTP Handler Pattern

type Server struct {
    db     *sql.DB
    logger *slog.Logger
}

func (s *Server) handleGetUser() http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        id := chi.URLParam(r, "id")

        user, err := s.db.GetUser(r.Context(), id)
        if err != nil {
            if errors.Is(err, sql.ErrNoRows) {
                http.Error(w, "user not found", http.StatusNotFound)
                return
            }
            s.logger.Error("get user", "error", err)
            http.Error(w, "internal error", http.StatusInternalServerError)
            return
        }

        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(user)
    }
}

Middleware

func LoggingMiddleware(logger *slog.Logger) func(http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            start := time.Now()
            ww := &responseWriter{ResponseWriter: w, status: 200}

            defer func() {
                logger.Info("request",
                    "method", r.Method,
                    "path", r.URL.Path,
                    "status", ww.status,
                    "duration", time.Since(start),
                )
            }()

            next.ServeHTTP(ww, r)
        })
    }
}

func RecoveryMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        defer func() {
            if err := recover(); err != nil {
                http.Error(w, "internal error", http.StatusInternalServerError)
            }
        }()
        next.ServeHTTP(w, r)
    })
}

JWT Authentication

func JWTMiddleware(secret []byte) func(http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            auth := r.Header.Get("Authorization")
            if !strings.HasPrefix(auth, "Bearer ") {
                http.Error(w, "unauthorized", http.StatusUnauthorized)
                return
            }

            token, err := jwt.Parse(strings.TrimPrefix(auth, "Bearer "), func(t *jwt.Token) (interface{}, error) {
                return secret, nil
            })
            if err != nil || !token.Valid {
                http.Error(w, "invalid token", http.StatusUnauthorized)
                return
            }

            claims := token.Claims.(jwt.MapClaims)
            ctx := context.WithValue(r.Context(), "user_id", claims["sub"])
            next.ServeHTTP(w, r.WithContext(ctx))
        })
    }
}

Request Validation

type CreateUserRequest struct {
    Name  string `json:"name" validate:"required,min=2,max=100"`
    Email string `json:"email" validate:"required,email"`
    Age   int    `json:"age" validate:"gte=0,lte=130"`
}

func (s *Server) handleCreateUser() http.HandlerFunc {
    validate := validator.New()

    return func(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 := validate.Struct(req); err != nil {
            http.Error(w, err.Error(), http.StatusBadRequest)
            return
        }

        // process valid request
    }
}

Retry Logic

type HTTPClient struct {
    client  *http.Client
    backoff []time.Duration
}

func (c *HTTPClient) Do(req *http.Request) (*http.Response, error) {
    var resp *http.Response
    var err error

    for i, delay := range c.backoff {
        resp, err = c.client.Do(req)
        if err == nil && resp.StatusCode < 500 {
            return resp, nil
        }
        if i < len(c.backoff)-1 {
            time.Sleep(delay)
        }
    }
    return resp, err
}

Unit Test Template

func TestHandleGetUser(t *testing.T) {
    srv := &Server{db: mockDB, logger: slog.Default()}

    req := httptest.NewRequest("GET", "/users/123", nil)
    w := httptest.NewRecorder()

    srv.handleGetUser().ServeHTTP(w, req)

    if w.Code != http.StatusOK {
        t.Errorf("got status %d, want %d", w.Code, http.StatusOK)
    }

    var user User
    json.NewDecoder(w.Body).Decode(&user)
    if user.ID != 123 {
        t.Errorf("got id %d, want 123", user.ID)
    }
}

Troubleshooting

Failure Modes

Symptom Cause Fix
5xx spike Handler panic Add recovery middleware
Slow responses Missing timeouts Configure server timeouts
Memory leak Unclosed body Always defer resp.Body.Close()

Usage

Skill("go-web-apis")