@@ -3,7 +3,9 @@ package scw
33import (
44 "encoding/json"
55 "fmt"
6+ "io/ioutil"
67 "net/http"
8+ "strings"
79
810 "github.com/scaleway/scaleway-sdk-go/internal/errors"
911)
@@ -71,10 +73,137 @@ func hasResponseError(res *http.Response) SdkError {
7173 return newErr
7274 }
7375
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 )
7582 if err != nil {
7683 return errors .Wrap (err , "could not parse error response body" )
7784 }
85+ stdErr := unmarshalStandardError (newErr .Type , body )
86+ if stdErr != nil {
87+ return stdErr
88+ }
7889
7990 return newErr
8091}
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