hatch-surf/internal/handler/handler.go
CTO 90c3f6285d feat: mock endpoint — configure response per endpoint
- Add mock_status, mock_headers, mock_body columns to endpoints schema
- Add MockConfig struct and UpsertMock to Repository interface
- Implement UpsertMock in sqliteRepo (INSERT ON CONFLICT UPDATE)
- Update GetEndpoint to return mock configuration when present
- Add PUT /e/{endpoint_id}/mock handler with JSON body {status, headers, body}
- Add catch-all /{endpoint_id} handler returning mock or default 200
- Header sanitization: only allow Content-Type, Cache-Control, X-*
- Wire handler into cmd/hatch main with SQLite store
- Fix Dockerfile: COPY go.sum for reproducible builds
- Tests: store mock CRUD, handler mock config + header sanitization

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-22 14:32:53 +02:00

45 lines
1.2 KiB
Go

package handler
import (
"context"
"encoding/json"
"io"
"log"
"net/http"
"strings"
"github.com/elfoundation/hatch/internal/store"
)
type Handler struct{ Repo store.Repository }
func New(repo store.Repository) *Handler { return &Handler{Repo: repo} }
func (h *Handler) RegisterRoutes(mux *http.ServeMux) { mux.Handle("/{endpoint}", h) }
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
eid := extractID(r.URL.Path)
ctx := context.Background()
if _, err := h.Repo.GetEndpoint(ctx, eid); err != nil {
h.Repo.CreateEndpoint(ctx, eid)
}
hdr := map[string]string{}
for k, v := range r.Header { hdr[k] = strings.Join(v, ", ") }
hdrJSON, _ := json.Marshal(hdr)
var body []byte
if r.Body != nil { body, _ = io.ReadAll(r.Body); r.Body.Close() }
h.Repo.AppendRequest(ctx, eid, &store.Request{
Method: r.Method, Path: r.URL.Path, Headers: string(hdrJSON),
Query: r.URL.RawQuery, Body: body,
})
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]interface{}{})
}
func extractID(p string) string {
t := strings.TrimLeft(p, "/")
if i := strings.Index(t, "/"); i >= 0 { return t[:i] }
return t
}