Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/josestg/problemdetail
An idiomatic implementation of Problem Details for HTTP APIs (RFC 7807) for Go.
https://github.com/josestg/problemdetail
http-error-handling problem-details problem-details-for-http-apis
Last synced: 19 days ago
JSON representation
An idiomatic implementation of Problem Details for HTTP APIs (RFC 7807) for Go.
- Host: GitHub
- URL: https://github.com/josestg/problemdetail
- Owner: josestg
- License: gpl-3.0
- Created: 2023-10-13T15:35:40.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2023-10-15T08:26:58.000Z (about 1 year ago)
- Last Synced: 2024-10-28T09:35:08.245Z (about 2 months ago)
- Topics: http-error-handling, problem-details, problem-details-for-http-apis
- Language: Go
- Homepage: https://github.com/josestg/problemdetail
- Size: 21.5 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Problem Details
This package implements [RFC 7807](https://datatracker.ietf.org/doc/html/rfc7807) (Problem Details for HTTP APIs) for Go.
It provides an idiomatic way to use RFC 7807 in Go and offers both JSON and XML writers.## Installation
```bash
go get github.com/josestg/problemdetail
```## Examples
### Problem Details as an Error
```go
const (
TypOutOfCredit = "https://example.com/probs/out-of-credit"
TypProductNotFound = "https://example.com/probs/product-not-found"
)func service() error {
// do something...// simulate 30% error rate for each type of error.
n := rand.Intn(9)
if n < 3 {
return problemdetail.New(TypOutOfCredit,
problemdetail.WithValidateLevel(problemdetail.LStandard),
problemdetail.WithTitle("You do not have enough credit."),
problemdetail.WithDetail("Your current balance is 30, but that costs 50."),
)
}if n < 6 {
return problemdetail.New(TypProductNotFound,
problemdetail.WithValidateLevel(problemdetail.LStandard),
problemdetail.WithTitle("The product was not found."),
problemdetail.WithDetail("The product you requested was not found in the system."),
)
}return errors.New("unknown error")
}// handler is a sample handler for HTTP server.
// you can make this as a centralized error handler middleware.
func handler(w http.ResponseWriter, _ *http.Request) {
err := service()
if err != nil {
// read the error as problemdetail.ProblemDetailer.
var pd problemdetail.ProblemDetailer
if !errors.As(err, &pd) {
// untyped error for generic error handling.
untyped := problemdetail.New(
problemdetail.Untyped,
problemdetail.WithValidateLevel(problemdetail.LStandard),
)
_ = problemdetail.WriteJSON(w, untyped, http.StatusInternalServerError)
return
}// typed error for specific error handling.
switch pd.Kind() {
case TypOutOfCredit:
_ = problemdetail.WriteJSON(w, pd, http.StatusForbidden)
// or problemdetail.WriteXML(w, pd, http.StatusForbidden) for XML
case TypProductNotFound:
_ = problemdetail.WriteJSON(w, pd, http.StatusNotFound)
}
return
}
w.WriteHeader(http.StatusOK)
}func main() {
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
```### Problem Details with Extensions
```go
const (
TypOutOfCredit = "https://example.com/probs/out-of-credit"
TypProductNotFound = "https://example.com/probs/product-not-found"
)// BalanceProblemDetail is a sample problem detail with extension by embedding ProblemDetail.
type BalanceProblemDetail struct {
*problemdetail.ProblemDetail
Balance int64 `json:"balance" xml:"balance"`
Accounts []string `json:"accounts" xml:"accounts"`
}func service() error {
// do something...// simulate 30% error rate for each type of error.
n := rand.Intn(9)
if n < 3 {
pd := problemdetail.New(TypOutOfCredit,
problemdetail.WithValidateLevel(problemdetail.LStandard),
problemdetail.WithTitle("You do not have enough credit."),
problemdetail.WithDetail("Your current balance is 30, but that costs 50."),
)
return &BalanceProblemDetail{
ProblemDetail: pd,
Balance: 30,
Accounts: []string{"/account/12345", "/account/67890"},
}
}if n < 6 {
return problemdetail.New(TypProductNotFound,
problemdetail.WithValidateLevel(problemdetail.LStandard),
problemdetail.WithTitle("The product was not found."),
problemdetail.WithDetail("The product you requested was not found in the system."),
)
}return errors.New("unknown error")
}// handler is a sample handler for HTTP server.
// you can make this as a centralized error handler middleware.
func handler(w http.ResponseWriter, _ *http.Request) {
err := service()
if err != nil {
// read the error as problemdetail.ProblemDetailer.
var pd problemdetail.ProblemDetailer
if !errors.As(err, &pd) {
// untyped error for generic error handling.
untyped := problemdetail.New(
problemdetail.Untyped,
problemdetail.WithValidateLevel(problemdetail.LStandard),
)
_ = problemdetail.WriteJSON(w, untyped, http.StatusInternalServerError)
return
}// typed error for specific error handling.
switch pd.Kind() {
case TypOutOfCredit:
_ = problemdetail.WriteJSON(w, pd, http.StatusForbidden)
// or problemdetail.WriteXML(w, pd, http.StatusForbidden) for XML
case TypProductNotFound:
_ = problemdetail.WriteJSON(w, pd, http.StatusNotFound)
}
return
}
w.WriteHeader(http.StatusOK)
}func main() {
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
```