From b3c48f806724b82b649c89aa5e0d07a09e414140 Mon Sep 17 00:00:00 2001 From: Alexander Kiryukhin Date: Wed, 5 Jan 2022 21:21:51 +0300 Subject: Added interfaces --- _examples/headers/main.go | 53 +++++++++++++++++++++++++++++++++++++++++++++ _examples/headers/test.http | 24 ++++++++++++++++++++ _examples/simple/main.go | 35 ++++++++++++++++++++++++++++++ _examples/simple/test.http | 24 ++++++++++++++++++++ _examples/wrap/main.go | 35 ------------------------------ _examples/wrap/test.http | 12 ---------- handler.go | 31 -------------------------- wrap.go | 51 +++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 187 insertions(+), 78 deletions(-) create mode 100644 _examples/headers/main.go create mode 100644 _examples/headers/test.http create mode 100644 _examples/simple/main.go create mode 100644 _examples/simple/test.http delete mode 100644 _examples/wrap/main.go delete mode 100644 _examples/wrap/test.http delete mode 100644 handler.go create mode 100644 wrap.go diff --git a/_examples/headers/main.go b/_examples/headers/main.go new file mode 100644 index 0000000..d0ab968 --- /dev/null +++ b/_examples/headers/main.go @@ -0,0 +1,53 @@ +package main + +import ( + "context" + "fmt" + "log" + "net/http" + + "github.com/gogeneric/api" +) + +func main() { + h := &http.Server{Addr: "0.0.0.0:3000"} + mux := http.NewServeMux() + h.Handler = mux + + // Here is magic! + mux.Handle("/hello", api.Wrap(handleHello)) + + if err := h.ListenAndServe(); err != http.ErrServerClosed { + log.Fatalln(err) + } +} + +func handleHello(ctx context.Context, req *helloRequest) (*helloResponse, error) { + return &helloResponse{Message: fmt.Sprintf("Hello, %s!", req.Name)}, nil +} + +type helloRequest struct { + Name string `json:"name"` + User string +} + +// SetHeaders implements api.WithHeader interface +func (h *helloRequest) WithHeader(header http.Header) { + h.User = header.Get("user") +} + +type helloResponse struct { + Message string `json:"message"` +} + +func test[T IN](x T) { + +} + +type IN interface { + string | int | inter +} + +type inter interface { + String() string +} diff --git a/_examples/headers/test.http b/_examples/headers/test.http new file mode 100644 index 0000000..6efd342 --- /dev/null +++ b/_examples/headers/test.http @@ -0,0 +1,24 @@ +### Request JSON: +http://localhost:3000/hello +Content-Type: application/json + +{ + "name": "Alex" +} + +### Response: +# http://localhost:3000/hello +# +#{"message":"Hello, Alex!"} + +### Request Form: +http://localhost:3000/hello +Content-Type: application/x-www-form-urlencoded + +name=Alex + +### Response: +# http://localhost:3000/hello +# +#{"message":"Hello, Alex!"} + diff --git a/_examples/simple/main.go b/_examples/simple/main.go new file mode 100644 index 0000000..2248038 --- /dev/null +++ b/_examples/simple/main.go @@ -0,0 +1,35 @@ +package main + +import ( + "context" + "fmt" + "log" + "net/http" + + "github.com/gogeneric/api" +) + +func main() { + h := &http.Server{Addr: "0.0.0.0:3000"} + mux := http.NewServeMux() + h.Handler = mux + + // Here is magic! + mux.Handle("/hello", api.Wrap(handleHello)) + + if err := h.ListenAndServe(); err != http.ErrServerClosed { + log.Fatalln(err) + } +} + +func handleHello(ctx context.Context, req *helloRequest) (*helloResponse, error) { + return &helloResponse{Message: fmt.Sprintf("Hello, %s!", req.Name)}, nil +} + +type helloRequest struct { + Name string `json:"name"` +} + +type helloResponse struct { + Message string `json:"message"` +} diff --git a/_examples/simple/test.http b/_examples/simple/test.http new file mode 100644 index 0000000..6efd342 --- /dev/null +++ b/_examples/simple/test.http @@ -0,0 +1,24 @@ +### Request JSON: +http://localhost:3000/hello +Content-Type: application/json + +{ + "name": "Alex" +} + +### Response: +# http://localhost:3000/hello +# +#{"message":"Hello, Alex!"} + +### Request Form: +http://localhost:3000/hello +Content-Type: application/x-www-form-urlencoded + +name=Alex + +### Response: +# http://localhost:3000/hello +# +#{"message":"Hello, Alex!"} + diff --git a/_examples/wrap/main.go b/_examples/wrap/main.go deleted file mode 100644 index 2248038..0000000 --- a/_examples/wrap/main.go +++ /dev/null @@ -1,35 +0,0 @@ -package main - -import ( - "context" - "fmt" - "log" - "net/http" - - "github.com/gogeneric/api" -) - -func main() { - h := &http.Server{Addr: "0.0.0.0:3000"} - mux := http.NewServeMux() - h.Handler = mux - - // Here is magic! - mux.Handle("/hello", api.Wrap(handleHello)) - - if err := h.ListenAndServe(); err != http.ErrServerClosed { - log.Fatalln(err) - } -} - -func handleHello(ctx context.Context, req *helloRequest) (*helloResponse, error) { - return &helloResponse{Message: fmt.Sprintf("Hello, %s!", req.Name)}, nil -} - -type helloRequest struct { - Name string `json:"name"` -} - -type helloResponse struct { - Message string `json:"message"` -} diff --git a/_examples/wrap/test.http b/_examples/wrap/test.http deleted file mode 100644 index fd8230c..0000000 --- a/_examples/wrap/test.http +++ /dev/null @@ -1,12 +0,0 @@ -### Request: -http://localhost:3000/hello -Content-Type: application/json - -{ - "name": "Alex" -} - -### Response: -# http://localhost:3000/hello -# -#{"message":"Hello, Alex!"} diff --git a/handler.go b/handler.go deleted file mode 100644 index 62ca233..0000000 --- a/handler.go +++ /dev/null @@ -1,31 +0,0 @@ -package api - -import ( - "context" - "encoding/json" - "fmt" - "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) - if err := json.NewDecoder(r.Body).Decode(req); err != nil { - w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write([]byte(fmt.Sprintf("Fail to parse request body: %s", err.Error()))) - return - } - resp, err := handler(r.Context(), req) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - _, _ = w.Write([]byte(err.Error())) - return - } - if err := json.NewEncoder(w).Encode(resp); err != nil { - w.WriteHeader(http.StatusInternalServerError) - _, _ = w.Write([]byte(err.Error())) - return - } - } -} diff --git a/wrap.go b/wrap.go new file mode 100644 index 0000000..ab071cf --- /dev/null +++ b/wrap.go @@ -0,0 +1,51 @@ +package api + +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 + } + if err := json.NewEncoder(w).Encode(resp); err != nil { + w.WriteHeader(http.StatusInternalServerError) + _, _ = w.Write([]byte(err.Error())) + return + } + } +} + +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 WithHeader interface { + WithHeader(header http.Header) +} + +type WithMethod interface { + WithMethod(method string) +} -- cgit v1.2.3