diff options
| author | Leonardo Bishop <me@leonardobishop.net> | 2025-09-09 22:44:09 +0100 |
|---|---|---|
| committer | Leonardo Bishop <me@leonardobishop.net> | 2025-09-09 22:44:09 +0100 |
| commit | f1741a7faa9538e9b12ac60e0fbf6c7721a36059 (patch) | |
| tree | 2b70b14fc20a8520718910a0cd2e0134790c6f53 /api/dto | |
Initial commit
Diffstat (limited to 'api/dto')
| -rw-r--r-- | api/dto/entry.go | 9 | ||||
| -rw-r--r-- | api/dto/response.go | 38 | ||||
| -rw-r--r-- | api/dto/util.go | 54 |
3 files changed, 101 insertions, 0 deletions
diff --git a/api/dto/entry.go b/api/dto/entry.go new file mode 100644 index 0000000..85e39f3 --- /dev/null +++ b/api/dto/entry.go @@ -0,0 +1,9 @@ +package dto + +type CreateEntryRequest struct { + Title string `json:"title"` + Kind string `json:"kind"` + Url string `json:"url"` + Description string `json:"description"` + Token string `json:"token"` +} diff --git a/api/dto/response.go b/api/dto/response.go new file mode 100644 index 0000000..2c13218 --- /dev/null +++ b/api/dto/response.go @@ -0,0 +1,38 @@ +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..651f026 --- /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, err error) { + if o, ok := err.(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", err) + } +} |
