• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

go-fuego / fuego / 12750881970

13 Jan 2025 03:47PM UTC coverage: 93.915% (+0.5%) from 93.455%
12750881970

push

github

dylanhitt
fix: SendYAMLError to properly pass the entire error when sending

1 of 1 new or added line in 1 file covered. (100.0%)

23 existing lines in 2 files now uncovered.

2377 of 2531 relevant lines covered (93.92%)

1.07 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.96
/errors.go
1
package fuego
2

3
import (
4
        "errors"
5
        "fmt"
6
        "log/slog"
7
        "net/http"
8
)
9

10
// ErrorWithStatus is an interface that can be implemented by an error to provide
11
// a status code
12
type ErrorWithStatus interface {
13
        error
14
        StatusCode() int
15
}
16

17
// ErrorWithDetail is an interface that can be implemented by an error to provide
18
// an additional detail message about the error
19
type ErrorWithDetail interface {
20
        error
21
        DetailMsg() string
22
}
23

24
// HTTPError is the error response used by the serialization part of the framework.
25
type HTTPError struct {
26
        // Developer readable error message. Not shown to the user to avoid security leaks.
27
        Err error `json:"-" xml:"-" yaml:"-"`
28
        // URL of the error type. Can be used to lookup the error in a documentation
29
        Type string `json:"type,omitempty" xml:"type,omitempty" yaml:"type,omitempty" description:"URL of the error type. Can be used to lookup the error in a documentation"`
30
        // Short title of the error
31
        Title string `json:"title,omitempty" xml:"title,omitempty" yaml:"title,omitempty" description:"Short title of the error"`
32
        // HTTP status code. If using a different type than [HTTPError], for example [BadRequestError], this will be automatically overridden after Fuego error handling.
33
        Status int `json:"status,omitempty" xml:"status,omitempty" yaml:"status,omitempty" description:"HTTP status code" example:"403"`
34
        // Human readable error message
35
        Detail   string      `json:"detail,omitempty" xml:"detail,omitempty" yaml:"detail,omitempty" description:"Human readable error message"`
36
        Instance string      `json:"instance,omitempty" xml:"instance,omitempty" yaml:"instance,omitempty"`
37
        Errors   []ErrorItem `json:"errors,omitempty" xml:"errors,omitempty" yaml:"errors,omitempty"`
38
}
39

40
type ErrorItem struct {
41
        More   map[string]any `json:"more,omitempty" xml:"more,omitempty" description:"Additional information about the error"`
42
        Name   string         `json:"name" xml:"name" description:"For example, name of the parameter that caused the error"`
43
        Reason string         `json:"reason" xml:"reason" description:"Human readable error message"`
44
}
45

46
func (e HTTPError) Error() string {
1✔
47
        code := e.StatusCode()
1✔
48
        title := e.Title
1✔
49
        if title == "" {
2✔
50
                title = http.StatusText(code)
1✔
51
                if title == "" {
1✔
52
                        title = "HTTP Error"
×
53
                }
×
54
        }
55
        msg := fmt.Sprintf("%d %s", code, title)
1✔
56

1✔
57
        detail := e.DetailMsg()
1✔
58
        if detail == "" {
2✔
59
                return msg
1✔
60
        }
1✔
61

62
        return fmt.Sprintf("%s: %s", msg, e.Detail)
1✔
63
}
64

65
func (e HTTPError) StatusCode() int {
1✔
66
        if e.Status == 0 {
2✔
67
                return http.StatusInternalServerError
1✔
68
        }
1✔
69
        return e.Status
1✔
70
}
71

72
func (e HTTPError) DetailMsg() string {
1✔
73
        return e.Detail
1✔
74
}
1✔
75

76
func (e HTTPError) Unwrap() error { return e.Err }
1✔
77

78
// BadRequestError is an error used to return a 400 status code.
79
type BadRequestError HTTPError
80

81
var _ ErrorWithStatus = BadRequestError{}
82

83
func (e BadRequestError) Error() string { return e.Err.Error() }
1✔
84

85
func (e BadRequestError) StatusCode() int { return http.StatusBadRequest }
1✔
86

87
func (e BadRequestError) Unwrap() error { return HTTPError(e) }
1✔
88

89
// NotFoundError is an error used to return a 404 status code.
90
type NotFoundError HTTPError
91

