github.com/vmware/go-vcloud-director/v2@v2.24.0/govcd/api_json.go (about) 1 /* 2 * Copyright 2023 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. 3 */ 4 5 package govcd 6 7 import ( 8 "encoding/json" 9 "fmt" 10 "github.com/vmware/go-vcloud-director/v2/types/v56" 11 "github.com/vmware/go-vcloud-director/v2/util" 12 "io" 13 "net/http" 14 "net/url" 15 "strings" 16 ) 17 18 // executeJsonRequest is a wrapper around regular API call operations, similar to client.ExecuteRequest, but with JSON payback 19 // Returns a http.Response object, which, in case of success, has its body still unread 20 // Caller function has the responsibility for closing the response body 21 func (client Client) executeJsonRequest(href, httpMethod string, inputStructure any, errorMessage string) (*http.Response, error) { 22 23 text, err := json.MarshalIndent(inputStructure, " ", " ") 24 if err != nil { 25 return nil, err 26 } 27 requestHref, err := url.Parse(href) 28 if err != nil { 29 return nil, err 30 } 31 32 var resp *http.Response 33 body := strings.NewReader(string(text)) 34 apiVersion := client.APIVersion 35 headAccept := http.Header{} 36 headAccept.Set("Accept", fmt.Sprintf("application/*+json;version=%s", apiVersion)) 37 headAccept.Set("Content-Type", "application/*+json") 38 request := client.newRequest(nil, nil, httpMethod, *requestHref, body, apiVersion, headAccept) 39 resp, err = client.Http.Do(request) 40 if err != nil { 41 return nil, fmt.Errorf(errorMessage, err) 42 } 43 44 if resp.StatusCode < 200 || resp.StatusCode >= 300 { 45 body, _ := io.ReadAll(resp.Body) 46 util.ProcessResponseOutput(util.CallFuncName(), resp, string(body)) 47 var jsonError types.OpenApiError 48 err = json.Unmarshal(body, &jsonError) 49 // By default, we return the whole response body as error message. This may also contain the stack trace 50 message := string(body) 51 // if the body contains a valid JSON representation of the error, we return a more agile message, using the 52 // exposed fields, and hiding the stack trace from view 53 if err == nil { 54 message = fmt.Sprintf("%s - %s", jsonError.MinorErrorCode, jsonError.Message) 55 } 56 util.ProcessResponseOutput(util.CallFuncName(), resp, string(body)) 57 return resp, fmt.Errorf(errorMessage, message) 58 } 59 60 return checkRespWithErrType(types.BodyTypeJSON, resp, err, &types.Error{}) 61 } 62 63 // closeBody is a wrapper function that should be used with "defer" after calling executeJsonRequest 64 func closeBody(resp *http.Response) { 65 err := resp.Body.Close() 66 if err != nil { 67 util.Logger.Printf("error closing response body - Called by %s: %s\n", util.CallFuncName(), err) 68 } 69 }