smithery/pluginagentmarketplace

go-web-apis

Build production REST APIs with Go - handlers, middleware, security

Installation

$ npx skills add smithery/pluginagentmarketplace --skill go-web-apis

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery/pluginagentmarketplace · top by installs.

npx skills add smithery/pluginagentmarketplace

Browse all from smithery/pluginagentmarketplace

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Also listed on

Alternate registries and mirrors of this skill.

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 5,584 B
  • docs SUMMARY.md 86 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

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")