92
var _ ErrorWithStatus = NotFoundError{}
93

94
func (e NotFoundError) Error() string { return e.Err.Error() }
1✔
95

96
func (e NotFoundError) StatusCode() int { return http.StatusNotFound }
1✔
97

98
func (e NotFoundError) Unwrap() error { return HTTPError(e) }
1✔
99

100
// UnauthorizedError is an error used to return a 401 status code.
101
type UnauthorizedError HTTPError
102

103
var _ ErrorWithStatus = UnauthorizedError{}
104

105
func (e UnauthorizedError) Error() string { return e.Err.Error() }
1✔
106

107
func (e UnauthorizedError) StatusCode() int { return http.StatusUnauthorized }
1✔
108

109
func (e UnauthorizedError) Unwrap() error { return HTTPError(e) }
1✔
110

111
// ForbiddenError is an error used to return a 403 status code.
112
type ForbiddenError HTTPError
113

114
var _ ErrorWithStatus = ForbiddenError{}
115

116
func (e ForbiddenError) Error() string { return e.Err.Error() }
1✔
117

118
func (e ForbiddenError) StatusCode() int { return http.StatusForbidden }
1✔
119

120
func (e ForbiddenError) Unwrap() error { return HTTPError(e) }
1✔
121

122
// ConflictError is an error used to return a 409 status code.
123
type ConflictError HTTPError
124

125
var _ ErrorWithStatus = ConflictError{}
126

127
func (e ConflictError) Error() string { return e.Err.Error() }
1✔
128

129
func (e ConflictError) StatusCode() int { return http.StatusConflict }
1✔
130

131
func (e ConflictError) Unwrap() error { return HTTPError(e) }
1✔
132

133
// InternalServerError is an error used to return a 500 status code.
134
type InternalServerError = HTTPError
135

136
// NotAcceptableError is an error used to return a 406 status code.
137
type NotAcceptableError HTTPError
138

139
var _ ErrorWithStatus = NotAcceptableError{}
140

UNCOV
141
func (e NotAcceptableError) Error() string { return e.Err.Error() }
×
142

UNCOV
143
func (e NotAcceptableError) StatusCode() int { return http.StatusNotAcceptable }
×
144

UNCOV
145
func (e NotAcceptableError) Unwrap() error { return HTTPError(e) }
×
146

147
// ErrorHandler is the default error handler used by the framework.
148
// If the error is an [HTTPError] that error is returned.
149
// If the error adheres to the [ErrorWithStatus] and/or [ErrorWithDetail] interface
150
// the error is transformed to a [HTTPError].
151
// If the error is not an [HTTPError] nor does it adhere to an
152
// interface the error is returned as is.
153
func ErrorHandler(err error) error {
1✔
154
        var errorStatus ErrorWithStatus
1✔
155
        switch {
1✔
156
        case errors.As(err, &HTTPError{}),
157
                errors.As(err, &errorStatus):
1✔
158
                return handleHTTPError(err)
1✔
159
        }
160

161
        return err
1✔
162
}
163

164
func handleHTTPError(err error) HTTPError {
1✔
165
        errResponse := HTTPError{
1✔
166
                Err: err,
1✔
167
        }
1✔
168

1✔
169
        var errorInfo HTTPError
1✔
170
        if errors.As(err, &errorInfo) {
2✔
171
                errResponse = errorInfo
1✔
172
        }
1✔
173

174
        // Check status code
175
        var errorStatus ErrorWithStatus
1✔
176
        if errors.As(err, &errorStatus) {
2✔
177
                errResponse.Status = errorStatus.StatusCode()
1✔
178
        }
1✔
179

180
        // Check for detail
181
        var errorDetail ErrorWithDetail
1✔
182
        if errors.As(err, &errorDetail) {
2✔
183
                errResponse.Detail = errorDetail.DetailMsg()
1✔
184
        }
1✔
185

186
        if errResponse.Title == "" {
2✔
187
                errResponse.Title = http.StatusText(errResponse.Status)
1✔
188
        }
1✔
189

190
        slog.Error("Error "+errResponse.Title, "status", errResponse.StatusCode(), "detail", errResponse.DetailMsg(), "error", errResponse.Err)
1✔
191

1✔
192
        return errResponse
1✔
193
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc