Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add problem library #2

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
44 changes: 43 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# PlayNet Libs

[![Go Report Card](https://goreportcard.com/badge/github.com/playnet-public/libs)](https://goreportcard.com/report/github.com/playnet-public/libs)
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
[![Build Status](https://travis-ci.org/playnet-public/libs.svg?branch=master)](https://travis-ci.org/playnet-public/libs)
Expand All @@ -9,7 +10,8 @@ The repository containing various shared libs for the entire playnet project.
## Libs

### Logging
Our logging setup using go.uber.org/zap.

Our logging setup using `go.uber.org/zap`.
Sentry and Jaeger are being added for production environments.

```go
Expand All @@ -27,6 +29,46 @@ If you provide a zap.Error tag, the related stacktrace will also be attached.

Additionally there is a tracer(opentracing/jaeger) available in the logger which should be closed before exiting main.

### Problems

`problems` is a small library which implements the RFC7807 error response format standard for e.g. HTTP API's.

The `problems` lib provides a struct called `Problem` and an interface called `ProblemInfo`.
`Problem` implements the `error` interface, so you can simply return the problem as an error in your application.

```go
func returnError() error {
return problems.New()
}
```

You can marshal the `Problem` struct to JSON:

```go
func makeJSON(problem *Problem) ([]byte, error) {
return json.Marshal(&problem)
}
```

If you want to define a HTTP problem, you can do it like this:

```go
var problemNotFound = problems.New().SetTitle("NotFound").SetDetail("The requested url was not found.").SetStatus(404).SetType("https://example.com/problem/description")
```

For custom fields for more detailed problem information, you can implement `Problem` in your custom struct:

```go
type customInfo struct {
AdditionalField1 bool `json:"additional_field_1"`
}

type customProblem struct {
*problems.Problem
pixlcrashr marked this conversation as resolved.
Show resolved Hide resolved
*customInfo
}
```

## Contributions

Pull Requests and Issue Reports are welcome.
Expand Down
74 changes: 74 additions & 0 deletions problems/problems.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package errors
pixlcrashr marked this conversation as resolved.
Show resolved Hide resolved

import (
"fmt"
)

//Problem implements the RFC7807 "problem"/error standard
//Additional error field can be defined in custom struct implementing the Problem struct
type Problem struct {
pixlcrashr marked this conversation as resolved.
Show resolved Hide resolved
Title string `json:"title"`
Detail string `json:"detail,omitempty"`
Type string `json:"type,omitempty"`
Instance string `json:"instance,omitempty"`
Status int `json:"status,omitempty"`
}

//Error implements the error interface
func (p *Problem) Error() string {
pixlcrashr marked this conversation as resolved.
Show resolved Hide resolved
return fmt.Sprintf("Title: %s; Detail: %s", p.Title, p.Detail)
}

//DefaultType implements the default type content described in RFC7807
const DefaultType = "about:blank"

pixlcrashr marked this conversation as resolved.
Show resolved Hide resolved
//SetTitle sets the title of the problem object
func (p *Problem) SetTitle(title string) *Problem {
p.Title = title
return p
}

//SetDetail sets the detail info of the problem object
pixlcrashr marked this conversation as resolved.
Show resolved Hide resolved
func (p *Problem) SetDetail(detail string) *Problem {
p.Detail = detail
return p
}

//SetType sets the type of the problem object
func (p *Problem) SetType(typ string) *Problem {
pixlcrashr marked this conversation as resolved.
Show resolved Hide resolved
if typ == "" {
p.Type = DefaultType
} else {
p.Type = typ
}

return p
}

//SetInstance sets the instance of the problem object
func (p *Problem) SetInstance(instance string) *Problem {
p.Instance = instance
return p
}

//SetStatus sets the HTTP status of the problem object HTTP request
func (p *Problem) SetStatus(status int) *Problem {
p.Status = status
return p
}

//New creates a new Problem with all object details described in RFC7807
pixlcrashr marked this conversation as resolved.
Show resolved Hide resolved
func New() *Problem {
return &Problem{
Type: DefaultType,
}
}

//NewFromError returns a new Problem object from an error interface
//The error message is replaced with the detail field
func NewFromError(err error) *Problem {
return &Problem{
Type: DefaultType,
Detail: err.Error(),
}
}