Extract shared service layer for sandbox, API key, and template operations
Moves business logic from API handlers into internal/service/ so that both the REST API and the upcoming dashboard can share the same operations without duplicating code. API handlers now delegate to the service layer and only handle HTTP-specific concerns (request parsing, response formatting).
This commit is contained in:
@ -3,10 +3,12 @@ package api
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
@ -68,6 +70,30 @@ func decodeJSON(r *http.Request, v any) error {
|
||||
return json.NewDecoder(r.Body).Decode(v)
|
||||
}
|
||||
|
||||
// serviceErrToHTTP maps a service-layer error to an HTTP status, code, and message.
|
||||
// It inspects the underlying Connect RPC error if present, otherwise returns 500.
|
||||
func serviceErrToHTTP(err error) (int, string, string) {
|
||||
msg := err.Error()
|
||||
|
||||
// Check for Connect RPC errors wrapped by the service layer.
|
||||
var connectErr *connect.Error
|
||||
if errors.As(err, &connectErr) {
|
||||
return agentErrToHTTP(connectErr)
|
||||
}
|
||||
|
||||
// Map well-known service error patterns.
|
||||
switch {
|
||||
case strings.Contains(msg, "not found"):
|
||||
return http.StatusNotFound, "not_found", msg
|
||||
case strings.Contains(msg, "not running"), strings.Contains(msg, "not paused"):
|
||||
return http.StatusConflict, "invalid_state", msg
|
||||
case strings.Contains(msg, "invalid"):
|
||||
return http.StatusBadRequest, "invalid_request", msg
|
||||
default:
|
||||
return http.StatusInternalServerError, "internal_error", msg
|
||||
}
|
||||
}
|
||||
|
||||
type statusWriter struct {
|
||||
http.ResponseWriter
|
||||
status int
|
||||
|
||||
Reference in New Issue
Block a user