Weekly Library | Chi: π¦ An Elegant HTTP Router Library for Go
When building web services and APIs, an excellent routing library can greatly enhance development efficiency. Chi, with its lightweight design and powerful features, has become a highly regarded HTTP routing solution in the Go language ecosystem.
π‘ Understanding Chi
Chi is a lightweight routing library built on the standard library <span>net/http</span>, created by Peter Kieltyka, the technical lead at Pressly. It adheres to Go’s design philosophy of simplicity and efficiency, having garnered over 14,000 stars on GitHub, making it one of the most popular HTTP routing libraries in the Go ecosystem.
β¨ Core Features
β
Fully compatible with the standard library: Seamless integration with <span>net/http</span>, no need to learn new conceptsβ
No external dependencies: Does not rely on any packages other than the Go standard libraryβ
Highly expressive routing: Supports route groups, path parameters, and wildcardsβ
Elegant middleware system: Global, group, and single-route level middlewareβ
Context control: Pass request values through the standard <span>context.Context</span>β
Modular design: Components can be used individually or flexibly combinedβ
High performance: Performance close to native <span>net/http</span>‘s performance
π Quick Start
π¦ Installing Chi
// Install Chi using Go modules
go get -u github.com/go-chi/chi/v5
π° Basic Example
package main
import (
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
func main() {
// Create a router
r := chi.NewRouter()
// Global middleware
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
// Basic route
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Welcome to the Chi example!"))
})
// Route with parameters
r.Get("/hello/{name}", func(w http.ResponseWriter, r *http.Request) {
name := chi.URLParam(r, "name")
w.Write([]byte("Hello, " + name + "!"))
})
// Start the server
http.ListenAndServe(":3000", r)
}
π Routing System Explained
π§© Routing Methods
Chi provides a simple API for all HTTP methods:
// Handler functions for HTTP methods
r.Get("/users", listUsers) // GET request
r.Post("/users", createUser) // POST request
r.Put("/users/{id}", updateUser) // PUT request
r.Delete("/users/{id}", deleteUser) // DELETE request
r.Patch("/users/{id}", patchUser) // PATCH request
π URL Parameters and Pattern Matching
Chi supports flexible route parameters and pattern matching:
// Simple parameters
r.Get("/users/{id}", getUser)
// Regex constrained parameters
r.Get("/articles/{year:[0-9]{4}}/{month:[0-9]{2}}", getArticlesByMonth)
// Wildcard matching
r.Get("/files/{filepath:*}", serveFiles)
ποΈ Route Organization and Nesting
Chi’s route grouping feature makes organizing large APIs clear:
// API versioning and resource grouping
r.Route("/api", func(r chi.Router) {
// V1 API
r.Route("/v1", func(r chi.Router) {
// User resources
r.Route("/users", func(r chi.Router) {
r.Get("/", listUsers) // GET /api/v1/users
r.Post("/", createUser) // POST /api/v1/users
// Single user operations
r.Route("/{id}", func(r chi.Router) {
r.Get("/", getUser) // GET /api/v1/users/123
r.Put("/", updateUser) // PUT /api/v1/users/123
r.Delete("/", deleteUser) // DELETE /api/v1/users/123
})
})
})
})
π Route Mounting
The modular design allows you to mount independent routers onto the main router:
// User router
func userRouter() http.Handler {
r := chi.NewRouter()
r.Get("/", listUsers)
r.Post("/", createUser)
// ...
return r
}
// Product router
func productRouter() http.Handler {
r := chi.NewRouter()
r.Get("/", listProducts)
// ...
return r
}
// Main router
r := chi.NewRouter()
r.Mount("/users", userRouter()) // Mounted at /users path
r.Mount("/products", productRouter()) // Mounted at /products path
π Middleware System
Middleware is a powerful feature of Chi, allowing you to execute code at various stages of request processing.
π Built-in Middleware
Chi provides various useful middleware:
r := chi.NewRouter()
// Request logging
r.Use(middleware.Logger)
// Recover from panic
r.Use(middleware.Recoverer)
// Request ID tracking
r.Use(middleware.RequestID)
// Request timeout control
r.Use(middleware.Timeout(30 * time.Second))
// Response compression
r.Use(middleware.Compress(5))
π οΈ Custom Middleware
Creating your own middleware is very simple:
// Authentication middleware example
func AuthMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
if !isValidToken(token) {
http.Error(w, "Unauthorized access", http.StatusUnauthorized)
return
}
// Continue processing the request
next.ServeHTTP(w, r)
})
}
// Using custom middleware
r.Use(AuthMiddleware)
π― Middleware Application Scope
Middleware can be applied at different levels:
// Global middleware
r.Use(middleware.Logger)
// Route group middleware
r.Route("/admin", func(r chi.Router) {
r.Use(adminOnly) // Only effective for /admin path
// ...
})
// Single route middleware
r.With(cacheControl).Get("/public", servePublicContent)
π RESTful API Practical Example
Here is a complete RESTful API example:
func main() {
r := chi.NewRouter()
// Basic middleware
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
// API routes
r.Route("/api/users", func(r chi.Router) {
r.Get("/", listUsers) // Get all users
r.Post("/", createUser) // Create user
r.Route("/{id}", func(r chi.Router) {
r.Get("/", getUser) // Get single user
r.Put("/", updateUser) // Update user
r.Delete("/", deleteUser) // Delete user
})
})
http.ListenAndServe(":3000", r)
}
// Handler function example
func listUsers(w http.ResponseWriter, r *http.Request) {
users := []User{
{ID: "1", Name: "Zhang San"},
{ID: "2", Name: "Li Si"},
}
respondJSON(w, http.StatusOK, users)
}
func getUser(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
// Fetch user from database
user := User{ID: id, Name: "Zhang San"}
respondJSON(w, http.StatusOK, user)
}
// Helper function
func respondJSON(w http.ResponseWriter, status int, data interface{}) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(data)
}
π Security Best Practices
Key points for building secure applications with Chi:
Security Headers Middleware
func securityHeaders(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Prevent clickjacking
w.Header().Set("X-Frame-Options", "DENY")
// Prevent MIME sniffing
w.Header().Set("X-Content-Type-Options", "nosniff")
// XSS protection
w.Header().Set("X-XSS-Protection", "1; mode=block")
next.ServeHTTP(w, r)
})
}
// Apply security headers
r.Use(securityHeaders)
π§ͺ Testing Chi Applications
Chi is fully compatible with Go’s testing tools, making it easy to write tests:
func TestGetUser(t *testing.T) {
// Create request
req := httptest.NewRequest("GET", "/users/123", nil)
w := httptest.NewRecorder()
// Set up routes
r := chi.NewRouter()
r.Get("/users/{id}", getUser)
// Handle request
r.ServeHTTP(w, req)
// Validate result
if w.Code != 200 {
t.Errorf("Expected status code 200, got %d", w.Code)
}
}
π Routing Framework Comparison
Comparison of Chi with other popular Go HTTP routing frameworks:
| Feature | Chi | Gin | Standard Library | Gorilla Mux |
| Compatibility with Standard Library | βββββ | βββ | βββββ | βββββ |
| Routing Features | βββββ | βββββ | ββ | βββββ |
| Performance | ββββ | βββββ | βββββ | βββ |
| Middleware Support | βββββ | βββββ | ββ | βββ |
| Usability | ββββ | βββββ | ββ | βββ |
| External Dependencies | βββββ | βββ | βββββ | ββββ |
| Community Support | ββββ | βββββ | βββββ | βββ |
π‘ Summary
Chi provides an elegant and powerful HTTP routing solution by cleverly balancing simplicity and functionality. Its design philosophy aligns with Go, emphasizing practicality, performance, and code readability.
Scenarios Where Chi is Particularly Suitable
- β’ Building RESTful APIs
- β’ Microservices architecture
- β’ Performance-sensitive web services
- β’ Projects that require tight integration with the standard library
Whether you are developing simple APIs or complex web applications, Chi provides the right abstractions and tools to help you build high-quality Go web services more efficiently.
Learning Resources:
- β’ Chi GitHub Repository
- β’ Chi Official Documentation
- β’ Chi Example Code
π€ Today’s Discussion: Which routing framework do you use in Go web development? What do you think are the pros and cons compared to Chi?
π₯ Join the Community: Reply with γJoin Groupγ to exchange learning experiences with thousands of Go developers and share practical insights!
π Follow γGopher Tribeγ for continuous updates on Go language technical content, with quality updates every week.