summaryrefslogtreecommitdiff
path: root/handler.go
diff options
context:
space:
mode:
authorAlexander Neonxp Kiryukhin <i@neonxp.ru>2024-09-17 01:19:25 +0300
committerAlexander Neonxp Kiryukhin <i@neonxp.ru>2024-09-17 01:19:25 +0300
commita054f480adf26e90ddcb66408688486704ab7094 (patch)
tree4600b6e7633979e1a4b94cfcaeb7ddf156733575 /handler.go
parent5094ebf213243023c6325310b3f710a0974025dd (diff)
simple handlerv0.0.2
Diffstat (limited to 'handler.go')
-rw-r--r--handler.go91
1 files changed, 91 insertions, 0 deletions
diff --git a/handler.go b/handler.go
new file mode 100644
index 0000000..c7f9b66
--- /dev/null
+++ b/handler.go
@@ -0,0 +1,91 @@
+package mux
+
+import (
+ "context"
+ "encoding/json"
+ "net/http"
+
+ "go.neonxp.ru/mux/ctxlib"
+)
+
+// Handler API handler and returns standard http.HandlerFunc function
+func Handler[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)
+ ctx := r.Context()
+ ctx = context.WithValue(ctx, ctxlib.Request, r)
+ ctx = context.WithValue(ctx, ctxlib.Method, r.Method)
+ ctx = context.WithValue(ctx, ctxlib.Headers, r.Header)
+
+ switch r.Method {
+ case http.MethodPost, http.MethodPatch, http.MethodDelete, http.MethodPut:
+ if err := Bind(r, req); err != nil {
+ w.WriteHeader(http.StatusBadRequest)
+ _, _ = w.Write([]byte(err.Error()))
+ return
+ }
+ }
+ resp, err := handler(ctx, 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 {
+ err = v.Render(ctx, w)
+ return
+ }
+
+ 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)
+
+ }
+}
+
+type NilRequest struct{}
+
+// WithContentType returns custom content type for response
+type WithContentType interface {
+ ContentType() string
+}
+
+// WithHTTPStatus returns custom status code
+type WithHTTPStatus interface {
+ Status() int
+}
+
+type RedirectResponse struct {
+ Code int
+ Location string
+}
+
+func (rr *RedirectResponse) Render(ctx context.Context, w http.ResponseWriter) error {
+ w.Header().Add("Location", rr.Location)
+ w.WriteHeader(rr.Code)
+ return nil
+}
+
+func Redirect(code int, location string) *RedirectResponse {
+ return &RedirectResponse{
+ Code: code,
+ Location: location,
+ }
+}