A golang library that implements application/problem+json
and application/problem+xml
- compatible with
application/problem+json
- inspired by https://github.com/zalando/problem
- RFC link https://tools.ietf.org/html/rfc7807
- a Problem implements the Error interface and can be compared with errors.Is()
- Wrap an error to a Problem
application/problem+xml
is also supported usingxml.Unmarshal
andxml.Marshal
- Auto-Title based on StatusCode with
problem.Of(statusCode)
go get -u schneider.vip/problem
problem.New(problem.Title("Not Found"), problem.Status(404)).JSONString()
Will produce this:
{
"status": 404,
"title": "Not Found"
}
You can also autofill the title based on the StatusCode:
problem.Of(404)
Will produce the same problem as above!
You can also append some more options:
p := problem.Of(http.StatusNotFound)
p.Append(problem.Detail("some more details"))
// Use the Marshaler interface to get the problem json as []byte
jsonBytes, err := json.Marshal(p)
// or simpler (ignores the error)
jsonBytes = p.JSON()
Custom key/values are also supported:
problem.New(problem.Title("Not Found"), problem.Custom("key", "value"))
To write the Problem directly to a http.ResponseWriter:
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
problem.New(
problem.Type("https://example.com/404"),
problem.Status(404),
).WriteTo(w)
})
Create a Problem from an existing error
_, err := ioutil.ReadFile("non-existing")
if err != nil {
p := problem.New(
problem.Wrap(err),
problem.Title("Internal Error"),
problem.Status(404),
)
if !errors.Is(p, os.ErrNotExist) {
t.Fatalf("expected not existing error")
}
}
Gin Framework
If you are using gin you can simply reply the problem to the client:
func(c *gin.Context) {
problem.New(
problem.Title("houston! we have a problem"),
problem.Status(http.StatusNotFound),
).WriteTo(c.Writer)
}
Echo Framework
If you are using echo you can use the following error handler to handle Problems and return them to client.
func ProblemHandler(err error, c echo.Context) {
if prb, ok := err.(*problem.Problem); ok {
if !c.Response().Committed {
if c.Request().Method == http.MethodHead {
prb.WriteHeaderTo(c.Response())
} else if _, err := prb.WriteTo(c.Response()); err != nil {
c.Logger().Error(err)
}
}
} else {
c.Echo().DefaultHTTPErrorHandler(err, c)
}
}
...
// e is an instance of echo.Echo
e.HTTPErrorHandler = ProblemHandler