Documentation
¶
Overview ¶
Package httpsyproblem provides a standard interface for handling API error responses in web applications. It implements RFC 7807 which specifies a way to carry machine-readable details of errors in a HTTP response to avoid the need to define new error response formats for HTTP APIs.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Error ¶
func Error(w http.ResponseWriter, r *http.Request, err error)
Error replies to the request by calling err's handler if it implements http.Handler or by wrapping it otherwise.
Example (Json) ¶
package main
import (
"fmt"
"io"
"net/http"
"net/http/httptest"
"os"
"github.com/askeladdk/httpsyproblem"
)
func main() {
w := httptest.NewRecorder()
r := httptest.NewRequest("GET", "/", nil)
r.Header.Set("Accept", "application/json")
err := httpsyproblem.Wrap(http.StatusBadRequest, io.EOF)
err.(*httpsyproblem.Details).Instance = "/products/42"
httpsyproblem.Error(w, r, err)
fmt.Println(w.Result().Status)
_, _ = io.Copy(os.Stdout, w.Body)
}
Output: 400 Bad Request {"detail":"EOF","instance":"/products/42","status":400,"title":"Bad Request","type":"about:blank"}
Example (Text) ¶
package main
import (
"fmt"
"io"
"net/http/httptest"
"os"
"github.com/askeladdk/httpsyproblem"
)
func main() {
w := httptest.NewRecorder()
r := httptest.NewRequest("GET", "/", nil)
httpsyproblem.Error(w, r, io.EOF)
fmt.Println(w.Result().Status)
_, _ = io.Copy(os.Stdout, w.Body)
}
Output: 500 Internal Server Error Internal Server Error
func ServeError ¶ added in v0.0.4
func ServeError(w http.ResponseWriter, r *http.Request, err error)
ServeError replies to the request with a problem details object in JSON or XML format depending on the Accept request header. Panics if an error occurred while marshaling.
func StatusCode ¶
StatusCode reports the HTTP status code associated with err if it implements the StatusCode() int method, 504 Gateway Timeout if it implements Timeout() bool, 503 Service Unavailable if it implements Temporary() bool, 500 Internal Server Error otherwise, or 200 OK if err is nil. StatusCode will unwrap err to find the most precise status code.
Example ¶
package main
import (
"fmt"
"io"
"net/http"
"github.com/askeladdk/httpsyproblem"
)
func main() {
fmt.Println(httpsyproblem.StatusCode(nil))
fmt.Println(httpsyproblem.StatusCode(io.EOF))
fmt.Println(httpsyproblem.StatusCode(httpsyproblem.Wrap(http.StatusBadRequest, io.EOF)))
}
Output: 200 500 400
func Wrap ¶
Wrap associates an error with a status code and wraps it in a Details.
Example ¶
package main
import (
"fmt"
"io"
"net/http"
"github.com/askeladdk/httpsyproblem"
)
func main() {
// Errors are associated with 500 Internal Server Error by default.
err := io.EOF
fmt.Println(httpsyproblem.StatusCode(err), err)
// Wrap any error to associate it with a status code.
err = httpsyproblem.Wrap(http.StatusBadRequest, err)
fmt.Println(httpsyproblem.StatusCode(err), err)
// Wrapping an already wrapped error changes the status code but preserves the details.
err = httpsyproblem.Wrap(http.StatusNotFound, err)
fmt.Println(httpsyproblem.StatusCode(err), err)
fmt.Println(err.(*httpsyproblem.Details).Detail)
}
Output: 500 EOF 400 Bad Request 404 Not Found EOF
Types ¶
type Details ¶
type Details struct {
// A human-readable explanation specific to this occurrence of the problem.
Detail string `json:"detail,omitempty" xml:"detail,omitempty"`
// A URI reference that identifies the specific occurrence of the problem.
// It may or may not yield further information if dereferenced.
Instance string `json:"instance,omitempty" xml:"instance,omitempty"`
// The HTTP status code ([RFC7231], Section 6)
// generated by the origin server for this occurrence of the problem.
Status int `json:"status,omitempty" xml:"status,omitempty"`
// A short, human-readable summary of the problem
// type. It SHOULD NOT change from occurrence to occurrence of the
// problem, except for purposes of localization (e.g., using
// proactive content negotiation; see [RFC7231], Section 3.4).
Title string `json:"title,omitempty" xml:"title,omitempty"`
// A URI reference [RFC3986] that identifies the
// problem type. This specification encourages that, when
// dereferenced, it provide human-readable documentation for the
// problem type (e.g., using HTML [W3C.REC-html5-20141028]). When
// this member is not present, its value is assumed to be
// "about:blank".
Type string `json:"type,omitempty" xml:"type,omitempty"`
// XMLName is needed to marshal to XML.
XMLName xml.Name `json:"-" xml:"urn:ietf:rfc:7807 problem"`
// contains filtered or unexported fields
}
Details implements the RFC 7807 model and can marshaled to JSON and XML.
Additional fields can be added by embedding Details inside another struct. The struct should implement ServeHTTP as follows or the additional fields will not be marshaled.
type MoreDetails struct {
httpsyproblem.Details
TraceID string `json:"trace_id" xml:"trace_id"`
}
func (err *MoreDetails) ServeHTTP(w http.ResponseWriter, r *http.Request) {
httpsyproblem.ServeError(w, r, err)
}
func New ¶
New returns a Details with the Detail, Status and Title fields set according to code and err. If code is 0, the result of StatusCode(err) will be used instead.
func (*Details) ServeHTTP ¶
func (details *Details) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements http.Handler.
func (*Details) StatusCode ¶
StatusCode implements the interface used by StatusCode.
