1package autorest
2
3// Copyright 2017 Microsoft Corporation
4//
5//  Licensed under the Apache License, Version 2.0 (the "License");
6//  you may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at
8//
9//      http://www.apache.org/licenses/LICENSE-2.0
10//
11//  Unless required by applicable law or agreed to in writing, software
12//  distributed under the License is distributed on an "AS IS" BASIS,
13//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14//  See the License for the specific language governing permissions and
15//  limitations under the License.
16
17import (
18	"fmt"
19	"net/http"
20)
21
22const (
23	// UndefinedStatusCode is used when HTTP status code is not available for an error.
24	UndefinedStatusCode = 0
25)
26
27// DetailedError encloses a error with details of the package, method, and associated HTTP
28// status code (if any).
29type DetailedError struct {
30	Original error
31
32	// PackageType is the package type of the object emitting the error. For types, the value
33	// matches that produced the the '%T' format specifier of the fmt package. For other elements,
34	// such as functions, it is just the package name (e.g., "autorest").
35	PackageType string
36
37	// Method is the name of the method raising the error.
38	Method string
39
40	// StatusCode is the HTTP Response StatusCode (if non-zero) that led to the error.
41	StatusCode interface{}
42
43	// Message is the error message.
44	Message string
45
46	// Service Error is the response body of failed API in bytes
47	ServiceError []byte
48
49	// Response is the response object that was returned during failure if applicable.
50	Response *http.Response
51}
52
53// NewError creates a new Error conforming object from the passed packageType, method, and
54// message. message is treated as a format string to which the optional args apply.
55func NewError(packageType string, method string, message string, args ...interface{}) DetailedError {
56	return NewErrorWithError(nil, packageType, method, nil, message, args...)
57}
58
59// NewErrorWithResponse creates a new Error conforming object from the passed
60// packageType, method, statusCode of the given resp (UndefinedStatusCode if
61// resp is nil), and message. message is treated as a format string to which the
62// optional args apply.
63func NewErrorWithResponse(packageType string, method string, resp *http.Response, message string, args ...interface{}) DetailedError {
64	return NewErrorWithError(nil, packageType, method, resp, message, args...)
65}
66
67// NewErrorWithError creates a new Error conforming object from the
68// passed packageType, method, statusCode of the given resp (UndefinedStatusCode
69// if resp is nil), message, and original error. message is treated as a format
70// string to which the optional args apply.
71func NewErrorWithError(original error, packageType string, method string, resp *http.Response, message string, args ...interface{}) DetailedError {
72	if v, ok := original.(DetailedError); ok {
73		return v
74	}
75
76	statusCode := UndefinedStatusCode
77	if resp != nil {
78		statusCode = resp.StatusCode
79	}
80
81	return DetailedError{
82		Original:    original,
83		PackageType: packageType,
84		Method:      method,
85		StatusCode:  statusCode,
86		Message:     fmt.Sprintf(message, args...),
87		Response:    resp,
88	}
89}
90
91// Error returns a formatted containing all available details (i.e., PackageType, Method,
92// StatusCode, Message, and original error (if any)).
93func (e DetailedError) Error() string {
94	if e.Original == nil {
95		return fmt.Sprintf("%s#%s: %s: StatusCode=%d", e.PackageType, e.Method, e.Message, e.StatusCode)
96	}
97	return fmt.Sprintf("%s#%s: %s: StatusCode=%d -- Original Error: %v", e.PackageType, e.Method, e.Message, e.StatusCode, e.Original)
98}
99