Skip to content

Commit

Permalink
add the result response responder for Context
Browse files Browse the repository at this point in the history
  • Loading branch information
xgfone committed Apr 6, 2024
1 parent fac6b40 commit 5d3cb77
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 0 deletions.
18 changes: 18 additions & 0 deletions http/reqresp/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"github.com/xgfone/go-apiserver/helper"
"github.com/xgfone/go-apiserver/http/handler"
"github.com/xgfone/go-apiserver/http/header"
"github.com/xgfone/go-apiserver/result"
"github.com/xgfone/go-binder"
"github.com/xgfone/go-defaults"
)
Expand Down Expand Up @@ -115,6 +116,11 @@ type Context struct {
// If nil, use binder.HeaderDecoder instead.
HeaderDecoder binder.Decoder

// Responder is the result responder used by the method Respond.
//
// If nil, use DefaultResponder instead.
Responder func(*Context, result.Response)

// Query and Cookies are used to cache the parsed request query and cookies.
Cookies []*http.Cookie
Query url.Values
Expand Down Expand Up @@ -557,3 +563,15 @@ func (c *Context) sendfile(name, path, dtype string) {
c.SetContentDisposition(dtype, name)
http.ServeContent(c.ResponseWriter, c.Request, stat.Name(), stat.ModTime(), file)
}

// Respond implements the interface result.Responder.
func (c *Context) Respond(response result.Response) {
if c.Responder != nil {
c.Responder(c, response)
} else {
DefaultResponder(c, response)
}
}

// DefaultResponder is default result responder.
var DefaultResponder func(*Context, result.Response) = RespondResultResponse
69 changes: 69 additions & 0 deletions http/reqresp/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
package reqresp

import (
"encoding/json"
"net/http"

"github.com/xgfone/go-apiserver/result"
"github.com/xgfone/go-apiserver/result/codeint"
)

// Handler is a handler based on Context to handle the http request.
Expand Down Expand Up @@ -51,3 +53,70 @@ func runhandler(w http.ResponseWriter, r *http.Request, f Handler) {
result.Err(c.Err).Respond(c)
}
}

/// ----------------------------------------------------------------------- ///

func RespondResultResponse(c *Context, response result.Response) {
xcode := c.Request.Header.Get("X-Response-Code")
if xcode == "" {
xcode = c.GetQuery("X-Response-Code")
}

switch xcode {
case "", "std":
respondstd(c, response)
case "200":
respond200(c, response)
case "500":
respond500(c, response)
default:
respondstd(c, response)
}
}

func getStatusCodeFromError(err error) int {
if e, ok := err.(StatusCoder); ok {
return e.StatusCode()
}
return 500
}

func respondstd(c *Context, r result.Response) {
switch r.Error.(type) {
case nil:
c.JSON(200, r.Data)

case json.Marshaler:
c.JSON(getStatusCodeFromError(r.Error), r.Error)

default:
r.Error = codeint.ErrInternalServerError.WithError(r.Error)
c.JSON(getStatusCodeFromError(r.Error), r.Error)
}
}

func respond200(c *Context, r result.Response) {
switch e := r.Error.(type) {
case nil:
c.JSON(200, r.Data)

case json.Marshaler:
c.JSON(200, e)

default:
c.JSON(200, codeint.ErrInternalServerError.WithError(e))
}
}

func respond500(c *Context, r result.Response) {
switch e := r.Error.(type) {
case nil:
c.JSON(200, r.Data)

case json.Marshaler:
c.JSON(500, e)

default:
c.JSON(500, codeint.ErrInternalServerError.WithError(e))
}
}
4 changes: 4 additions & 0 deletions http/reqresp/responsewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ func WroteHeader(w http.ResponseWriter) bool {
}
}

type StatusCoder interface {
StatusCode() int
}

// ResponseWriter is an extended http.ResponseWriter.
type ResponseWriter interface {
http.ResponseWriter
Expand Down
11 changes: 11 additions & 0 deletions result/codeint/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,17 @@ func (e Error) Respond(responder any) {
result.Err(e).Respond(responder)
}

var _ json.Marshaler = Error{}

func (e Error) MarshalJSON() ([]byte, error) {
type Error struct {
Code int
Message string
}

return json.Marshal(Error{Code: e.Code, Message: e.Message})
}

// Decode uses the decode function to decode the result to the error.
func (e *Error) Decode(decode func(interface{}) error) error {
return decode(e)
Expand Down

0 comments on commit 5d3cb77

Please sign in to comment.