summaryrefslogtreecommitdiff
path: root/wrap.go
diff options
context:
space:
mode:
authorAlexander <a.kiryukhin@vk.team>2024-06-11 14:12:30 +0300
committerAlexander <a.kiryukhin@vk.team>2024-06-11 14:12:30 +0300
commit88a6b1cb628e4e334068e861ac5fb56274d88845 (patch)
tree312f2a3a7182b6e2fc45e87ec71ddde9861c77f8 /wrap.go
InitialHEADmaster
Diffstat (limited to 'wrap.go')
-rw-r--r--wrap.go93
1 files changed, 93 insertions, 0 deletions
diff --git a/wrap.go b/wrap.go
new file mode 100644
index 0000000..e8ae72b
--- /dev/null
+++ b/wrap.go
@@ -0,0 +1,93 @@
+package muxtool
+
+import (
+ "context"
+ "encoding/json"
+ "net/http"
+)
+
+// Wrap API handler and returns standard http.HandlerFunc function
+func Wrap[RQ any, RS any](handler func(ctx context.Context, request *RQ) (RS, error)) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ req := new(RQ)
+ richifyRequest(req, r)
+ switch r.Method {
+ case http.MethodPost, http.MethodPatch, http.MethodDelete, http.MethodPut:
+ if err := json.NewDecoder(r.Body).Decode(req); err != nil {
+ w.WriteHeader(http.StatusBadRequest)
+ _, _ = w.Write([]byte(err.Error()))
+ return
+ }
+ }
+ resp, err := handler(r.Context(), req)
+ if err != nil {
+ w.WriteHeader(http.StatusInternalServerError)
+ _, _ = w.Write([]byte(err.Error()))
+ return
+ }
+
+ statusCode := http.StatusOK
+ contentType := "application/json"
+ var body []byte
+
+ if v, ok := (any)(resp).(WithContentType); ok {
+ contentType = v.ContentType()
+ }
+ if v, ok := (any)(resp).(WithHTTPStatus); ok {
+ statusCode = v.Status()
+ }
+ if v, ok := (any)(resp).(Renderer); ok {
+ body, err = v.Render()
+ } else {
+ body, err = json.Marshal(resp)
+ }
+ if err != nil {
+ w.WriteHeader(http.StatusInternalServerError)
+ _, _ = w.Write([]byte(err.Error()))
+ return
+ }
+ w.WriteHeader(statusCode)
+ w.Header().Set("Content-Type", contentType)
+ w.Write(body)
+ }
+}
+
+func richifyRequest[RQ any](req *RQ, baseRequest *http.Request) {
+ if v, ok := (any)(req).(WithHeader); ok {
+ v.WithHeader(baseRequest.Header)
+ }
+ if v, ok := (any)(req).(WithMethod); ok {
+ v.WithMethod(baseRequest.Method)
+ }
+}
+
+type NilRequest struct{}
+
+// Optional interfaces for request type
+
+// WithHeader sets headers to request
+type WithHeader interface {
+ WithHeader(header http.Header)
+}
+
+// WithMethod sets method to request
+type WithMethod interface {
+ WithMethod(method string)
+}
+
+// Optional interfaces for response type
+
+// Renderer renders response to byte slice
+type Renderer interface {
+ Render() ([]byte, error)
+}
+
+// WithContentType returns custom content type for response
+type WithContentType interface {
+ ContentType() string
+}
+
+// WithHTTPStatus returns custom status code
+type WithHTTPStatus interface {
+ Status() int
+}