From 84a91d56eb37fe517e912452ab95bc71b7e2ec43 Mon Sep 17 00:00:00 2001 From: some Date: Tue, 8 Oct 2024 22:30:29 -0400 Subject: [PATCH] Attempt to implement default methods --- body.go | 9 +++ common.go | 3 + default.go | 167 +++++++++++++++++++++++++++++++++++++++++++++++ header.go | 6 ++ unimplemented.go | 129 ------------------------------------ values.go | 6 ++ 6 files changed, 191 insertions(+), 129 deletions(-) create mode 100644 body.go create mode 100644 default.go delete mode 100644 unimplemented.go diff --git a/body.go b/body.go new file mode 100644 index 0000000..156f277 --- /dev/null +++ b/body.go @@ -0,0 +1,9 @@ +package router + +type body interface { + mustEmbedBody() +} + +type Body []byte + +func (Body) mustEmbedBody() {} diff --git a/common.go b/common.go index db19065..1e53492 100644 --- a/common.go +++ b/common.go @@ -12,6 +12,9 @@ func (gv genericValues) Parse(data any, tag string) (err error) { gv = make(genericValues) } d := reflect.ValueOf(data) + if d.Kind() == reflect.Pointer || d.Kind() == reflect.Interface { + d = d.Elem() + } if d.Kind() != reflect.Struct { err = fmt.Errorf("expected struct input for data") return diff --git a/default.go b/default.go new file mode 100644 index 0000000..59cce6c --- /dev/null +++ b/default.go @@ -0,0 +1,167 @@ +package router + +import ( + "encoding/json" + "fmt" + "io" + "net/http" +) + +type DefaultError uint32 + +const ( + DefaultOk DefaultError = http.StatusOK + DefaultErrorNotImplemented DefaultError = http.StatusNotImplemented + DefaultErrorMethodNotAllowed DefaultError = http.StatusMethodNotAllowed + DefaultErrorBadRequest DefaultError = http.StatusBadRequest + DefaultErrorUnauthorized DefaultError = http.StatusUnauthorized + DefaultErrorServerError DefaultError = http.StatusInternalServerError +) + +func (e DefaultError) Ok() (ok bool) { + return e == DefaultOk +} + +func (e DefaultError) HttpStatus() (code int) { + return int(e) +} + +func (e DefaultError) String() (out string) { + switch e { + case DefaultOk: + out = "ok" + case DefaultErrorNotImplemented: + out = "server not implemented" + case DefaultErrorMethodNotAllowed: + out = "method not allowed" + case DefaultErrorBadRequest: + out = "bad request" + case DefaultErrorUnauthorized: + out = "user unauthorized" + case DefaultErrorServerError: + out = "internal server error" + default: + out = "unhandled error" + } + return +} + +func (e DefaultError) Error() (out string) { + return fmt.Sprintf("%s (%d)", e.String(), e.HttpStatus()) +} + +func (e DefaultError) BodyBytes() (body []byte) { + body, _ = json.Marshal(struct{ Error string }{Error: e.String()}) + return +} + +type DefaultRequestBuilder struct { + requestBuilder RequestBuilder + allowedMethods *[]string + header struct { + *Header + fields *header + } + values struct { + *Values + fields *values + } + body struct { + *Body + fields *body + } +} + +func NewDefaultRequestBuilder(rb RequestBuilder, am *[]string, h *Header, hf *header, v *Values, vf *values, b *Body, bf *body) DefaultRequestBuilder { + return DefaultRequestBuilder{ + requestBuilder: rb, + allowedMethods: am, + header: struct { + *Header + fields *header + }{ + Header: h, + fields: hf, + }, + values: struct { + *Values + fields *values + }{ + Values: v, + fields: vf, + }, + body: struct { + *Body + fields *body + }{ + Body: b, + fields: bf, + }, + } +} + +func (rb DefaultRequestBuilder) RequestBuilder() RequestBuilder { + return rb.requestBuilder +} + +func (rb *DefaultRequestBuilder) Allowed(method string) (errRes ErrorResponse) { + var ok bool + for _, m := range *rb.allowedMethods { + if m == method { + ok = true + } + } + if !ok { + return DefaultErrorMethodNotAllowed + } + return DefaultOk +} + +func (rb *DefaultRequestBuilder) Header(header Header) (errRes ErrorResponse) { + err := rb.header.Header.Parse(header) + if err != nil { + return DefaultErrorBadRequest + } + return DefaultOk +} + +func (rb *DefaultRequestBuilder) ReadBody(body io.ReadCloser) (errRes ErrorResponse) { + defer body.Close() + json.NewDecoder(body).Decode(rb.body.fields) + return DefaultOk +} + +func (rb *DefaultRequestBuilder) Values(values Values) (errRes ErrorResponse) { + err := rb.values.Values.Parse(values) + if err != nil { + return DefaultErrorBadRequest + } + return DefaultOk +} + +type DefaultResponse struct { + header struct { + *Header + fields *header + } + body struct { + *Body + fields *body + } +} + +func (r DefaultResponse) Response() Response { + return &r +} + +func (r *DefaultResponse) Header() (header Header) { + if r.header.Header == nil { + r.header.Header.Parse(r.header.fields) + } + return *r.header.Header +} + +func (r *DefaultResponse) BodyBytes() (body []byte) { + body, _ = json.Marshal(r.body.fields) + return +} diff --git a/header.go b/header.go index f60ed6c..fbe12c5 100644 --- a/header.go +++ b/header.go @@ -4,8 +4,14 @@ import ( "strings" ) +type header interface { + mustEmbedHeader() +} + type Header map[string][]string +func (Header) mustEmbedHeader() {} + func (h Header) Parse(data any) error { return genericValues(h).Parse(data, "header") } diff --git a/unimplemented.go b/unimplemented.go deleted file mode 100644 index e7956a3..0000000 --- a/unimplemented.go +++ /dev/null @@ -1,129 +0,0 @@ -package router - -import ( - "encoding/json" - "fmt" - "io" - "net/http" -) - -type UnimplementedError uint32 - -const ( - UnimplementedOk UnimplementedError = http.StatusOK - UnimplementedErrorNotImplemented UnimplementedError = http.StatusNotImplemented - UnimplementedErrorMethodNotAllowed UnimplementedError = http.StatusMethodNotAllowed - UnimplementedErrorBadRequest UnimplementedError = http.StatusBadRequest - UnimplementedErrorUnauthorized UnimplementedError = http.StatusUnauthorized - UnimplementedErrorServerError UnimplementedError = http.StatusInternalServerError -) - -func (e UnimplementedError) Ok() (ok bool) { - return e == UnimplementedOk -} - -func (e UnimplementedError) HttpStatus() (code int) { - return int(e) -} - -func (e UnimplementedError) String() (out string) { - switch e { - case UnimplementedOk: - out = "ok" - case UnimplementedErrorNotImplemented: - out = "server not implemented" - case UnimplementedErrorMethodNotAllowed: - out = "method not allowed" - case UnimplementedErrorBadRequest: - out = "bad request" - case UnimplementedErrorUnauthorized: - out = "user unauthorized" - case UnimplementedErrorServerError: - out = "internal server error" - default: - out = "unhandled error" - } - return -} - -func (e UnimplementedError) Error() (out string) { - return fmt.Sprintf("%s (%d)", e.String(), e.HttpStatus()) -} - -func (e UnimplementedError) BodyBytes() (body []byte) { - body, _ = json.Marshal(struct{ Error string }{Error: e.String()}) - return -} - -type UnimplementedRequestBuilder struct { - allowedMethods []string - header struct { - Header - } - values struct { - Values - } - Body struct{} -} - -func (rb UnimplementedRequestBuilder) RequestBuilder() RequestBuilder { - return &rb -} - -func (rb *UnimplementedRequestBuilder) Allowed(method string) (errRes ErrorResponse) { - var ok bool - for _, m := range rb.allowedMethods { - if m == method { - ok = true - } - } - if !ok { - return UnimplementedErrorMethodNotAllowed - } - return UnimplementedOk -} - -func (rb *UnimplementedRequestBuilder) Header(header Header) (errRes ErrorResponse) { - err := rb.header.Header.Parse(header) - if err != nil { - return UnimplementedErrorBadRequest - } - return UnimplementedOk -} - -func (rb *UnimplementedRequestBuilder) ReadBody(body io.ReadCloser) (errRes ErrorResponse) { - defer body.Close() - json.NewDecoder(body).Decode(&rb.Body) - return UnimplementedOk -} - -func (rb *UnimplementedRequestBuilder) Values(values Values) (errRes ErrorResponse) { - err := rb.values.Values.Parse(values) - if err != nil { - return UnimplementedErrorBadRequest - } - return UnimplementedOk -} - -type UnimplementedResponse struct { - header struct { - Header - } - Body struct{} -} - -func (r UnimplementedResponse) Response() Response { - return &r -} - -func (r *UnimplementedResponse) Header() (header Header) { - if r.header.Header == nil { - r.header.Header.Parse(r.header) - } - return r.header.Header -} - -func (r *UnimplementedResponse) BodyBytes() (body []byte) { - body, _ = json.Marshal(r.Body) - return -} diff --git a/values.go b/values.go index 445637c..cb39a5c 100644 --- a/values.go +++ b/values.go @@ -1,7 +1,13 @@ package router +type values interface { + mustEmbedValues() +} + type Values map[string][]string +func (Values) mustEmbedValues() {} + func (v Values) Parse(data any) error { return genericValues(v).Parse(data, "form") }