This repository has been archived by the owner on Dec 22, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 84
/
skyerr.go
292 lines (243 loc) · 8.74 KB
/
skyerr.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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
// Copyright 2015-present Oursky Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package skyerr contains information of errors used in skygear.
package skyerr
import (
"encoding/json"
"fmt"
)
// ErrorCode is an integer representation of an error condition
// occurred within the system.
//go:generate stringer -type=ErrorCode
type ErrorCode int
// A list of all expected errors.
//
// Naming convention:
// * Try not to end an error name with "Error"
// * "NotAccepted" refers to information that seems valid but still not accepted for some reason
// * "Bad" refers to information that is malformed or in a corrupted format
// * "Invalid" refers to information that is not correct
const (
// NotAuthenticated is for operations that requires authentication
// but the request is not properly authenticated.
NotAuthenticated ErrorCode = 101 + iota
// PermissionDenied occurs when the requested resource or operation
// exists, but the request is not allowed for some reason.
PermissionDenied
// AccessKeyNotAccepted occurs when the request contains access key
// (API key), but the access key is not accepted.
AccessKeyNotAccepted
// AccessTokenNotAccepted occurs when the request contains access token
// but the access token is not accepted.
AccessTokenNotAccepted
// InvalidCredentials occurs when the information supplied by a user
// to get authenticated is incorrect.
InvalidCredentials
// InvalidSignature is returned by an operation that requires a signature
// and the provided signature is not valid.
InvalidSignature
// BadRequest is an error when the server does not understand the request.
//
// The same error is used for requests that does not conform to HTTP
// protocol.
// The same error may be used for requests that are missing arguments.
BadRequest
// InvalidArgument is an error when the server understand the request,
// but the supplied argument is not valid
InvalidArgument
// Duplicated is an error that occurs when a resource to be saved is
// a duplicate of an existing resource
Duplicated
// ResourceNotFound is returned because the requested resource
// is not found, and this is unlikely due to a failure.
//
// The same error is used for operations that require a critical resource
// to be available, and that resource is specified in the request.
ResourceNotFound
// NotSupported occurs when the server understands the request,
// but the feature is not available due to a known limitation.
//
// Use this when the feature is not likely to be implemented in the near
// future.
NotSupported
// NotImplemented occurs when the server understands the request,
// but the feature is not implemented yet.
//
// Use this when the feature is likely to be implemented in the near
// future.
NotImplemented
// ConstraintViolated occurs when a resource cannot be saved because
// doing so would violate a constraint.
ConstraintViolated
// IncompatibleSchema occurs if because the saving record is incompatible
// with the existing schema.
IncompatibleSchema
// AtomicOperationFailure occurs when a batch operation failed because
// it failed partially, and the batch operation is required to be atomic
AtomicOperationFailure
// PartialOperationFailure occurs when a batch operation failed because
// it failed partially, and the batch operation is not required to be atomic
PartialOperationFailure
// UndefinedOperation is an operation that is not known to the system
UndefinedOperation
// PluginUnavailable occurs when the configured plugin is not available at
// the moment
PluginUnavailable
// PluginTimeout occurs when an operation carried by a plugin is timed out
PluginTimeout
// QueryInvalid is returned when information contained in a record query
// is not valid. Examples include referencing keypath that is invalid, and
// unsupported comparison.
RecordQueryInvalid
// Error codes for expected error condition should be placed
// above this line.
)
// A list of unexpected errors.
const (
// UnexpectedError is for an error that is not likely to happen or
// an error that cannot be classified into any other error type.
//
// Refrain from using this error code.
UnexpectedError ErrorCode = 10000 + iota
UnexpectedUserInfoNotFound
UnexpectedUnableToOpenDatabase
UnexpectedPushNotificationNotConfigured
InternalQueryInvalid
// Error codes for unexpected error condition should be placed
// above this line.
)
// Error specifies the interfaces required by an error in skygear
type Error interface {
Name() string
Code() ErrorCode
Message() string
Info() map[string]interface{}
error
json.Marshaler
}
// genericError is an intuitive implementation of Error that contains
// an code and error message.
type genericError struct {
code ErrorCode
message string
info map[string]interface{}
}
// NewError returns an error suitable to be returned to the client
func NewError(code ErrorCode, message string) Error {
return NewErrorWithInfo(code, message, nil)
}
// NewErrorf returns an Error
func NewErrorf(code ErrorCode, message string, a ...interface{}) Error {
return NewError(code, fmt.Sprintf(message, a...))
}
// NewErrorWithInfo returns an Error
func NewErrorWithInfo(code ErrorCode, message string, info map[string]interface{}) Error {
return &genericError{
code: code,
message: message,
info: info,
}
}
// NewInvalidArgument is a convenient function to returns an invalid argument
// error with a list of arguments that are invalid.
func NewInvalidArgument(message string, arguments []string) Error {
return &genericError{
code: InvalidArgument,
message: message,
info: map[string]interface{}{
"arguments": arguments,
},
}
}
func newNotFoundErr(code ErrorCode, message string) Error {
return NewError(code, message)
}
// MakeError returns an Error interface with the specified error. If the
// specified error already implements the Error interface, the specified error
// is returned.
//
// For specified error of other kinds, the returned error always have code
// `UnexpectedError`.
func MakeError(err error) Error {
if skyError, ok := err.(Error); ok {
return skyError
}
return NewError(UnexpectedError, err.Error())
}
// NewRequestJSONInvalidErr returns new RequestJSONInvalid Error
func NewRequestJSONInvalidErr(err error) Error {
return NewError(BadRequest, err.Error())
}
// NewResourceFetchFailureErr returns a new ResourceFetchFailure Error
func NewResourceFetchFailureErr(kind string, id interface{}) Error {
return NewError(UnexpectedError, fmt.Sprintf("failed to fetch %v id = %v", kind, id))
}
func newResourceSaveFailureErr(kind string, id interface{}) Error {
var message string
if id != nil {
message = fmt.Sprintf("failed to save %v id = %v", kind, id)
} else {
message = "failed to save " + kind
}
return NewError(UnexpectedError, message)
}
// NewResourceSaveFailureErrWithStringID returns a new ResourceSaveFailure Error
// with the specified kind and string id in the error message
func NewResourceSaveFailureErrWithStringID(kind string, id string) Error {
var iID interface{}
if id != "" {
iID = id
}
return newResourceSaveFailureErr(kind, iID)
}
func newResourceDeleteFailureErr(kind string, id interface{}) Error {
var message string
if id != nil {
message = fmt.Sprintf("failed to delete %v id = %v", kind, id)
} else {
message = "failed to delete " + kind
}
return NewError(UnexpectedError, message)
}
// NewResourceDeleteFailureErrWithStringID returns a new ResourceDeleteFailure Error
func NewResourceDeleteFailureErrWithStringID(kind string, id string) Error {
var iID interface{}
if id != "" {
iID = id
}
return newResourceDeleteFailureErr(kind, iID)
}
func (e *genericError) Name() string {
return fmt.Sprintf("%v", e.code)
}
func (e *genericError) Code() ErrorCode {
return e.code
}
func (e *genericError) Message() string {
return e.message
}
func (e *genericError) Info() map[string]interface{} {
return e.info
}
func (e *genericError) Error() string {
return fmt.Sprintf("%v: %v", e.code, e.message)
}
func (e *genericError) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Name string `json:"name"`
Code ErrorCode `json:"code"`
Message string `json:"message"`
Info map[string]interface{} `json:"info,omitempty"`
}{e.Name(), e.Code(), e.Message(), e.Info()})
}