Skip to content

Commit

Permalink
- Added logic for the user to overwrite the transfer object error.
Browse files Browse the repository at this point in the history
- Updated example to demonstrate
  • Loading branch information
Leon Silcott committed Sep 10, 2021
1 parent 2046955 commit 38c7f47
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 11 deletions.
111 changes: 111 additions & 0 deletions examples/example_simple_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"log"
"net/http"
"strconv"

"github.com/ooaklee/reply"
)
Expand Down Expand Up @@ -75,6 +76,105 @@ func (t *fooReplyTransferObject) SetErrors(transferObjectErrors []reply.Transfer

////////////////////

/////////////////////////////////////////////////
//// Custom Transition Object Error Example /////
// This is an example of how you can create a
// custom response structure for errrors retutned
// in the response

type barError struct {

// Title a short summary of the problem
Title string `json:"title,omitempty"`

// Message a description of the error
Message string `json:"message,omitempty"`

// About holds the link that gives further insight into the error
About string `json:"about,omitempty"`

// More randomd top level attribute to make error
// difference
More struct {
// Status the HTTP status associated with error
Status string `json:"status,omitempty"`

// Code internal error code used to reference error
Code string `json:"code,omitempty"`

// Meta contains additional meta-information about the error
Meta interface{} `json:"meta,omitempty"`
} `json:"more,omitempty"`
}

// SetTitle adds title to error
func (b *barError) SetTitle(title string) {
b.Title = title
}

// GetTitle returns error's title
func (b *barError) GetTitle() string {
return b.Title
}

// SetDetail adds detail to error
func (b *barError) SetDetail(detail string) {
b.Message = detail
}

// GetDetail return error's detail
func (b *barError) GetDetail() string {
return b.Message
}

// SetAbout adds about to error
func (b *barError) SetAbout(about string) {
b.About = about
}

// GetAbout return error's about
func (b *barError) GetAbout() string {
return b.About
}

// SetStatusCode converts and add http status code to error
func (b *barError) SetStatusCode(status int) {
b.More.Status = strconv.Itoa(status)
}

// GetStatusCode returns error's HTTP status code
func (b *barError) GetStatusCode() string {
return b.More.Status
}

// SetCode adds internal code to error
func (b *barError) SetCode(code string) {
b.More.Code = code
}

// GetCode returns error's internal code
func (b *barError) GetCode() string {
return b.More.Code
}

// SetMeta adds meta property to error
func (b *barError) SetMeta(meta interface{}) {
b.More.Meta = meta
}

// GetMeta returns error's meta property
func (b *barError) GetMeta() interface{} {
return b.More.Meta
}

// RefreshTransferObject returns an empty instance of transfer object
// error
func (b *barError) RefreshTransferObject() reply.TransferObjectError {
return &barError{}
}

////////////////////

type user struct {
ID int `json:"id"`
Name string `json:"name"`
Expand All @@ -90,6 +190,8 @@ var replier *reply.Replier = reply.NewReplier(baseManifest)

var replierWithCustomTransitionObj *reply.Replier = reply.NewReplier(baseManifest, reply.WithTransferObject(&fooReplyTransferObject{}))

var replierWithCustomTransitionObjError *reply.Replier = reply.NewReplier(baseManifest, reply.WithTransferObjectError(&barError{}))

func simpleUsersAPINotFoundHandler(w http.ResponseWriter, r *http.Request) {

// Do something with a server
Expand Down Expand Up @@ -177,6 +279,14 @@ func simpleUsersAPINotFoundCustomReplierHandler(w http.ResponseWriter, r *http.R
//////////////////////////////
//// Handlers Using Aides ////

func simpleUsersAPIMultiErrorUsingAideWithCustomErrorHandler(w http.ResponseWriter, r *http.Request) {

// Do something with a server
serverErrs := []error{errors.New("example-dob-validation-error"), errors.New("example-name-validation-error")}

_ = replierWithCustomTransitionObjError.NewHTTPMultiErrorResponse(w, serverErrs)
}

func simpleUsersAPIMultiErrorUsingAideHandler(w http.ResponseWriter, r *http.Request) {

// Do something with a server
Expand Down Expand Up @@ -255,6 +365,7 @@ func handleRequest() {
http.HandleFunc("/custom/users/3", simpleUsersAPINotFoundCustomReplierHandler)

http.HandleFunc("/aides/errors", simpleUsersAPIMultiErrorUsingAideHandler)
http.HandleFunc("/aides/errors/custom", simpleUsersAPIMultiErrorUsingAideWithCustomErrorHandler)
http.HandleFunc("/aides/users", simpleUsersAPIUsingAideHandler)
http.HandleFunc("/aides/users/3", simpleUsersAPINotFoundUsingAideHandler)
http.HandleFunc("/aides/users/4", simpleUsersAPINoManifestEntryUsingAideHandler)
Expand Down
6 changes: 6 additions & 0 deletions model.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ func (e *Error) GetMeta() interface{} {
return e.Meta
}

// RefreshTransferObject returns an empty instance of transfer object
// error
func (e *Error) RefreshTransferObject() TransferObjectError {
return &Error{}
}

// defaultReplyTransferObject handles structing response for client
// consumption
type defaultReplyTransferObject struct {
Expand Down
37 changes: 26 additions & 11 deletions replier.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type TransferObjectError interface {
GetCode() string
SetMeta(meta interface{})
GetMeta() interface{}
RefreshTransferObject() TransferObjectError
}

// TransferObject outlines expected methods of a transfer object
Expand Down Expand Up @@ -65,6 +66,14 @@ func WithTransferObject(replacementTransferObject TransferObject) Option {
}
}

// WithTransferObjectError overwrites the transfer object used to represent
// errors in response
func WithTransferObjectError(replacementTransferObjectError TransferObjectError) Option {
return func(r *Replier) {
r.transferObjectError = replacementTransferObjectError
}
}

// NewResponseRequest holds attributes for response
type NewResponseRequest struct {
Writer http.ResponseWriter
Expand All @@ -81,18 +90,21 @@ type NewResponseRequest struct {

// Replier handles managing responses
type Replier struct {
errorManifest ErrorManifest
transferObject TransferObject
errorManifest ErrorManifest
transferObject TransferObject
transferObjectError TransferObjectError
}

// NewReplier creates a replier
func NewReplier(manifests []ErrorManifest, options ...Option) *Replier {

activeTransferObject := &defaultReplyTransferObject{}
activeTransferObjectError := &Error{}

replier := Replier{
errorManifest: mergeManifestCollections(manifests),
transferObject: activeTransferObject,
errorManifest: mergeManifestCollections(manifests),
transferObject: activeTransferObject,
transferObjectError: activeTransferObjectError,
}

// Add option add-ons on replier
Expand Down Expand Up @@ -189,10 +201,10 @@ func (r *Replier) generateMultiErrorResponse(errs []error) error {
if is5xx(manifestItem.StatusCode) {
return r.sendHTTPErrorsResponse(manifestItem.StatusCode, append(
[]TransferObjectError{},
ConvertErrorItemToTransferObjectError(manifestItem)))
r.convertErrorManifestItemToTransferObjectError(manifestItem)))
}

transferObjectErrors = append(transferObjectErrors, ConvertErrorItemToTransferObjectError(manifestItem))
transferObjectErrors = append(transferObjectErrors, r.convertErrorManifestItemToTransferObjectError(manifestItem))
}

statusCode := getAppropiateStatusCodeOrDefault(transferObjectErrors)
Expand All @@ -205,7 +217,7 @@ func (r *Replier) generateMultiErrorResponse(errs []error) error {
func (r *Replier) generateErrorResponse(err error) error {
manifestItem := r.getErrorManifestItem(err)

transferObjectErrors := append([]TransferObjectError{}, ConvertErrorItemToTransferObjectError(manifestItem))
transferObjectErrors := append([]TransferObjectError{}, r.convertErrorManifestItemToTransferObjectError(manifestItem))

return r.sendHTTPErrorsResponse(manifestItem.StatusCode, transferObjectErrors)
}
Expand Down Expand Up @@ -269,18 +281,21 @@ func (r *Replier) setHeaders(h map[string]string) {
}
}

// ConvertErrorItemToTransferObjectError converts manifest item to valid
// convertErrorManifestItemToTransferObjectError converts manifest error item to valid
// transfer object error
func ConvertErrorItemToTransferObjectError(errorItem ErrorManifestItem) TransferObjectError {
convertedError := Error{}
func (r *Replier) convertErrorManifestItemToTransferObjectError(errorItem ErrorManifestItem) TransferObjectError {

// Use fresh transfer object error
convertedError := r.transferObjectError.RefreshTransferObject()

convertedError.SetTitle(errorItem.Title)
convertedError.SetDetail(errorItem.Detail)
convertedError.SetAbout(errorItem.About)
convertedError.SetCode(errorItem.Code)
convertedError.SetStatusCode(errorItem.StatusCode)
convertedError.SetMeta(errorItem.Meta)

return &convertedError
return convertedError
}

// getAppropiateStatusCodeOrDefault loops through collection of transfer object errors (first to last), and
Expand Down

0 comments on commit 38c7f47

Please sign in to comment.