chi

$npx mdskill add TerminalSkills/skills/chi

Build lightweight Go HTTP services with Chi's idiomatic routing and middleware stack

  • Helps developers create composable HTTP services with route groups and URL parameters
  • Uses Chi router, Go's net/http, and middleware like logging and CORS
  • Analyzes routing needs and applies context-based scoping and sub-routers
  • Delivers clean, idiomatic Go code with Express-like ergonomics and stdlib compatibility
SKILL.md
.github/skills/chiView on GitHub ↗
---
name: chi
description: >-
  You are an expert in Chi, the lightweight, idiomatic Go HTTP router built
  on `net/http`. You help developers build composable HTTP services using
  Chi's middleware stack, route groups, URL parameters, sub-routers, and
  context-based request scoping — providing Express-like ergonomics while
  staying 100% compatible with Go's standard library.
license: Apache-2.0
compatibility: ''
metadata:
  author: terminal-skills
  version: 1.0.0
  category: Backend Development
  tags:
    - go
    - router
    - http
    - middleware
    - lightweight
    - stdlib-compatible
---

# Chi — Lightweight Go HTTP Router

You are an expert in Chi, the lightweight, idiomatic Go HTTP router built on `net/http`. You help developers build composable HTTP services using Chi's middleware stack, route groups, URL parameters, sub-routers, and context-based request scoping — providing Express-like ergonomics while staying 100% compatible with Go's standard library.

## Core Capabilities

### Router and Routes

```go
package main

import (
    "encoding/json"
    "net/http"
    "github.com/go-chi/chi/v5"
    "github.com/go-chi/chi/v5/middleware"
    "github.com/go-chi/cors"
)

func main() {
    r := chi.NewRouter()

    // Built-in middleware
    r.Use(middleware.Logger)
    r.Use(middleware.Recoverer)
    r.Use(middleware.RequestID)
    r.Use(middleware.RealIP)
    r.Use(middleware.Timeout(30 * time.Second))
    r.Use(cors.Handler(cors.Options{
        AllowedOrigins: []string{"https://app.example.com"},
        AllowedMethods: []string{"GET", "POST", "PUT", "DELETE"},
    }))

    // Public routes
    r.Get("/health", func(w http.ResponseWriter, r *http.Request) {
        json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
    })

    // Protected routes
    r.Route("/api", func(r chi.Router) {
        r.Use(authMiddleware)

        r.Route("/users", func(r chi.Router) {
            r.Get("/", listUsers)
            r.Post("/", createUser)

            r.Route("/{userID}", func(r chi.Router) {
                r.Use(userCtx)            // Load user into context
                r.Get("/", getUser)
                r.Put("/", updateUser)
                r.Delete("/", deleteUser)
                r.Get("/posts", getUserPosts)
            })
        })
    })

    http.ListenAndServe(":3000", r)
}

// Context middleware — load resource once, use in all sub-routes
func userCtx(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        userID := chi.URLParam(r, "userID")
        user, err := db.FindUser(userID)
        if err != nil {
            http.Error(w, "user not found", 404)
            return
        }
        ctx := context.WithValue(r.Context(), "user", user)
        next.ServeHTTP(w, r.WithContext(ctx))
    })
}

func getUser(w http.ResponseWriter, r *http.Request) {
    user := r.Context().Value("user").(*User)
    json.NewEncoder(w).Encode(user)
}

func listUsers(w http.ResponseWriter, r *http.Request) {
    page := r.URL.Query().Get("page")
    users, _ := db.ListUsers(page)
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(users)
}
```

## Installation

```bash
go get -u github.com/go-chi/chi/v5
```

## Best Practices

1. **stdlib compatible** — Chi handlers are `http.HandlerFunc`; use any `net/http` middleware without adapters
2. **Route groups** — Use `r.Route("/prefix", func(r chi.Router) {...})` for scoped middleware and routes
3. **Context middleware** — Load resources in middleware, share via `context.WithValue`; DRY across sub-routes
4. **URL params** — Use `chi.URLParam(r, "id")` to extract route parameters; type-safe, explicit
5. **Middleware ordering** — Logger first, Recoverer second; auth before route-specific middleware
6. **Sub-routers** — Mount independent routers: `r.Mount("/admin", adminRouter())`; clean separation
7. **Timeouts** — Use `middleware.Timeout` to prevent slow handlers from blocking; returns 504 on timeout
8. **No magic** — Chi doesn't do dependency injection or auto-binding; explicit is better than implicit in Go
More from TerminalSkills/skills