refactor: extract API handlers into internal packages
Move HTTP handler logic out of main into internal api and server packages, slimming main to a thin entrypoint. Bundles bug fixes: login nil-panic, empty-password validation, chirp sort ordering, duplicate-email 409, and restricting the file server to the assets directory.
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
// Package api provides small HTTP helpers shared by the HTTP handlers.
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Error is an error that serializes to the shape {"error": message}.
|
||||
type Error struct {
|
||||
Err string `json:"error"`
|
||||
}
|
||||
|
||||
// Error returns the error message.
|
||||
func (e Error) Error() string { return e.Err }
|
||||
|
||||
// NewError returns an Error with the given message.
|
||||
func NewError(msg string) error { return Error{Err: msg} }
|
||||
|
||||
// WriteJSON writes a JSON response. A nil payload writes only the status code.
|
||||
func WriteJSON(w http.ResponseWriter, status int, payload any) {
|
||||
if payload == nil {
|
||||
w.WriteHeader(status)
|
||||
return
|
||||
}
|
||||
|
||||
data, err := json.Marshal(payload)
|
||||
|
||||
if err != nil {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
_, _ = w.Write([]byte(`{"error":"Failed to encode JSON response"}`))
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(status)
|
||||
_, _ = w.Write(data)
|
||||
}
|
||||
|
||||
// WriteError writes an error response with the given status code.
|
||||
func WriteError(w http.ResponseWriter, status int, msg string) {
|
||||
WriteJSON(w, status, Error{Err: msg})
|
||||
}
|
||||
|
||||
// DecodeJSON decodes a JSON request body into a new value of type T.
|
||||
func DecodeJSON[T any](r *http.Request) (*T, error) {
|
||||
defer r.Body.Close()
|
||||
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
var data *T
|
||||
|
||||
if err := decoder.Decode(&data); err != nil {
|
||||
return nil, NewError("Failed to deserialize request")
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
Reference in New Issue
Block a user