Go with the Flow: Navigating HTTP Services with chi
Streamline Your Web Development with Go's Lightweight, Idiomatic Router

full stack dev | SaaS | AI | maker - builder
In Go (Golang), chi is a lightweight, idiomatic and composable router for building HTTP services. It's designed to offer the power and flexibility of the standard library net/http package while providing a clean API for building complex applications with less code and more clarity.
Here are some of the key features and benefits of using chi:
Lightweight and Idiomatic:
chiis designed to be simple and straightforward, sticking closely to Go's standard library idioms. This makes it easy to learn and integrate into existing Go projects.Composability:
chiallows you to build middleware and routes in a highly composable way. You can define routes and middlewares in a tree-like structure, enabling modular and reusable code.Middleware Support:
chisupports middleware out-of-the-box, allowing you to add functionalities like logging, authentication, and request validation easily.Context Aware:
chiis built on top of Go's context package, enabling you to pass request-scoped values, deadlines, and cancellations across API boundaries and goroutines.Performance:
chiis designed with performance in mind, providing minimal overhead while offering powerful routing capabilities.
Example Usage
Here's a basic example of how to use chi to set up a simple web server:
package main
import (
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
func main() {
r := chi.NewRouter()
// Use some middleware
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
// Define routes
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Welcome to the home page!"))
})
r.Get("/hello", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, World!"))
})
// Start the server
http.ListenAndServe(":8080", r)
}
Setting Up Middleware
Middleware in chi can be applied globally to all routes or locally to specific routes or groups of routes. Here's an example:
// Applying middleware globally
r.Use(middleware.Logger)
// Applying middleware to specific routes
r.With(middleware.BasicAuth("myRealm", map[string]string{"user": "password"})).
Get("/secure", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("This is a secure endpoint"))
})
Nested Routes and Groups
You can also create nested routes and groups for better organization:
coder.Route("/admin", func(r chi.Router) {
r.Use(AdminOnly) // Apply middleware specific to this group
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Admin home"))
})
r.Get("/dashboard", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Admin dashboard"))
})
})
URL Parameters
chi allows you to define routes with parameters:
coder.Get("/user/{userID}", func(w http.ResponseWriter, r *http.Request) {
userID := chi.URLParam(r, "userID")
w.Write([]byte("User ID: " + userID))
})
Handling Subroutes
Subroutes can be defined to handle nested routing structures:
coder.Route("/api", func(r chi.Router) {
r.Get("/users", listUsers)
r.Get("/users/{userID}", getUser)
r.Post("/users", createUser)
})
Middleware Example
Here's an example of a custom middleware that logs the request duration:
codefunc requestDurationLogger(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
duration := time.Since(start)
log.Printf("Request %s took %v", r.URL.Path, duration)
})
}
// Applying the custom middleware
r.Use(requestDurationLogger)
Take-away
chi is a lightweight, idiomatic, and composable Go router for building HTTP services. It offers middleware support, context awareness, and high performance. Its simple API allows for modular and reusable code, making it a powerful choice for developing complex web applications efficiently.
Image attribution




