An HTTP layer translates requests into domain operations and responses. In a Go REST service, handlers remain read-only by depending on the narrow domain.ArticleReader interface rather than the full storage interface. section 11.3.2
A practical HTTP layer:
- Stores its domain dependency in a small Handlers type. section 11.3.2
- Registers routes on an http.ServeMux and rejects unsupported methods. section 11.3.2
- Reads query parameters, invokes domain reads, and serves API data. section 11.3.2
- Keeps handlers in an internal package while reusing storage from a shared module. section 11.3.2
Articles API
Construct a BoltStore, inject it into handlers.New, register the handlers on a ServeMux, and start the server on :8080. The storage implementation satisfies ArticleReader through its broader Storage interface. section 11.3.2
Listing 11.4 HTTP handlers with an injected ArticleReader
package handlers
import (
"encoding/json"
"net/http"
"strconv"
"github.com/YOUR_USERNAME/go-news/domain"
)
type Handlers struct { #1
articles domain.ArticleReader
}
func New(articles domain.ArticleReader) *Handlers { #2
return &Handlers{
articles: articles,
}
}
func (h *Handlers) RegisterRoutes(mux *http.ServeMux) { #3
mux.HandleFunc("/articles", h.articlesHandler)
}
func (h *Handlers) articlesHandler(w http.ResponseWriter, r *http.Request) { #4
if r.Method != http.MethodGet {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
n := 10
if countStr := r.URL.Query().Get("count"); countStr != "" { #5
if count, err := strconv.Atoi(countStr); err == nil && count > 0 {
n = count
}
}
articles := h.articles.GetRecent(n)
w.Header().Set("Content-Type", "application/json") #6
if err := json.NewEncoder(w).Encode(articles); err != nil {
http.Error(w, "failed to encode response", http.StatusInternalServerError)
return
}
}
Browse the handler implementation showing ArticleReader injection, route registration, GET validation, and count-query handling. section 11.3.2
