aboutsummaryrefslogtreecommitdiffstats
path: root/api/dto
diff options
context:
space:
mode:
authorLeonardo Bishop <me@leonardobishop.com>2025-08-14 18:07:12 +0100
committerLeonardo Bishop <me@leonardobishop.com>2025-08-14 18:07:12 +0100
commit4697556cac819c47d068819b9fc9c3b4ea84e279 (patch)
treeb832d8fc6b643a8b9d0eeca35c1268e1649da731 /api/dto
parentdd49c9205bb04844b686b9c3396c40eb49d25826 (diff)
Merge confplanner-web and replace fiber with native net/http
Diffstat (limited to 'api/dto')
-rw-r--r--api/dto/response.go17
-rw-r--r--api/dto/util.go54
2 files changed, 71 insertions, 0 deletions
diff --git a/api/dto/response.go b/api/dto/response.go
index 43f98bd..2c13218 100644
--- a/api/dto/response.go
+++ b/api/dto/response.go
@@ -2,20 +2,37 @@ package dto
import "fmt"
+type Response interface {
+ Error() string
+ Status() int
+}
+
type OkResponse struct {
Code int `json:"code"`
Data interface{} `json:"data,omitempty"`
}
+var _ Response = (*OkResponse)(nil)
+
type ErrorResponse struct {
Code int `json:"code"`
Message string `json:"message"`
}
+var _ Response = (*ErrorResponse)(nil)
+
+func (r *OkResponse) Status() int {
+ return r.Code
+}
+
func (r *OkResponse) Error() string {
return fmt.Sprintf("HTTP status %d", r.Code)
}
+func (r *ErrorResponse) Status() int {
+ return r.Code
+}
+
func (r *ErrorResponse) Error() string {
return fmt.Sprintf("HTTP status %d: %s", r.Code, r.Message)
}
diff --git a/api/dto/util.go b/api/dto/util.go
new file mode 100644
index 0000000..cb3ea52
--- /dev/null
+++ b/api/dto/util.go
@@ -0,0 +1,54 @@
+package dto
+
+import (
+ "encoding/json"
+ "fmt"
+ "log/slog"
+ "net/http"
+
+ "github.com/go-playground/validator/v10"
+)
+
+var validate = validator.New(validator.WithRequiredStructEnabled())
+
+func ReadDto(r *http.Request, o interface{}) Response {
+ decoder := json.NewDecoder(r.Body)
+ if err := decoder.Decode(o); err != nil {
+ return &ErrorResponse{
+ Code: http.StatusBadRequest,
+ Message: fmt.Errorf("Invalid request (%w)", err).Error(),
+ }
+ }
+
+ if err := validate.Struct(o); err != nil {
+ return &ErrorResponse{
+ Code: http.StatusBadRequest,
+ Message: err.Error(),
+ }
+ }
+
+ return nil
+}
+
+func WrapResponseFunc(dtoFunc func(http.ResponseWriter, *http.Request) error) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ WriteDto(w, r, dtoFunc(w, r))
+ }
+}
+
+func WriteDto(w http.ResponseWriter, r *http.Request, o error) {
+ if o, ok := o.(Response); ok {
+ data, err := json.Marshal(o)
+ if err != nil {
+ w.WriteHeader(500)
+ slog.Error("could not serialise JSON", "error", err)
+ return
+ }
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(o.Status())
+ w.Write(data)
+ } else {
+ w.WriteHeader(500)
+ slog.Error("internal server error handling request", "error", o)
+ }
+}