This repository has been archived by the owner on Mar 11, 2021. It is now read-only.
/
jsonapi_utility.go
171 lines (156 loc) · 5.15 KB
/
jsonapi_utility.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package jsonapi
import (
"context"
"net/http"
"strconv"
"github.com/fabric8-services/fabric8-auth/app"
"github.com/fabric8-services/fabric8-auth/errors"
"github.com/fabric8-services/fabric8-auth/log"
"github.com/goadesign/goa"
errs "github.com/pkg/errors"
)
const (
ErrorCodeNotFound = "not_found"
ErrorCodeBadParameter = "bad_parameter"
ErrorCodeVersionConflict = "version_conflict"
ErrorCodeDataConflict = "data_conflict"
ErrorCodeUnknownError = "unknown_error"
ErrorCodeConversionError = "conversion_error"
ErrorCodeInternalError = "internal_error"
ErrorCodeUnauthorizedError = "unauthorized_error"
ErrorCodeForbiddenError = "forbidden_error"
ErrorCodeJWTSecurityError = "jwt_security_error"
)
// ErrorToJSONAPIError returns the JSONAPI representation
// of an error and the HTTP status code that will be associated with it.
// This function knows about the models package and the errors from there
// as well as goa error classes.
func ErrorToJSONAPIError(ctx context.Context, err error) (app.JSONAPIError, int) {
cause := errs.Cause(err)
detail := cause.Error()
var title, code string
var statusCode int
var id *string
log.Info(ctx, map[string]interface{}{"err": cause, "error_message": cause.Error()}, "an error occurred in our api")
switch cause.(type) {
case errors.NotFoundError:
code = ErrorCodeNotFound
title = "Not found error"
statusCode = http.StatusNotFound
case errors.ConversionError:
code = ErrorCodeConversionError
title = "Conversion error"
statusCode = http.StatusBadRequest
case errors.BadParameterError:
code = ErrorCodeBadParameter
title = "Bad parameter error"
statusCode = http.StatusBadRequest
case errors.VersionConflictError:
code = ErrorCodeVersionConflict
title = "Version conflict error"
statusCode = http.StatusConflict
case errors.DataConflictError:
code = ErrorCodeDataConflict
title = "Data conflict error"
statusCode = http.StatusConflict
case errors.InternalError:
code = ErrorCodeInternalError
title = "Internal error"
statusCode = http.StatusInternalServerError
case errors.UnauthorizedError:
code = ErrorCodeUnauthorizedError
title = "Unauthorized error"
statusCode = http.StatusUnauthorized
case errors.ForbiddenError:
code = ErrorCodeForbiddenError
title = "Forbidden error"
statusCode = http.StatusForbidden
default:
code = ErrorCodeUnknownError
title = "Unknown error"
statusCode = http.StatusInternalServerError
cause := errs.Cause(err)
if err, ok := cause.(goa.ServiceError); ok {
statusCode = err.ResponseStatus()
idStr := err.Token()
id = &idStr
title = http.StatusText(statusCode)
}
if errResp, ok := cause.(*goa.ErrorResponse); ok {
code = errResp.Code
detail = errResp.Detail
}
}
statusCodeStr := strconv.Itoa(statusCode)
jerr := app.JSONAPIError{
ID: id,
Code: &code,
Status: &statusCodeStr,
Title: &title,
Detail: detail,
}
return jerr, statusCode
}
// ErrorToJSONAPIErrors is a convenience function if you
// just want to return one error from the models package as a JSONAPI errors
// array.
func ErrorToJSONAPIErrors(ctx context.Context, err error) (*app.JSONAPIErrors, int) {
jerr, httpStatusCode := ErrorToJSONAPIError(ctx, err)
jerrors := app.JSONAPIErrors{}
jerrors.Errors = append(jerrors.Errors, &jerr)
return &jerrors, httpStatusCode
}
// BadRequest represent a Context that can return a BadRequest HTTP status
type BadRequest interface {
BadRequest(*app.JSONAPIErrors) error
}
// InternalServerError represent a Context that can return a InternalServerError HTTP status
type InternalServerError interface {
context.Context
InternalServerError(*app.JSONAPIErrors) error
}
// NotFound represent a Context that can return a NotFound HTTP status
type NotFound interface {
NotFound(*app.JSONAPIErrors) error
}
// Unauthorized represent a Context that can return a Unauthorized HTTP status
type Unauthorized interface {
Unauthorized(*app.JSONAPIErrors) error
}
// Forbidden represent a Context that can return a Unauthorized HTTP status
type Forbidden interface {
Forbidden(*app.JSONAPIErrors) error
}
// Conflict represent a Context that can return a Conflict HTTP status
type Conflict interface {
Conflict(*app.JSONAPIErrors) error
}
// JSONErrorResponse auto maps the provided error to the correct response type
// If all else fails, InternalServerError is returned
func JSONErrorResponse(ctx InternalServerError, err error) error {
jsonErr, status := ErrorToJSONAPIErrors(ctx, err)
switch status {
case http.StatusBadRequest:
if ctx, ok := ctx.(BadRequest); ok {
return errs.WithStack(ctx.BadRequest(jsonErr))
}
case http.StatusNotFound:
if ctx, ok := ctx.(NotFound); ok {
return errs.WithStack(ctx.NotFound(jsonErr))
}
case http.StatusUnauthorized:
if ctx, ok := ctx.(Unauthorized); ok {
return errs.WithStack(ctx.Unauthorized(jsonErr))
}
case http.StatusForbidden:
if ctx, ok := ctx.(Forbidden); ok {
return errs.WithStack(ctx.Forbidden(jsonErr))
}
case http.StatusConflict:
if ctx, ok := ctx.(Conflict); ok {
return errs.WithStack(ctx.Conflict(jsonErr))
}
}
// sentry.Sentry().CaptureError(ctx, err)
return errs.WithStack(ctx.InternalServerError(jsonErr))
}