From 052eb1ed56db211984b00fe969a8fa158dd228d1 Mon Sep 17 00:00:00 2001 From: some Date: Thu, 10 Oct 2024 14:59:55 -0400 Subject: [PATCH] Add back ResponseBuilder --- default.go | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++--- server.go | 61 +++++++++++++++++++++++------------ 2 files changed, 131 insertions(+), 25 deletions(-) diff --git a/default.go b/default.go index d8797d0..7d71155 100644 --- a/default.go +++ b/default.go @@ -43,12 +43,12 @@ func (e DefaultError) String() (out string) { return } -func (e DefaultError) Response() *Response { +func (e DefaultError) Response() *response { body, err := json.Marshal(struct{ Error string }{Error: e.String()}) if err != nil { panic(err) } - return &Response{ + return &response{ Status: e.Status(), Header: Header{"Content-Type": []string{"text/javascript", "charset=utf-8"}}, Body: body, @@ -81,7 +81,7 @@ type DefaultRequestBuilder struct { } } -// /* Leave commented to require services to create their own New method */ +// Leave commented to require services to create their own New method // var _ RequestBuilder = (*DefaultRequestBuilder)(nil) // func (*DefaultRequestBuilder) New() RequestBuilder { // return NewDefaultRequestBuilder() @@ -177,7 +177,7 @@ func (rqb *DefaultRequestBuilder) Url(url url.URL) (e Error) { return } -func (rqb *DefaultRequestBuilder) Header(header Header) (e Error) { +func (rqb *DefaultRequestBuilder) Header(header map[string][]string) (e Error) { *rqb.header.Header = header err := rqb.header.Header.Unmarshal(rqb.header.fields) if err != nil { @@ -192,7 +192,7 @@ func (rqb *DefaultRequestBuilder) Body(body io.ReadCloser) (e Error) { return } -func (rqb *DefaultRequestBuilder) Values(values Values) (e Error) { +func (rqb *DefaultRequestBuilder) Values(values map[string][]string) (e Error) { *rqb.values.Values = values err := rqb.values.Values.Unmarshal(rqb.values.fields) if err != nil { @@ -210,3 +210,88 @@ func (rqb *DefaultRequestBuilder) Request() (req *request) { } return } + +type DefaultResponseBuilder struct { + errorHandler Error + status *int + header struct { + *Header + fields header + } + body struct { + *Body + fields body + } +} + +// Leave commented to require services to create their own New method +// var _ ResponseBuilder = (*DefaultResponseBuilder)(nil) +// func (rsb *DefaultResponseBuilder) New() ResponseBuilder { +// return NewDefaultResponseBuilder() +// } + +func (*DefaultResponseBuilder) mustEmbedDefaultResponseBuilder() {} + +func NewDefaultResponseBuilder() *DefaultResponseBuilder { + return &DefaultResponseBuilder{} +} + +func (rsb *DefaultResponseBuilder) SetStatus(code *int) *DefaultResponseBuilder { + rsb.status = code + return rsb +} + +func (rsb *DefaultResponseBuilder) SetHeader(parsed *Header, fields header) *DefaultResponseBuilder { + rsb.header.Header = parsed + rsb.header.fields = fields + return rsb +} + +func (rsb *DefaultResponseBuilder) SetBody(parsed *Body, fields body) *DefaultResponseBuilder { + rsb.body.Body = parsed + rsb.body.fields = fields + return rsb +} + +func (rsb *DefaultResponseBuilder) SetDefaults() *DefaultResponseBuilder { + if rsb.status == nil { + c := http.StatusOK + rsb.status = &c + } + if rsb.header.Header == nil || rsb.header.fields == nil { + hd := Header{"Content-Type": []string{"text/plain", "charset=utf-8"}} + rsb.header.Header = &hd + hfd := struct{ Header }{Header: hd} + rsb.header.fields = &hfd + } + if rsb.body.Body == nil || rsb.body.fields == nil { + bd := make(Body, 0) + rsb.body.Body = &bd + bfd := struct{ Body }{Body: bd} + rsb.body.fields = &bfd + } + return rsb +} + +func (rsb *DefaultResponseBuilder) Header(header map[string][]string) (e Error) { + *rsb.header.Header = header + err := rsb.header.Header.Unmarshal(rsb.header.fields) + if err != nil { + return rsb.errorHandler.Error(DefaultErrorInternalServerError) + } + return +} + +func (rsb *DefaultResponseBuilder) Write(body []byte) (e Error) { + *rsb.body.Body = append(*rsb.body.Body, body...) + return +} + +func (rsb *DefaultResponseBuilder) Response() (res *response) { + res = &response{ + Status: *rsb.status, + Header: *rsb.header.Header, + Body: *rsb.body.Body, + } + return +} diff --git a/server.go b/server.go index 50a9d3e..0bd34ec 100644 --- a/server.go +++ b/server.go @@ -8,17 +8,25 @@ import ( "somehole.com/common/log" ) -type Response struct { +type response struct { Status int Header Header Body Body } +type Response[RSB ResponseBuilder] struct { + response +} + +func NewResponse[RSB ResponseBuilder](rsb RSB) *Response[RSB] { + return &Response[RSB]{*rsb.Response()} +} + type Error interface { Error(e Error) (err Error) Status() (code int) String() (out string) - Response() (res *Response) + Response() (res *response) } type request struct { @@ -46,12 +54,25 @@ type RequestBuilder interface { New() (rqb RequestBuilder) Allowed(method string) (err Error) Url(url url.URL) (err Error) - Header(header Header) (err Error) - Values(values Values) (err Error) + Header(map[string][]string) (err Error) + Values(map[string][]string) (err Error) Body(body io.ReadCloser) (err Error) Request() *request } +func (*Response[RSB]) ResponseBuilder() ResponseBuilder { + var rsb RSB + return rsb.New() +} + +type ResponseBuilder interface { + mustEmbedDefaultResponseBuilder() + New() (rsb ResponseBuilder) + Header(header Header) (err Error) + Write(body []byte) (err Error) + Response() *response +} + type writer struct { http.ResponseWriter log.Logger @@ -82,47 +103,47 @@ const ( numServeStages ) -type ServeFunc[RQB RequestBuilder] func(req *Request[RQB]) (res *Response, err Error) +type ServeFunc[RQB RequestBuilder, RSB ResponseBuilder] func(req *Request[RQB]) (res *Response[RSB], err Error) -type server[RQB RequestBuilder] struct { +type server[RQB RequestBuilder, RSB ResponseBuilder] struct { logger log.Logger - serve [numServeStages][]ServeFunc[RQB] + serve [numServeStages][]ServeFunc[RQB, RSB] } -func NewServer[RQB RequestBuilder](serve func(req *Request[RQB]) (res *Response, err Error)) (srv *server[RQB]) { - srv = &server[RQB]{ - serve: [numServeStages][]ServeFunc[RQB]{}, +func NewServer[RQB RequestBuilder, RSB ResponseBuilder](serve ServeFunc[RQB, RSB]) (srv *server[RQB, RSB]) { + srv = &server[RQB, RSB]{ + serve: [numServeStages][]ServeFunc[RQB, RSB]{}, } srv.serve[serveMain] = append(srv.serve[serveMain], serve) return srv } -func (srv *server[RQB]) SetLogger(logger log.Logger) *server[RQB] { +func (srv *server[RQB, RSB]) SetLogger(logger log.Logger) *server[RQB, RSB] { srv.logger = logger return srv } -func (srv *server[RQB]) addServeFunc(when serveStage, serve ServeFunc[RQB]) *server[RQB] { +func (srv *server[RQB, RSB]) addServeFunc(when serveStage, serve ServeFunc[RQB, RSB]) *server[RQB, RSB] { if srv.serve[when] == nil { - srv.serve[when] = make([]ServeFunc[RQB], 0) + srv.serve[when] = make([]ServeFunc[RQB, RSB], 0) } srv.serve[when] = append(srv.serve[when], serve) return srv } -func (srv *server[RQB]) PreServeFunc(serve ServeFunc[RQB]) *server[RQB] { +func (srv *server[RQB, RSB]) PreServeFunc(serve ServeFunc[RQB, RSB]) *server[RQB, RSB] { return srv.addServeFunc(servePre, serve) } -func (srv *server[RQB]) AddServeFunc(serve ServeFunc[RQB]) *server[RQB] { +func (srv *server[RQB, RSB]) AddServeFunc(serve ServeFunc[RQB, RSB]) *server[RQB, RSB] { return srv.addServeFunc(serveMain, serve) } -func (srv *server[RQB]) PostServeFunc(serve ServeFunc[RQB]) *server[RQB] { +func (srv *server[RQB, RSB]) PostServeFunc(serve ServeFunc[RQB, RSB]) *server[RQB, RSB] { return srv.addServeFunc(servePost, serve) } -func (srv *server[RQB]) ServeHTTP(w http.ResponseWriter, r *http.Request) { +func (srv *server[RQB, RSB]) ServeHTTP(w http.ResponseWriter, r *http.Request) { var rqb RQB rqb = rqb.New().(RQB) wr := writer{ResponseWriter: w, Logger: srv.logger} @@ -132,14 +153,14 @@ func (srv *server[RQB]) ServeHTTP(w http.ResponseWriter, r *http.Request) { if ok := wr.handleError(rqb.Url(*r.URL)); !ok { return } - if ok := wr.handleError(rqb.Header(Header(r.Header))); !ok { + if ok := wr.handleError(rqb.Header(r.Header)); !ok { return } if ok := wr.handleError(rqb.Body(r.Body)); !ok { return } r.ParseForm() - if ok := wr.handleError(rqb.Values(Values(r.Form))); !ok { + if ok := wr.handleError(rqb.Values(r.Form)); !ok { return } for _, stage := range srv.serve { @@ -151,7 +172,7 @@ func (srv *server[RQB]) ServeHTTP(w http.ResponseWriter, r *http.Request) { if res.Header != nil { for key, value := range res.Header { for _, v := range value { - w.Header().Add(key, v) + wr.Header().Add(key, v) } } }