Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions DESIGN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
Design for go-errors refactor

# Introduction
The main objective of this refactor is to ease the usage of go-errors library, with key points
* One unique function with argument for standard error and go-errors
* Variadic options following the "Functional Options" pattern
* An error code, obtained by concatenating identifiers defined at each calls of subfunctions, that allow tracing the root cause
* Comply with error interface (Error() string)

# One unique function
The signature of this unique function would be:
```go
func Wrap(error, errors.Opts...) error
```
Where error can be of type
1. standard errors
2. go-errors

## standard errors
The provided error will be considered as a root error and stored as cause of a new go-errors one

## go-errors
The provided error will be considered as a template for a new go-errors one

# Variadic Options
The variadic options would be the following one

* `WithDetail`/`WithDetailf`: provide a message that details the error
* `WithProperty`: provide a key/value pair for additional informations (filename, path, username, ... )
* `WithIdentifier`: used to provide an identifer, it could be concatenated with other idenfier from previous calls from subfunctions (See example below for clarity)

Signature could be as follow

```go
errors.WithDetail(string)
errors.WithDetailf(string, ...any)
errors.WithProperty(string, any)
errors.WithIdentifier(int)
```

# Identifier

Below an example of using `go-errors` with identifier.
Also, find the expected error message

```go
package main

import (
"fmt"

errors "github.com/scality/go-errors"
)

var ErrForbidden = errors.New("forbidden")

func main(){
err := appel1()
fmt.Println(err)
}
func appel1() error {
return errors.Wrap(
appel2(),
errors.WithIdentifier(19),
)
}

func appel2() error {
return errors.Wrap(
appel3(),
errors.WithDetail("missing required role"),
errors.WithProperty("Role", "Reader"),
errors.WithProperty("User", "john.doe"),
errors.WithIdentifier(12),
)
}

func appel3() error {
// Something went wrong here
return errors.Wrap(
ErrForbidden,
errors.WithIdentifer(2),
errors.WithDetail("permission denied"),
errors.WithProperty("File", "test.txt"),
)
}
```

In the following situation, the program would return
```
forbidden (19-12-2): permission denied: missing required role: File='test.txt', User='john.doe', Role:'Reader', at=(func='main.appel3', file='main.go', line='270')
```