@@ -3,7 +3,9 @@ package scw
3
3
import (
4
4
"encoding/json"
5
5
"fmt"
6
+ "io/ioutil"
6
7
"net/http"
8
+ "strings"
7
9
8
10
"github.com./scaleway/scaleway-sdk-go/internal/errors"
9
11
)
@@ -71,10 +73,137 @@ func hasResponseError(res *http.Response) SdkError {
71
73
return newErr
72
74
}
73
75
74
- err := json .NewDecoder (res .Body ).Decode (newErr )
76
+ body , err := ioutil .ReadAll (res .Body )
77
+ if err != nil {
78
+ return errors .Wrap (err , "cannot read error response body" )
79
+ }
80
+
81
+ err = json .Unmarshal (body , newErr )
75
82
if err != nil {
76
83
return errors .Wrap (err , "could not parse error response body" )
77
84
}
85
+ stdErr := unmarshalStandardError (newErr .Type , body )
86
+ if stdErr != nil {
87
+ return stdErr
88
+ }
78
89
79
90
return newErr
80
91
}
92
+
93
+ func unmarshalStandardError (errorType string , body []byte ) SdkError {
94
+ var stdErr SdkError
95
+
96
+ switch errorType {
97
+ case "invalid_arguments" :
98
+ stdErr = & InvalidArgumentsError {}
99
+ case "quotas_exceeded" :
100
+ stdErr = & QuotasExceededError {}
101
+ case "transient_state" :
102
+ stdErr = & TransientStateError {}
103
+ case "not_found" :
104
+ stdErr = & ResourceNotFound {}
105
+ case "permissions_denied" :
106
+ stdErr = & PermissionsDeniedError {}
107
+ default :
108
+ return nil
109
+ }
110
+
111
+ err := json .Unmarshal (body , stdErr )
112
+ if err != nil {
113
+ return errors .Wrap (err , "could not parse error %s response body" , errorType )
114
+ }
115
+
116
+ return stdErr
117
+ }
118
+
119
+ type InvalidArgumentsError struct {
120
+ Details []struct {
121
+ ArgumentName string `json:"argument_name"`
122
+ Reason string `json:"reason"`
123
+ HelpMessage string `json:"help_message"`
124
+ } `json:"details"`
125
+ }
126
+
127
+ // IsScwSdkError implements the SdkError interface
128
+ func (e * InvalidArgumentsError ) IsScwSdkError () {}
129
+ func (e * InvalidArgumentsError ) Error () string {
130
+ invalidArgs := make ([]string , len (e .Details ))
131
+ for i , d := range e .Details {
132
+ invalidArgs [i ] = d .ArgumentName
133
+ switch d .Reason {
134
+ case "unknown" :
135
+ invalidArgs [i ] += " is invalid for unexpected reason"
136
+ case "required" :
137
+ invalidArgs [i ] += " is required"
138
+ case "format" :
139
+ invalidArgs [i ] += " is wrongly formatted"
140
+ case "constraint" :
141
+ invalidArgs [i ] += " does not respect constraint"
142
+ }
143
+ if d .HelpMessage != "" {
144
+ invalidArgs [i ] += ", " + d .HelpMessage
145
+ }
146
+ }
147
+
148
+ return "scaleway-sdk-go: invalid argument(s): " + strings .Join (invalidArgs , "; " )
149
+ }
150
+
151
+ type QuotasExceededError struct {
152
+ Details []struct {
153
+ Resource string `json:"resource"`
154
+ Quota uint32 `json:"quota"`
155
+ Current uint32 `json:"current"`
156
+ } `json:"details"`
157
+ }
158
+
159
+ // IsScwSdkError implements the SdkError interface
160
+ func (e * QuotasExceededError ) IsScwSdkError () {}
161
+ func (e * QuotasExceededError ) Error () string {
162
+ invalidArgs := make ([]string , len (e .Details ))
163
+ for i , d := range e .Details {
164
+ invalidArgs [i ] = fmt .Sprintf ("%s has reached its quota (%d/%d)" , d .Resource , d .Current , d .Current )
165
+ }
166
+
167
+ return "scaleway-sdk-go: quota exceeded(s): " + strings .Join (invalidArgs , "; " )
168
+ }
169
+
170
+ type PermissionsDeniedError struct {
171
+ Details []struct {
172
+ Resource string `json:"resource"`
173
+ Action string `json:"action"`
174
+ } `json:"details"`
175
+ }
176
+
177
+ // IsScwSdkError implements the SdkError interface
178
+ func (e * PermissionsDeniedError ) IsScwSdkError () {}
179
+ func (e * PermissionsDeniedError ) Error () string {
180
+ invalidArgs := make ([]string , len (e .Details ))
181
+ for i , d := range e .Details {
182
+ invalidArgs [i ] = fmt .Sprintf ("%s %s" , d .Action , d .Resource )
183
+ }
184
+
185
+ return "scaleway-sdk-go: insufficient permissions: " + strings .Join (invalidArgs , "; " )
186
+ }
187
+
188
+ type TransientStateError struct {
189
+ Resource string `json:"resource"`
190
+ ResourceID string `json:"resource_id"`
191
+ CurrentState string `json:"current_state"`
192
+ }
193
+
194
+ // IsScwSdkError implements the SdkError interface
195
+ func (e * TransientStateError ) IsScwSdkError () {}
196
+ func (e * TransientStateError ) Error () string {
197
+ return fmt .Sprintf ("scaleway-sdk-go: resource %s with ID %s is in a transient state: %s" , e .Resource , e .ResourceID , e .CurrentState )
198
+ }
199
+
200
+ type ResourceNotFound struct {
201
+ Resource string `json:"resource"`
202
+ ResourceID string `json:"resource_id"`
203
+ }
204
+
205
+ // IsScwSdkError implements the SdkError interface
206
+ func (e * ResourceNotFound ) IsScwSdkError () {}
207
+ func (e * ResourceNotFound ) Error () string {
208
+ return fmt .Sprintf ("scaleway-sdk-go: resource %s with ID %s is not found" , e .Resource , e .ResourceID )
209
+ }
0 commit comments