@@ -8,146 +8,37 @@ package api
88
99import (
1010 "context"
11- "fmt"
1211 "net/http"
13- "reflect"
14- "strings"
15-
16- "github.com/perimeterx/marshmallow"
1712
1813 "github.com/ARM-software/embedded-development-services-client-utils/utils/errors"
19- "github.com/ARM-software/golang-utils/utils/commonerrors"
20- "github.com/ARM-software/golang-utils/utils/parallelisation"
21- "github.com/ARM-software/golang-utils/utils/reflection"
22- "github.com/ARM-software/golang-utils/utils/safeio"
14+ "github.com/ARM-software/golang-utils/utils/http/api"
2315)
2416
25- const requiredFieldError = "no value given for required property"
26-
17+ // Deprecated: Use github.com/ARM-software/golang-utils/utils/http/api instead
2718// IsCallSuccessful determines whether an API response is successful or not
2819func IsCallSuccessful (r * http.Response ) bool {
29- if r == nil {
30- return false
31- }
32- return r .StatusCode >= http .StatusOK && r .StatusCode < http .StatusMultipleChoices
20+ return api .IsCallSuccessful (r )
3321}
3422
3523// CheckAPICallSuccess verifies whether an API response is successful or not and if not, populates an error with all the information needed.
3624// errorContext corresponds to the description of what led to the error if error there is e.g. `Failed adding a user`.
3725// resp corresponds to the HTTP response from a certain endpoint. The body of such response is not closed by this function.
3826// apiErr corresponds to the error which may be returned by the HTTP client when calling the endpoint.
39- func CheckAPICallSuccess (ctx context.Context , errorContext string , resp * http.Response , apiErr error ) (err error ) {
40- err = parallelisation .DetermineContextError (ctx )
41- if err != nil {
42- return
43- }
44- if ! IsCallSuccessful (resp ) {
45- statusCode := 0
46- errorMessage := strings.Builder {}
47- respErr := commonerrors .ErrUnexpected
48- if resp != nil {
49- statusCode = resp .StatusCode
50- respErr = errors .MapErrorToHTTPResponseCode (statusCode )
51- if respErr == nil {
52- respErr = commonerrors .ErrUnexpected
53- }
54- errorDetails , subErr := errors .FetchAPIErrorDescriptionWithContext (ctx , resp )
55- if commonerrors .Ignore (subErr , commonerrors .ErrMarshalling ) != nil {
56- err = commonerrors .Join (commonerrors .New (respErr , errorContext ), subErr )
57- return
58- }
59- if ! reflection .IsEmpty (errorDetails ) {
60- errorMessage .WriteString (errorDetails )
61- }
62- _ = resp .Body .Close ()
63- }
64- extra := ""
65- if apiErr != nil {
66- extra = fmt .Sprintf ("; %v" , apiErr .Error ())
67- }
68- err = commonerrors .Newf (respErr , "%v (%d): %v%v" , errorContext , statusCode , errorMessage .String (), extra )
69- }
70- return
27+ func CheckAPICallSuccess (ctx context.Context , errorContext string , resp * http.Response , apiErr error ) error {
28+ return api .CheckAPICallSuccess (ctx , errorContext , errors .FetchAPIErrorDescriptionWithContext , resp , apiErr )
7129}
7230
7331// CallAndCheckSuccess is a wrapper for making an API call and then checking success with `CheckAPICallSuccess`
7432// errorContext corresponds to the description of what led to the error if error there is e.g. `Failed adding a user`.
7533// apiCallFunc corresponds to a generic function that will be called to make the API call
76- func CallAndCheckSuccess [T any ](ctx context.Context , errorContext string , apiCallFunc func (ctx context.Context ) (* T , * http.Response , error )) (result * T , err error ) {
77- if err = parallelisation .DetermineContextError (ctx ); err != nil {
78- return
79- }
80-
81- result , resp , apiErr := apiCallFunc (ctx )
82- if resp != nil && resp .Body != nil {
83- defer func () {
84- if resp != nil && resp .Body != nil {
85- _ = resp .Body .Close ()
86- }
87- }()
88- }
89-
90- err = checkResponse (ctx , apiErr , resp , result , errorContext )
91- return
92- }
93-
94- func checkResponse (ctx context.Context , apiErr error , resp * http.Response , result any , errorContext string ) (err error ) {
95- err = CheckAPICallSuccess (ctx , errorContext , resp , apiErr )
96- if err != nil {
97- return
98- }
99-
100- if apiErr != nil {
101- err = commonerrors .WrapError (commonerrors .ErrMarshalling , apiErr , "API call was successful but an error occurred during response marshalling" )
102- if commonerrors .CorrespondTo (apiErr , requiredFieldError ) {
103- return
104- }
105- if resp == nil || resp .Body == nil {
106- return
107- }
108- // At this point, the marshalling problem may be due to the present of unknown fields in the response due to an API extension.
109- // See https://github.com/OpenAPITools/openapi-generator/issues/21446
110- var respB []byte
111- respB , err = safeio .ReadAll (ctx , resp .Body )
112- if err != nil {
113- return
114- }
115- _ , err = marshmallow .Unmarshal (respB , result , marshmallow .WithSkipPopulateStruct (false ), marshmallow .WithExcludeKnownFieldsFromMap (true ))
116- if err != nil {
117- err = commonerrors .WrapError (commonerrors .ErrMarshalling , err , "API call was successful but an error occurred during response marshalling" )
118- return
119- }
120- }
121- if reflection .IsEmpty (result ) {
122- err = commonerrors .New (commonerrors .ErrMarshalling , "unmarshalled response is empty" )
123- return
124- }
125- return
34+ func CallAndCheckSuccess [T any ](ctx context.Context , errorContext string , apiCallFunc func (ctx context.Context ) (* T , * http.Response , error )) (* T , error ) {
35+ return api .CallAndCheckSuccess [T ](ctx , errorContext , errors .FetchAPIErrorDescriptionWithContext , apiCallFunc )
12636}
12737
12838// GenericCallAndCheckSuccess is similar to CallAndCheckSuccess but for function returning interfaces rather than concrete types.
12939// T must be an interface.
13040// errorContext corresponds to the description of what led to the error if error there is e.g. `Failed adding a user`.
13141// apiCallFunc corresponds to a generic function that will be called to make the API call
132- func GenericCallAndCheckSuccess [T any ](ctx context.Context , errorContext string , apiCallFunc func (ctx context.Context ) (T , * http.Response , error )) (result T , err error ) {
133- if err = parallelisation .DetermineContextError (ctx ); err != nil {
134- return
135- }
136-
137- result , resp , apiErr := apiCallFunc (ctx )
138- if resp != nil && resp .Body != nil {
139- _ = resp .Body .Close ()
140- }
141-
142- err = checkResponse (ctx , apiErr , resp , result , errorContext )
143- if err != nil {
144- return
145- }
146-
147- if reflect .ValueOf (result ).Kind () != reflect .Ptr {
148- err = commonerrors .Newf (commonerrors .ErrConflict , "result of the call is of type [%T] and so, not a pointer as expected" , result )
149- return
150- }
151-
152- return
42+ func GenericCallAndCheckSuccess [T any ](ctx context.Context , errorContext string , apiCallFunc func (ctx context.Context ) (T , * http.Response , error )) (T , error ) {
43+ return api .GenericCallAndCheckSuccess [T ](ctx , errorContext , errors .FetchAPIErrorDescriptionWithContext , apiCallFunc )
15344}
0 commit comments