Git Product home page Git Product logo

problem's Introduction

problem

Coverage PkgGoDev Go Report Card

A golang library that implements application/problem+json and application/problem+xml

Features

  • 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 using xml.Unmarshal and xml.Marshal
  • Auto-Title based on StatusCode with problem.Of(statusCode)

Install

go get -u schneider.vip/problem

Usage

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

problem's People

Contributors

1995parham avatar danielbprice avatar mschneider82 avatar ngoldack avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

problem's Issues

Maybe not a issue, but the question about "reason" field

Hello!

First at all, thank you so much for this library, it's quite useful to have something ready-to-use, instead of implement-in-house

The second - I have a question about "reason" field in output JSON link to problem.go#L193 from "master"

RFC 7807 specifies this field as an example of the problem at the beginning of the specification.

The field "reason" does not exists as field inside RFC. Somehow, you are adding it inside output JSON.
Could you please clarify "why"?

I feel like I am missing some important library design considerations

Can't seem to fetch v1.7.0

Hi, thanks so much for taking my PR. When I tried to get the latest version, I got:

% go get schneider.vip/[email protected]
go: added schneider.vip/problem v1.6.0
% go get schneider.vip/[email protected]
go: schneider.vip/[email protected]: unrecognized import path "schneider.vip/problem": https fetch: Get "https://schneider.vip/problem?go-get=1": x509: “TRAEFIK DEFAULT CERT” certificate is not trusted

Any idea what I might be doing wrong?

Http status in Echo context not set

Hi,
i'm using your library currently together with echo and i guess i've found an bug in the error handler example or in the writing code.

So when an error is handled/written to the response writer the http status is written to the response itself.
But sadly the status is not written to the echo context itself.
This results that http requests logs are always showing a status 200.

For example with the echo-logrus library or with this middleware

	router.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
		Format: "[${color.Blue('blue')}${time_custom}] ${protocol} ${method} uri=${uri} => ${status} ${latency_human}\n",
		Output: os.Stdout,
	}))

So either the status should be exported from a problem so we can set it in the handler on our own or it should be done in the prb.WriteTo.

What do you think?

best regards
eloo

Echo Error Handler

Do you think to implement an error handler for Echo that can handle the Problem instances in this repository, is a good idea?

Need API to get StatusCode back out of Problem, or implement WriteHeaderTo()

I'm trying to implement a robust error handler for Echo using problem.Problem. Mostly this was easy. However, trying to handle the case of HEAD requests is challenging, because a HEAD must not return a body. So my natural inclination was to do something like this:

func problemHTTPErrorHandler(err error, c echo.Context) {
         var prb *problem.Problem
           ...
         prb = err.(*problem.Problem)

         var writeErr error
         if c.Request().Method == http.MethodHead {
                 writeErr = c.NoContent(prb.Status())
         } else {
                 writeErr = prb.WriteTo(c.Response())
         }
    ...
}

However, there is no way, presently, to access the Status() from the problem. As a workaround, I can write the problem out to JSON, and then unmarshal it to get the status code, but it's a pain in the neck. I can see a couple of ways to solve this in the library. We could add Status() as I show above. Another option would be to add a new WriteHeaderTo() method. Maybe something like this?

// WriteHeaderTo writes the HTTP headers corresponding to the problem's content type
// and the problem's http statuscode. This is suitable for responding to HEAD requests.
func (p Problem) WriteHeaderTo(w http.ResponseWriter) (int, error) {
        w.Header().Set("Content-Type", ContentTypeJSON)
        if statuscode, ok := p.data["status"]; ok {
                if statusint, ok := statuscode.(int); ok {
                        w.WriteHeader(statusint)
                }
        }
        return nil
}

Thanks!!

Edit: If you let me know your preference, I can prepare a pull request.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.