{"id":15646349,"url":"https://github.com/meysamhadeli/problem-details","last_synced_at":"2025-05-08T00:09:04.788Z","repository":{"id":61626085,"uuid":"542752082","full_name":"meysamhadeli/problem-details","owner":"meysamhadeli","description":"ProblemDetails is a Error Handler base on [RFC 7807] standard to map our error to standardized error payload to client.","archived":false,"fork":false,"pushed_at":"2024-10-24T22:37:11.000Z","size":611,"stargazers_count":54,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-05-08T00:08:56.563Z","etag":null,"topics":["error","error-handler","error-handling","errorhanders","errorhandler","errors","go","golang","package","pkg","problem","problem-details","problemdetails"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/meysamhadeli.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-28T19:09:59.000Z","updated_at":"2025-04-16T19:28:28.000Z","dependencies_parsed_at":"2024-06-19T02:42:15.999Z","dependency_job_id":"fa5e3ecd-807b-40b6-bf1a-cb22c7dd72a5","html_url":"https://github.com/meysamhadeli/problem-details","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meysamhadeli%2Fproblem-details","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meysamhadeli%2Fproblem-details/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meysamhadeli%2Fproblem-details/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meysamhadeli%2Fproblem-details/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/meysamhadeli","download_url":"https://codeload.github.com/meysamhadeli/problem-details/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252973690,"owners_count":21834108,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["error","error-handler","error-handling","errorhanders","errorhandler","errors","go","golang","package","pkg","problem","problem-details","problemdetails"],"created_at":"2024-10-03T12:12:31.837Z","updated_at":"2025-05-08T00:09:04.745Z","avatar_url":"https://github.com/meysamhadeli.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\" style=\"margin-bottom:20px\"\u003e\n  \u003cimg src=\"assets/logo.png\" alt=\"problem-details\" /\u003e\n  \u003cdiv align=\"center\"\u003e\n    \u003ca href=\"https://github.com/meysamhadeli/problem-details/actions/workflows/ci.yml\"\u003e\u003cimg alt=\"build-status\" src=\"https://github.com/meysamhadeli/problem-details/actions/workflows/ci.yml/badge.svg?branch=main\u0026style=flat-square\"/\u003e\u003c/a\u003e\n\t  \u003ca href=\"https://goreportcard.com/report/github.com/meysamhadeli/problem-details\" \u003e\u003cimg alt=\"go report\" src=\"https://goreportcard.com/badge/github.com/meysamhadeli/problem-details\"/\u003e\u003c/a\u003e\n    \u003ca\u003e\u003cimg alt=\"license\" src=\"https://img.shields.io/badge/go%20version-%3E=1.23-2CFDD.svg?style=flat-square\"/\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/meysamhadeli/problem-details/blob/main/LICENSE\"\u003e\u003cimg alt=\"build-status\" src=\"https://img.shields.io/github/license/meysamhadeli/problem-details?color=%234275f5\u0026style=flat-square\"/\u003e\u003c/a\u003e\n        \u003ca href=\"https://coveralls.io/github/meysamhadeli/problem-details?branch=main\"\u003e\u003cimg alt=\"Coverage Status\" src=\"https://img.shields.io/coveralls/github/meysamhadeli/problem-details?color=%23f542cb\u0026style=flat-square\"/\u003e\u003c/a\u003e\n    \u003ca href=\"https://pkg.go.dev/github.com/meysamhadeli/problem-details\"\u003e\u003cimg alt=\"build-status\" src=\"https://pkg.go.dev/badge/github.com/meysamhadeli/problem-details\"/\u003e\u003c/a\u003e\n\n  \u003c/div\u003e\n\u003c/div\u003e\n\n\u003e ProblemDetails is a Error Handler base on [RFC 7807](https://datatracker.ietf.org/doc/html/rfc7807) standard to map our error to standardized error payload to client. The data model for problem details is a JSON object; when formatted as a JSON document, it uses the `application/problem+json` media type and for XML format it uses the `application/problem+xml` media type. By defining machine-readable details of HTTP errors, we can avoid defining new error response formats for HTTP APIs.\n\nOur problem details response body and headers will be look like this:\n```go\n    // Response body\n\n{\n    \"status\": 400,                                        // The HTTP status code generated on the problem occurrence\n    \"title\": \"bad-request\",                               // A short human-readable problem summary\n    \"detail\": \"We have a bad request in our endpoint\",    // A human-readable explanation for what exactly happened\n    \"type\": \"https://httpstatuses.io/400\",                // URI reference to identify the problem type\n    \"instance\": \"/sample1\",                               // URI reference of the occurrence\n    \"stackTrace\": \"some more trace for error\",            // More trace information error for what exactly happened\n}\n```\n```go\n    // Response headers\n\n     content-type: application/problem+json\n     date: Thu,29 Sep 2022 14:07:23 GMT \n```\nThere are some samples for using this package on top of Echo [here](./sample/cmd/echo/main.go) and for Gin [here](./sample/cmd/gin/main.go).\n\n## Installation\n\n```bash\ngo get github.com/meysamhadeli/problem-details\n```\n\n## Web-Frameworks\n\n\u003e ### Echo\n\n#### Error Handler:\nFor handling our error we need to specify an `Error Handler` on top of `Echo` framework:\n```go\n// EchoErrorHandler middleware for handle problem details error on echo\nfunc EchoErrorHandler(error error, c echo.Context) {\n\n        // add custom map problem details here...\n\n\t// resolve problem details error from response in echo\n\tif !c.Response().Committed {\n\t\tif _, err := problem.ResolveProblemDetails(c.Response(), c.Request(), error); err != nil {\n\t\t\tlog.Error(err)\n\t\t}\n\t}\n}\n```\n\n#### Map Status Code Error:\n\nIn this sample we map status code `StatusBadGateway` to `StatusUnauthorized` base on handler config to problem details error.\n \n ```go\n// handle specific status code to problem details error\nfunc sample1(c echo.Context) error {\n        err := errors.New(\"We have a specific status code error in our endpoint\")\n\t    return echo.NewHTTPError(http.StatusBadGateway, err)\n}\n ```\n ```go\n// problem details handler config\nproblem.MapStatus(http.StatusBadGateway, func() problem.ProblemDetailErr {\n        return \u0026problem.ProblemDetail{\n            Status: http.StatusUnauthorized,\n            Title:  \"unauthorized\",\n            Detail: error.Error(),\n        }\n})\n ```\n#### Map Custom Type Error:\n\nIn this sample we map custom error type to problem details error. \n\n```go\n// handle custom type error to problem details error\nfunc sample2(c echo.Context) error {\n        err := errors.New(\"We have a custom type error in our endpoint\")\n\treturn custom_errors.BadRequestError{InternalError: err}\n}\n```\n ```go\n// problem details handler config\nproblem.Map[custom_errors.BadRequestError](func() problem.ProblemDetailErr {\n        return \u0026problem.ProblemDetail{\n            Status: http.StatusBadRequest,\n            Title:  \"bad request\",\n            Detail: error.Error(),\n        }\n})\n ```\n\n\u003e ### Gin\n#### Error Handler:\nFor handling our error we need to specify an `Error Handler` on top of `Gin` framework:\n```go\n// GinErrorHandler middleware for handle problem details error on gin\nfunc GinErrorHandler() gin.HandlerFunc {\n\treturn func(c *gin.Context) {\n\n\t\tc.Next()\n\n\t\tfor _, err := range c.Errors {\n\n                        // add custom map problem details here...\n\t\t\t\n\t\t\tif _, err := problem.ResolveProblemDetails(c.Writer, c.Request, err); err != nil {\n\t\t\t\tlog.Error(err)\n\t\t\t}\n\t\t}\n\t}\n}\n```\n\n#### Map Status Code Error:\n\nIn this sample we map status code `StatusBadGateway` to `StatusUnauthorized` base on handler config to problem details error.\n \n ```go\n// handle specific status code to problem details error\nfunc sample1(c *gin.Context) {\n        err := errors.New(\"We have a specific status code error in our endpoint\")\n\t    _ = c.AbortWithError(http.StatusBadGateway, err)\n}\n ```\n```go\n// problem details handler config\nproblem.MapStatus(http.StatusBadGateway, func() problem.ProblemDetailErr {\n        return \u0026problem.ProblemDetail{\n            Status: http.StatusUnauthorized,\n            Title:  \"unauthorized\",\n            Detail: err.Error(),\n        }\n})\n```\n#### Map Custom Type Error:\n\nIn this sample we map custom error type to problem details error. \n\n```go\n// handle custom type error to problem details error\nfunc sample2(c *gin.Context) {\n        err := errors.New(\"We have a custom type error in our endpoint\")\n\tcustomBadRequestError := custom_errors.BadRequestError{InternalError: err}\n\t_ = c.Error(customBadRequestError)\n}\n```\n ```go\n// problem details handler config\nproblem.Map[custom_errors.BadRequestError](func() problem.ProblemDetailErr {\n        return \u0026problem.ProblemDetail{\n            Status: http.StatusBadRequest,\n            Title:  \"bad request\",\n            Detail: err.Error(),\n        }\n})\n ```\n\n\u003e ### Custom Problem Details:\n\nWe support custom problem details error for create more flexibility response error:\n```go\n// custom problem details\ntype CustomProblemDetail struct {\n            problem.ProblemDetailErr\n\t    Description    string `json:\"description,omitempty\"`\n\t    AdditionalInfo string `json:\"additionalInfo,omitempty\"`\n}\n```\n ```go\n// problem details handler config\nproblem.Map[custom_errors.ConflictError](func() problem.ProblemDetailErr {\n        return \u0026custom_problems.CustomProblemDetail{\n            ProblemDetailErr: \u0026problem.ProblemDetail{\n                Status: http.StatusConflict,\n                Title:  \"conflict\",\n                Detail: error.Error(),\n            },\n            AdditionalInfo: \"some additional info...\",\n            Description:    \"some description...\",\n        }\n})\n ```\n\n# Support\n\nIf you like my work, feel free to:\n\n- ⭐ this repository. And we will be happy together :)\n\nThanks a bunch for supporting me!\n\n## Contribution\n\nThanks to all [contributors](https://github.com/meysamhadeli/problem-details/graphs/contributors), you're awesome and this wouldn't be possible without you! The goal is to build a categorized community-driven collection of very well-known resources.\n\nPlease follow this [contribution guideline](./CONTRIBUTION.md) to submit a pull request or create the issue.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeysamhadeli%2Fproblem-details","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmeysamhadeli%2Fproblem-details","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeysamhadeli%2Fproblem-details/lists"}