Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
The English summary is being prepared. Showing the original description.
Use when adding or changing a Go HTTP endpoint — Fiber v2 or v3 (detect which), thin handlers, central error mapping, boundary validation; the same rules apply to net/http, chi, echo or gin
The English summary is being prepared. Showing the original description.
See how to installReview the instructions the agent will receive before you install.
A handler is a translator: HTTP in → service call → HTTP out. Business logic never lives there. The recurring defects are fat handlers, per-handler error mapping that drifts, endpoints that quietly drop the auth middleware their neighbors have, and copying a value Fiber is about to reuse.
Core principle: handlers parse, validate, delegate, and map. Nothing else.
grep -E 'gofiber/fiber/v[23]|go-chi/chi|labstack/echo|gin-gonic/gin' go.mod
Never change the router or the Fiber major version in a feature task; a repo on Fiber v2 stays v2 (security-fix branch only). A brand-new repo with no router yet gets Fiber v3 (needs Go ≥1.25) unless the task says otherwise.
| v2 | v3 | |
|---|---|---|
| Handler signature | func(c *fiber.Ctx) error | func(c fiber.Ctx) error |
| Body | c.BodyParser(&req) | c.Bind().Body(&req) |
| Query / params | c.QueryParser / c.ParamsParser | c.Bind().Query / c.Bind().URI |
| Struct tag for path params | params: | uri: |
| Typed query helper | c.QueryInt("limit", 20) | fiber.Query[int](c, "limit", 20) |
| Go-standard request context | c.UserContext() | c.Context() |
| Raw fasthttp context | c.Context() (returns *fasthttp.RequestCtx) | c.RequestCtx() |
| Request id from context | c.Locals("requestid") | requestid.FromContext(c) |
| Static files / sub-app mount | app.Static(...) / app.Mount(...) | static.New(...) / app.Use(...) |
fiber migrate --to v3 exists for a dedicated upgrade task; never fold a framework-major bump into a feature task.
The v2 bug this corrects: on Fiber v2, c.Context() returns the pooled *fasthttp.RequestCtx, not the request-scoped context.Context — passing it where a context.Context is expected either fails to compile or silently drops whatever middleware put into the real context (auth claims, request id, trace span). Use c.UserContext() on v2.
map[string]any.go-playground/validator v10 if the repo already uses it; v3 has a StructValidator hook). Reject early with 4xx and a field-specific message in the repo's one error shape (see api-design-conventions).ErrorHandler / mapper), not per handler, so the mapping can't drift. Show it mapping errors.Is/errors.As against domain sentinel errors to status + the error body.c.Params/c.Query/c.Body/c.Get are only valid for the lifetime of the handler call — Fiber reuses the underlying buffer across requests. strings.Clone (or otherwise copy) anything you store in a struct that outlives the request, send to a goroutine, or put in a cache, unless the app is configured with Immutable: true.fiber.Config{BodyLimit: ...} (v2/v3 default 4 MB) or http.MaxBytesReader on net/http — don't rely on the default alone for upload endpoints.mux.HandleFunc("POST /tasks/{id}/children", h.CreateChild)
id := r.PathValue("id")
r.Body = http.MaxBytesReader(w, r.Body, maxBody)
func (h *TaskHandler) Create(c fiber.Ctx) error {
var req createTaskRequest
if err := c.Bind().Body(&req); err != nil {
return fiber.NewError(fiber.StatusBadRequest, "invalid body")
}
if err := req.validate(); err != nil {
return fiber.NewError(fiber.StatusBadRequest, err.Error())
}
task, err := h.svc.Create(c.Context(), req.Title)
if err != nil {
return err
}
return c.Status(fiber.StatusCreated).JSON(taskResponseFrom(task))
}
The title-length rule lives in the service/domain, not the handler. The central error middleware maps domain.ErrInvalidTitle → 400, domain.ErrConflict → 409 — every handler benefits.
req := httptest.NewRequest(http.MethodPost, "/tasks", strings.NewReader(body))
req.Header.Set("Content-Type", "application/json")
resp, err := app.Test(req) // v2: app.Test(req, -1)
// v3: app.Test(req, fiber.TestConfig{Timeout: 0})
Assert status code and decoded body — this is still a unit test; it does not replace running the real service once (backend-runtime-check).
map[string]any request/response instead of DTOs.c.Params/c.Query/c.Body past the handler without copying it first.c.Context() where the request's context.Context is needed.pgx/repository calls inside a handler.c.Body()/c.Params().No reviews yet. Tell others what you thought.
No login needed. Share how it worked for you, ask a question, or note where it did not run.
No comments yet. Be the first to write one.
Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
The English summary is being prepared. Showing the original description.
Use when the diff adds or changes an endpoint, resolver, RPC, job or query that takes an object id, a role check, a request binding or a tenant filter - BOLA/IDOR, function-level authorization, mass assignment and tenant scoping
The English summary is being prepared. Showing the original description.
Use on every UI change - semantic HTML, labels for controls, keyboard-navigable dialogs/menus, visible focus, and never color as the only signal
The English summary is being prepared. Showing the original description.
Use when a task changes any screen, form, dialog, menu or control - Lighthouse/axe scan of the changed screens, a keyboard walk, and the thresholds that fail a task
The English summary is being prepared. Showing the original description.
How to work a task returned with review, QA or UAT findings. Use when a task is in need_revision or PR review comments are in your context.
The English summary is being prepared. Showing the original description.
Use when the repository keeps its alerting in code, or a person asks for alerts outside TaskTrooper - PrometheusRule YAML, a Cloud Monitoring alert policy in Terraform, a Datadog monitor, each routed to TaskTrooper's alert ingest URL so it opens an incident here
The English summary is being prepared. Showing the original description.