package jsonapi import ( "fmt" "net/http" "strconv" ) // SourceError contains references to the source of the error type SourceError struct { Pointer string `json:"pointer,omitempty"` Parameter string `json:"parameter,omitempty"` } // Error objects provide additional information about problems encountered // while performing an operation. // See http://jsonapi.org/format/#error-objects type Error struct { Status int `json:"status,string"` Title string `json:"title"` Code string `json:"code,omitempty"` Detail string `json:"detail,omitempty"` Source SourceError `json:"source,omitempty"` Links *LinksList `json:"links,omitempty"` } // ErrorList is just an array of error objects type ErrorList []*Error func (e *Error) Error() string { return e.Title + "(" + strconv.Itoa(e.Status) + ")" + ": " + e.Detail } // NewError creates a new generic Error func NewError(status int, detail string) *Error { return &Error{ Status: status, Title: http.StatusText(status), Detail: detail, } } // Errorf creates a new generic Error with detail build as Sprintf func Errorf(status int, format string, args ...interface{}) *Error { detail := fmt.Sprintf(format, args...) return NewError(status, detail) } // NotFound returns a 404 formatted error func NotFound(err error) *Error { return &Error{ Status: http.StatusNotFound, Title: "Not Found", Detail: err.Error(), } } // BadRequest returns a 400 formatted error func BadRequest(err error) *Error { return &Error{ Status: http.StatusBadRequest, Title: "Bad Request", Detail: err.Error(), } } // Unauthorized returns a 401 formatted error func Unauthorized(err error) *Error { return &Error{ Status: http.StatusUnauthorized, Title: "Unauthorized", Detail: err.Error(), } } // BadJSON returns a 400 formatted error meaning the json input is // malformed. func BadJSON() *Error { return &Error{ Status: http.StatusBadRequest, Title: "Bad Request", Detail: "JSON input is malformed or is missing mandatory fields", } } // MethodNotAllowed returns a 405 formatted error func MethodNotAllowed(method string) *Error { return &Error{ Status: http.StatusMethodNotAllowed, Title: "Method Not Allowed", Detail: method + " is not allowed on this endpoint", } } // Conflict returns a 409 formatted error representing a conflict func Conflict(err error) *Error { return &Error{ Status: http.StatusConflict, Title: "Conflict", Detail: err.Error(), } } // InternalServerError returns a 500 formatted error func InternalServerError(err error) *Error { return &Error{ Status: http.StatusInternalServerError, Title: "Internal Server Error", Detail: err.Error(), } } // PreconditionFailed returns a 412 formatted error when an expectation from an // HTTP header is not matched func PreconditionFailed(parameter string, err error) *Error { return &Error{ Status: http.StatusPreconditionFailed, Title: "Precondition Failed", Detail: err.Error(), Source: SourceError{ Parameter: parameter, }, } } // InvalidParameter returns a 422 formatted error when an HTTP or Query-String // parameter is invalid func InvalidParameter(parameter string, err error) *Error { return &Error{ Status: http.StatusUnprocessableEntity, Title: "Invalid Parameter", Detail: err.Error(), Source: SourceError{ Parameter: parameter, }, } } // InvalidAttribute returns a 422 formatted error when an attribute is invalid func InvalidAttribute(attribute string, err error) *Error { return &Error{ Status: http.StatusUnprocessableEntity, Title: "Invalid Attribute", Detail: err.Error(), Source: SourceError{ Pointer: "/data/attributes/" + attribute, }, } } // Forbidden returns a 403 Forbidden error formatted when an action is // fobidden. func Forbidden(err error) *Error { return &Error{ Status: http.StatusForbidden, Title: "Forbidden", Detail: err.Error(), } } // BadGateway returns a 502 formatted error func BadGateway(err error) *Error { return &Error{ Status: http.StatusBadGateway, Title: "Bad Gateway", Detail: err.Error(), } } // ServiceUnavailable returns a 503 formatted error func ServiceUnavailable(err error) *Error { return &Error{ Status: http.StatusServiceUnavailable, Title: "Service Unavailable", Detail: err.Error(), } }