github.com/openshift-online/ocm-sdk-go@v0.1.473/errors/errors.go (about) 1 /* 2 Copyright (c) 2020 Red Hat, Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // IMPORTANT: This file has been generated automatically, refrain from modifying it manually as all 18 // your changes will be lost when the file is generated again. 19 20 package errors // github.com/openshift-online/ocm-sdk-go/errors 21 22 import ( 23 "fmt" 24 "io" 25 "net/http" 26 "strconv" 27 "strings" 28 "time" 29 30 "github.com/golang/glog" 31 jsoniter "github.com/json-iterator/go" 32 "github.com/openshift-online/ocm-sdk-go/helpers" 33 ) 34 35 // Error kind is the name of the type used to represent errors. 36 const ErrorKind = "Error" 37 38 // ErrorNilKind is the name of the type used to nil errors. 39 const ErrorNilKind = "ErrorNil" 40 41 // ErrorBuilder is a builder for the error type. 42 type ErrorBuilder struct { 43 bitmap_ uint32 44 status int 45 id string 46 href string 47 code string 48 reason string 49 details interface{} 50 operationID string 51 timestamp *time.Time 52 } 53 54 // Error represents errors. 55 type Error struct { 56 bitmap_ uint32 57 status int 58 id string 59 href string 60 code string 61 reason string 62 details interface{} 63 operationID string 64 timestamp *time.Time 65 } 66 67 // NewError creates a new builder that can then be used to create error objects. 68 func NewError() *ErrorBuilder { 69 return &ErrorBuilder{} 70 } 71 72 // Status sets the HTTP status code. 73 func (b *ErrorBuilder) Status(value int) *ErrorBuilder { 74 b.status = value 75 b.bitmap_ |= 1 76 return b 77 } 78 79 // ID sets the identifier of the error. 80 func (b *ErrorBuilder) ID(value string) *ErrorBuilder { 81 b.id = value 82 b.bitmap_ |= 2 83 return b 84 } 85 86 // HREF sets the link of the error. 87 func (b *ErrorBuilder) HREF(value string) *ErrorBuilder { 88 b.href = value 89 b.bitmap_ |= 4 90 return b 91 } 92 93 // Code sets the code of the error. 94 func (b *ErrorBuilder) Code(value string) *ErrorBuilder { 95 b.code = value 96 b.bitmap_ |= 8 97 return b 98 } 99 100 // Reason sets the reason of the error. 101 func (b *ErrorBuilder) Reason(value string) *ErrorBuilder { 102 b.reason = value 103 b.bitmap_ |= 16 104 return b 105 } 106 107 // OperationID sets the identifier of the operation that caused the error. 108 func (b *ErrorBuilder) OperationID(value string) *ErrorBuilder { 109 b.operationID = value 110 b.bitmap_ |= 32 111 return b 112 } 113 114 // Details sets additional details of the error. 115 func (b *ErrorBuilder) Details(value interface{}) *ErrorBuilder { 116 b.details = value 117 b.bitmap_ |= 64 118 return b 119 } 120 121 // Timestamp sets the moment when it happened. 122 func (b *ErrorBuilder) Timestamp(value *time.Time) *ErrorBuilder { 123 b.timestamp = value 124 b.bitmap_ |= 128 125 return b 126 } 127 128 // Copy copies the attributes of the given error into this 129 // builder, discarding any previous values. 130 func (b *ErrorBuilder) Copy(object *Error) *ErrorBuilder { 131 if object == nil { 132 return b 133 } 134 b.bitmap_ = object.bitmap_ 135 b.status = object.status 136 b.id = object.id 137 b.href = object.href 138 b.code = object.code 139 b.reason = object.reason 140 b.details = object.details 141 b.operationID = object.operationID 142 b.timestamp = object.timestamp 143 return b 144 } 145 146 // Build uses the information stored in the builder to create a new error object. 147 func (b *ErrorBuilder) Build() (result *Error, err error) { 148 result = &Error{ 149 status: b.status, 150 id: b.id, 151 href: b.href, 152 code: b.code, 153 reason: b.reason, 154 details: b.details, 155 operationID: b.operationID, 156 timestamp: b.timestamp, 157 bitmap_: b.bitmap_, 158 } 159 return 160 } 161 162 // Kind returns the name of the type of the error. 163 func (e *Error) Kind() string { 164 if e == nil { 165 return ErrorNilKind 166 } 167 return ErrorKind 168 } 169 170 // Status returns the HTTP status code. 171 func (e *Error) Status() int { 172 if e != nil && e.bitmap_&1 != 0 { 173 return e.status 174 } 175 return 0 176 } 177 178 // GetStatus returns the HTTP status code of the error and a flag indicating 179 // if the status has a value. 180 func (e *Error) GetStatus() (value int, ok bool) { 181 ok = e != nil && e.bitmap_&1 != 0 182 if ok { 183 value = e.status 184 } 185 return 186 } 187 188 // ID returns the identifier of the error. 189 func (e *Error) ID() string { 190 if e != nil && e.bitmap_&2 != 0 { 191 return e.id 192 } 193 return "" 194 } 195 196 // GetID returns the identifier of the error and a flag indicating if the 197 // identifier has a value. 198 func (e *Error) GetID() (value string, ok bool) { 199 ok = e != nil && e.bitmap_&2 != 0 200 if ok { 201 value = e.id 202 } 203 return 204 } 205 206 // HREF returns the link to the error. 207 func (e *Error) HREF() string { 208 if e != nil && e.bitmap_&4 != 0 { 209 return e.href 210 } 211 return "" 212 } 213 214 // GetHREF returns the link of the error and a flag indicating if the 215 // link has a value. 216 func (e *Error) GetHREF() (value string, ok bool) { 217 ok = e != nil && e.bitmap_&4 != 0 218 if ok { 219 value = e.href 220 } 221 return 222 } 223 224 // Code returns the code of the error. 225 func (e *Error) Code() string { 226 if e != nil && e.bitmap_&8 != 0 { 227 return e.code 228 } 229 return "" 230 } 231 232 // GetCode returns the link of the error and a flag indicating if the 233 // code has a value. 234 func (e *Error) GetCode() (value string, ok bool) { 235 ok = e != nil && e.bitmap_&8 != 0 236 if ok { 237 value = e.code 238 } 239 return 240 } 241 242 // Reason returns the reason of the error. 243 func (e *Error) Reason() string { 244 if e != nil && e.bitmap_&16 != 0 { 245 return e.reason 246 } 247 return "" 248 } 249 250 // GetReason returns the link of the error and a flag indicating if the 251 // reason has a value. 252 func (e *Error) GetReason() (value string, ok bool) { 253 ok = e != nil && e.bitmap_&16 != 0 254 if ok { 255 value = e.reason 256 } 257 return 258 } 259 260 // OperationID returns the identifier of the operation that caused the error. 261 func (e *Error) OperationID() string { 262 if e != nil && e.bitmap_&32 != 0 { 263 return e.operationID 264 } 265 return "" 266 } 267 268 // GetOperationID returns the identifier of the operation that caused the error and 269 // a flag indicating if that identifier does have a value. 270 func (e *Error) GetOperationID() (value string, ok bool) { 271 ok = e != nil && e.bitmap_&32 != 0 272 if ok { 273 value = e.operationID 274 } 275 return 276 } 277 278 // Details returns the details of the error 279 func (e *Error) Details() interface{} { 280 if e != nil && e.bitmap_&64 != 0 { 281 return e.details 282 } 283 return nil 284 } 285 286 // GetDetails returns the details of the error and a flag 287 // indicating if the details have a value. 288 func (e *Error) GetDetails() (value interface{}, ok bool) { 289 ok = e != nil && e.bitmap_&64 != 0 290 if ok { 291 value = e.details 292 } 293 return 294 } 295 296 // Timestamp sets the moment when it happened 297 func (e *Error) Timestamp() *time.Time { 298 if e != nil && e.bitmap_&128 != 0 { 299 return e.timestamp 300 } 301 return nil 302 } 303 304 // GetTimestamp returns the timestamp of the error and a flag 305 // indicating if the timestamp have a value. 306 func (e *Error) GetTimestamp() (value *time.Time, ok bool) { 307 ok = e != nil && e.bitmap_&128 != 0 308 if ok { 309 value = e.timestamp 310 } 311 return 312 } 313 314 // Error is the implementation of the error interface. 315 // Details are intentionally left out as there is no guarantee of their type 316 func (e *Error) Error() string { 317 chunks := make([]string, 0, 3) 318 if e.bitmap_&1 != 0 { 319 chunks = append(chunks, fmt.Sprintf("status is %d", e.status)) 320 } 321 if e.bitmap_&2 != 0 { 322 chunks = append(chunks, fmt.Sprintf("identifier is '%s'", e.id)) 323 } 324 if e.bitmap_&8 != 0 { 325 chunks = append(chunks, fmt.Sprintf("code is '%s'", e.code)) 326 } 327 if e.bitmap_&128 != 0 { 328 chunks = append(chunks, fmt.Sprintf("at '%v'", e.timestamp.Format(time.RFC3339))) 329 } 330 if e.bitmap_&32 != 0 { 331 chunks = append(chunks, fmt.Sprintf("operation identifier is '%s'", e.operationID)) 332 } 333 var result string 334 size := len(chunks) 335 if size == 1 { 336 result = chunks[0] 337 } else if size > 1 { 338 result = strings.Join(chunks[0:size-1], ", ") + " and " + chunks[size-1] 339 } 340 if e.bitmap_&16 != 0 { 341 if result != "" { 342 result = result + ": " 343 } 344 result = result + e.reason 345 } 346 if result == "" { 347 result = "unknown error" 348 } 349 return result 350 } 351 352 // String returns a string representing the error. 353 func (e *Error) String() string { 354 return e.Error() 355 } 356 357 // UnmarshalError reads an error from the given source which can be an slice of 358 // bytes, a string, a reader or a JSON decoder. 359 func UnmarshalError(source interface{}) (object *Error, err error) { 360 iterator, err := helpers.NewIterator(source) 361 if err != nil { 362 return 363 } 364 object = readError(iterator) 365 err = iterator.Error 366 return 367 } 368 369 // UnmarshalErrorStatus reads an error from the given source and sets 370 // the given status code. 371 func UnmarshalErrorStatus(source interface{}, status int) (object *Error, err error) { 372 object, err = UnmarshalError(source) 373 if err != nil { 374 return 375 } 376 object.status = status 377 object.bitmap_ |= 1 378 return 379 } 380 func readError(iterator *jsoniter.Iterator) *Error { 381 object := &Error{} 382 for { 383 field := iterator.ReadObject() 384 if field == "" { 385 break 386 } 387 switch field { 388 case "status": 389 object.status = iterator.ReadInt() 390 object.bitmap_ |= 1 391 case "id": 392 object.id = iterator.ReadString() 393 object.bitmap_ |= 2 394 case "href": 395 object.href = iterator.ReadString() 396 object.bitmap_ |= 4 397 case "code": 398 object.code = iterator.ReadString() 399 object.bitmap_ |= 8 400 case "reason": 401 object.reason = iterator.ReadString() 402 object.bitmap_ |= 16 403 case "operation_id": 404 object.operationID = iterator.ReadString() 405 object.bitmap_ |= 32 406 case "details": 407 object.details = iterator.ReadAny().GetInterface() 408 object.bitmap_ |= 64 409 case "timestamp": 410 text := iterator.ReadString() 411 value, err := time.Parse(time.RFC3339, text) 412 if err != nil { 413 iterator.ReportError("", err.Error()) 414 } 415 object.timestamp = &value 416 object.bitmap_ |= 128 417 default: 418 iterator.ReadAny() 419 } 420 } 421 return object 422 } 423 424 // MarshalError writes an error to the given writer. 425 func MarshalError(e *Error, writer io.Writer) error { 426 stream := helpers.NewStream(writer) 427 writeError(e, stream) 428 err := stream.Flush() 429 if err != nil { 430 return err 431 } 432 return stream.Error 433 } 434 func writeError(e *Error, stream *jsoniter.Stream) { 435 stream.WriteObjectStart() 436 stream.WriteObjectField("kind") 437 stream.WriteString(ErrorKind) 438 if e.bitmap_&1 != 0 { 439 stream.WriteMore() 440 stream.WriteObjectField("status") 441 stream.WriteInt(e.status) 442 } 443 if e.bitmap_&2 != 0 { 444 stream.WriteMore() 445 stream.WriteObjectField("id") 446 stream.WriteString(e.id) 447 } 448 if e.bitmap_&4 != 0 { 449 stream.WriteMore() 450 stream.WriteObjectField("href") 451 stream.WriteString(e.href) 452 } 453 if e.bitmap_&8 != 0 { 454 stream.WriteMore() 455 stream.WriteObjectField("code") 456 stream.WriteString(e.code) 457 } 458 if e.bitmap_&16 != 0 { 459 stream.WriteMore() 460 stream.WriteObjectField("reason") 461 stream.WriteString(e.reason) 462 } 463 if e.bitmap_&32 != 0 { 464 stream.WriteMore() 465 stream.WriteObjectField("operation_id") 466 stream.WriteString(e.operationID) 467 } 468 if e.bitmap_&64 != 0 { 469 stream.WriteMore() 470 stream.WriteObjectField("details") 471 stream.WriteVal(e.details) 472 } 473 if e.bitmap_&128 != 0 { 474 stream.WriteMore() 475 stream.WriteObjectField("timestamp") 476 stream.WriteVal(e.timestamp) 477 } 478 stream.WriteObjectEnd() 479 } 480 481 var panicID = "1000" 482 var panicError, _ = NewError(). 483 ID(panicID). 484 Reason("An unexpected error happened, please check the log of the service " + 485 "for details"). 486 Build() 487 488 // SendError writes a given error and status code to a response writer. 489 // if an error occurred it will log the error and exit. 490 // This methods is used internaly and no backwards compatibily is guaranteed. 491 func SendError(w http.ResponseWriter, r *http.Request, object *Error) { 492 status, err := strconv.Atoi(object.ID()) 493 if err != nil { 494 SendPanic(w, r) 495 return 496 } 497 w.Header().Set("Content-Type", "application/json") 498 w.WriteHeader(status) 499 err = MarshalError(object, w) 500 if err != nil { 501 glog.Errorf("Can't send response body for request '%s'", r.URL.Path) 502 return 503 } 504 } 505 506 // SendPanic sends a panic error response to the client, but it doesn't end the process. 507 // This methods is used internaly and no backwards compatibily is guaranteed. 508 func SendPanic(w http.ResponseWriter, r *http.Request) { 509 w.Header().Set("Content-Type", "application/json") 510 err := MarshalError(panicError, w) 511 if err != nil { 512 glog.Errorf( 513 "Can't send panic response for request '%s': %s", 514 r.URL.Path, 515 err.Error(), 516 ) 517 } 518 } 519 520 // SendNotFound sends a generic 404 error. 521 func SendNotFound(w http.ResponseWriter, r *http.Request) { 522 reason := fmt.Sprintf( 523 "Can't find resource for path '%s'", 524 r.URL.Path, 525 ) 526 body, err := NewError(). 527 ID("404"). 528 Reason(reason). 529 Build() 530 if err != nil { 531 SendPanic(w, r) 532 return 533 } 534 SendError(w, r, body) 535 } 536 537 // SendMethodNotAllowed sends a generic 405 error. 538 func SendMethodNotAllowed(w http.ResponseWriter, r *http.Request) { 539 reason := fmt.Sprintf( 540 "Method '%s' isn't supported for path '%s'", 541 r.Method, r.URL.Path, 542 ) 543 body, err := NewError(). 544 ID("405"). 545 Reason(reason). 546 Build() 547 if err != nil { 548 SendPanic(w, r) 549 return 550 } 551 SendError(w, r, body) 552 } 553 554 // SendInternalServerError sends a generic 500 error. 555 func SendInternalServerError(w http.ResponseWriter, r *http.Request) { 556 reason := fmt.Sprintf( 557 "Can't process '%s' request for path '%s' due to an internal"+ 558 "server error", 559 r.Method, r.URL.Path, 560 ) 561 body, err := NewError(). 562 ID("500"). 563 Reason(reason). 564 Build() 565 if err != nil { 566 SendPanic(w, r) 567 return 568 } 569 SendError(w, r, body) 570 }