github.com/aldelo/common@v1.5.1/rest/rest.go (about)

     1  package rest
     2  
     3  /*
     4   * Copyright 2020-2023 Aldelo, LP
     5   *
     6   * Licensed under the Apache License, Version 2.0 (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   *     http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   * Unless required by applicable law or agreed to in writing, software
    13   * distributed under the License is distributed on an "AS IS" BASIS,
    14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15   * See the License for the specific language governing permissions and
    16   * limitations under the License.
    17   */
    18  
    19  import (
    20  	"bytes"
    21  	"crypto/tls"
    22  	"errors"
    23  	"github.com/aldelo/common/tlsconfig"
    24  	"google.golang.org/protobuf/proto"
    25  	"io/ioutil"
    26  	"net/http"
    27  	"strconv"
    28  	"strings"
    29  )
    30  
    31  // server ca pems stores list of self-signed CAs for client tls config
    32  var serverCaPems []string
    33  
    34  // client tls config stores the current client tls root CA config object
    35  var clientTlsConfig *tls.Config
    36  
    37  // AppendServerCAPemFiles adds self-signed server ca pems to local cache,
    38  // and then recreates the clientTlsConfig object based on the new list of CAs
    39  func AppendServerCAPemFiles(caPemFilePath ...string) error {
    40  	if len(caPemFilePath) > 0 {
    41  		serverCaPems = append(serverCaPems, caPemFilePath...)
    42  		return newClientTlsCAsConfig()
    43  	} else {
    44  		return nil
    45  	}
    46  }
    47  
    48  // ResetServerCAPemFiles first clears serverCaPems cache,
    49  // then adds self-signed server ca pems to local cache,
    50  // then recreates the clientTlsConfig object based on the new list of CAs
    51  func ResetServerCAPemFiles(caPemFilePath ...string) error {
    52  	serverCaPems = []string{}
    53  	clientTlsConfig = nil
    54  
    55  	if len(caPemFilePath) > 0 {
    56  		serverCaPems = append(serverCaPems, caPemFilePath...)
    57  		return newClientTlsCAsConfig()
    58  	} else {
    59  		return nil
    60  	}
    61  }
    62  
    63  // newClientTlsCAsConfig creates new ClientTlsConfig object for the serverCaPems in cache
    64  func newClientTlsCAsConfig() error {
    65  	if len(serverCaPems) == 0 {
    66  		clientTlsConfig = nil
    67  		return nil
    68  	}
    69  
    70  	t := &tlsconfig.TlsConfig{}
    71  
    72  	if c, e := t.GetClientTlsConfig(serverCaPems, "", ""); e != nil {
    73  		return e
    74  	} else {
    75  		clientTlsConfig = c
    76  		return nil
    77  	}
    78  }
    79  
    80  // HeaderKeyValue is struct used for containing http header element key value pair
    81  type HeaderKeyValue struct {
    82  	Key   string
    83  	Value string
    84  }
    85  
    86  // GET sends url get request to host and retrieve the body response in string
    87  func GET(url string, headers []*HeaderKeyValue) (statusCode int, body string, err error) {
    88  	// create http client
    89  	var client *http.Client
    90  
    91  	if clientTlsConfig == nil {
    92  		client = &http.Client{}
    93  	} else {
    94  		tr := &http.Transport{
    95  			TLSClientConfig: clientTlsConfig,
    96  		}
    97  
    98  		client = &http.Client{
    99  			Transport: tr,
   100  		}
   101  	}
   102  
   103  	// create http request from client
   104  	var req *http.Request
   105  
   106  	if req, err = http.NewRequest("GET", url, nil); err != nil {
   107  		return 0, "", errors.New("Create New Http GET Request Failed: " + err.Error())
   108  	}
   109  
   110  	// add headers to request if any
   111  	if len(headers) > 0 {
   112  		for _, v := range headers {
   113  			req.Header.Add(v.Key, v.Value)
   114  		}
   115  	}
   116  
   117  	// execute http request and assign response
   118  	var resp *http.Response
   119  
   120  	if resp, err = client.Do(req); err != nil {
   121  		return 500, "", errors.New("[500 - Http Get Error] " + err.Error())
   122  	}
   123  
   124  	// evaluate response
   125  	statusCode = resp.StatusCode
   126  
   127  	var respBytes []byte
   128  
   129  	respBytes, err = ioutil.ReadAll(resp.Body)
   130  	_ = resp.Body.Close()
   131  	resp.Close = true
   132  
   133  	// clean up stale connections
   134  	client.CloseIdleConnections()
   135  
   136  	if err != nil && statusCode == 400 {
   137  		return statusCode, "", err
   138  	}
   139  
   140  	if statusCode != 200 {
   141  		return statusCode, "", errors.New("[" + strconv.Itoa(statusCode) + " - Get Resp] " + string(respBytes))
   142  	}
   143  
   144  	// success
   145  	return statusCode, string(respBytes), nil
   146  }
   147  
   148  // POST sends url post request to host and retrieve the body response in string
   149  //
   150  // Default Header = Content-Type: application/x-www-form-urlencoded
   151  //
   152  // JSON Content-Type Header:
   153  //
   154  //	Content-Type: application/json
   155  func POST(url string, headers []*HeaderKeyValue, requestBody string) (statusCode int, responseBody string, err error) {
   156  	// create http client
   157  	var client *http.Client
   158  
   159  	if clientTlsConfig == nil {
   160  		client = &http.Client{}
   161  	} else {
   162  		tr := &http.Transport{
   163  			TLSClientConfig: clientTlsConfig,
   164  		}
   165  
   166  		client = &http.Client{
   167  			Transport: tr,
   168  		}
   169  	}
   170  
   171  	// create http request from client
   172  	var req *http.Request
   173  
   174  	if req, err = http.NewRequest("POST", url, bytes.NewBuffer([]byte(requestBody))); err != nil {
   175  		return 0, "", errors.New("Create New Http Post Request Failed: " + err.Error())
   176  	}
   177  
   178  	// add headers to request if any
   179  	contentTypeConfigured := false
   180  
   181  	if len(headers) > 0 {
   182  		for _, v := range headers {
   183  			req.Header.Add(v.Key, v.Value)
   184  
   185  			if strings.ToUpper(v.Key) == "CONTENT-TYPE" {
   186  				contentTypeConfigured = true
   187  			}
   188  		}
   189  	}
   190  
   191  	if !contentTypeConfigured {
   192  		req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
   193  	}
   194  
   195  	// execute http request and assign response
   196  	var resp *http.Response
   197  
   198  	if resp, err = client.Do(req); err != nil {
   199  		return 500, "", errors.New("[500 - Http Post Error] " + err.Error())
   200  	}
   201  
   202  	// evaluate response
   203  	statusCode = resp.StatusCode
   204  
   205  	var respBytes []byte
   206  
   207  	respBytes, err = ioutil.ReadAll(resp.Body)
   208  	_ = resp.Body.Close()
   209  	resp.Close = true
   210  
   211  	// clean up stale connections
   212  	client.CloseIdleConnections()
   213  
   214  	if err != nil && statusCode == 400 {
   215  		return statusCode, "", err
   216  	}
   217  
   218  	if statusCode != 200 {
   219  		return statusCode, "", errors.New("[" + strconv.Itoa(statusCode) + " - Post Resp] " + string(respBytes))
   220  	}
   221  
   222  	return statusCode, string(respBytes), nil
   223  }
   224  
   225  // PUT sends url put request to host and retrieve the body response in string
   226  //
   227  // Default Header = Content-Type: application/x-www-form-urlencoded
   228  //
   229  // JSON Content-Type Header:
   230  //
   231  //	Content-Type: application/json
   232  func PUT(url string, headers []*HeaderKeyValue, requestBody string) (statusCode int, responseBody string, err error) {
   233  	// create http client
   234  	var client *http.Client
   235  
   236  	if clientTlsConfig == nil {
   237  		client = &http.Client{}
   238  	} else {
   239  		tr := &http.Transport{
   240  			TLSClientConfig: clientTlsConfig,
   241  		}
   242  
   243  		client = &http.Client{
   244  			Transport: tr,
   245  		}
   246  	}
   247  
   248  	// create http request from client
   249  	var req *http.Request
   250  
   251  	if req, err = http.NewRequest("PUT", url, bytes.NewBuffer([]byte(requestBody))); err != nil {
   252  		return 0, "", errors.New("Create New Http Put Request Failed: " + err.Error())
   253  	}
   254  
   255  	// add headers to request if any
   256  	contentTypeConfigured := false
   257  
   258  	if len(headers) > 0 {
   259  		for _, v := range headers {
   260  			req.Header.Add(v.Key, v.Value)
   261  
   262  			if strings.ToUpper(v.Key) == "CONTENT-TYPE" {
   263  				contentTypeConfigured = true
   264  			}
   265  		}
   266  	}
   267  
   268  	if !contentTypeConfigured {
   269  		req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
   270  	}
   271  
   272  	// execute http request and assign response
   273  	var resp *http.Response
   274  
   275  	if resp, err = client.Do(req); err != nil {
   276  		return 500, "", errors.New("[500 - Http Put Error] " + err.Error())
   277  	}
   278  
   279  	// evaluate response
   280  	statusCode = resp.StatusCode
   281  
   282  	var respBytes []byte
   283  
   284  	respBytes, err = ioutil.ReadAll(resp.Body)
   285  	_ = resp.Body.Close()
   286  	resp.Close = true
   287  
   288  	// clean up stale connections
   289  	client.CloseIdleConnections()
   290  
   291  	if err != nil && statusCode == 400 {
   292  		return statusCode, "", err
   293  	}
   294  
   295  	if statusCode != 200 {
   296  		return statusCode, "", errors.New("[" + strconv.Itoa(statusCode) + " - Put Resp] " + string(respBytes))
   297  	}
   298  
   299  	return statusCode, string(respBytes), nil
   300  }
   301  
   302  // DELETE sends url delete request to host and performs delete action (no body expected)
   303  //
   304  // Default Header = Content-Type: application/x-www-form-urlencoded
   305  //
   306  // JSON Content-Type Header:
   307  //
   308  //	Content-Type: application/json
   309  func DELETE(url string, headers []*HeaderKeyValue) (statusCode int, body string, err error) {
   310  	// create http client
   311  	var client *http.Client
   312  
   313  	if clientTlsConfig == nil {
   314  		client = &http.Client{}
   315  	} else {
   316  		tr := &http.Transport{
   317  			TLSClientConfig: clientTlsConfig,
   318  		}
   319  
   320  		client = &http.Client{
   321  			Transport: tr,
   322  		}
   323  	}
   324  
   325  	// create http request from client
   326  	var req *http.Request
   327  
   328  	if req, err = http.NewRequest("DELETE", url, nil); err != nil {
   329  		return 0, "", errors.New("Create New Http Delete Request Failed: " + err.Error())
   330  	}
   331  
   332  	// add headers to request if any
   333  	if len(headers) > 0 {
   334  		for _, v := range headers {
   335  			req.Header.Add(v.Key, v.Value)
   336  		}
   337  	}
   338  
   339  	// execute http request and assign response
   340  	var resp *http.Response
   341  
   342  	if resp, err = client.Do(req); err != nil {
   343  		return 500, "", errors.New("[500 - Http Delete Error] " + err.Error())
   344  	}
   345  
   346  	// evaluate response
   347  	statusCode = resp.StatusCode
   348  
   349  	var respBytes []byte
   350  
   351  	respBytes, err = ioutil.ReadAll(resp.Body)
   352  	_ = resp.Body.Close()
   353  	resp.Close = true
   354  
   355  	// clean up stale connections
   356  	client.CloseIdleConnections()
   357  
   358  	if err != nil && statusCode == 400 {
   359  		return statusCode, "", err
   360  	}
   361  
   362  	if statusCode != 200 {
   363  		return statusCode, "", errors.New("[" + strconv.Itoa(statusCode) + " - Delete Resp] " + string(respBytes))
   364  	}
   365  
   366  	// success
   367  	return statusCode, string(respBytes), nil
   368  }
   369  
   370  // GETProtoBuf sends url get request to host, and retrieves response via protobuf object as an output pointer parameter
   371  //
   372  // default header if not specified:
   373  //
   374  //	Content-Type: application/x-protobuf
   375  func GETProtoBuf(url string, headers []*HeaderKeyValue, outResponseProtoBufObjectPtr proto.Message) (statusCode int, err error) {
   376  	// create http client
   377  	var client *http.Client
   378  
   379  	if clientTlsConfig == nil {
   380  		client = &http.Client{}
   381  	} else {
   382  		tr := &http.Transport{
   383  			TLSClientConfig: clientTlsConfig,
   384  		}
   385  
   386  		client = &http.Client{
   387  			Transport: tr,
   388  		}
   389  	}
   390  
   391  	// create http request from client
   392  	var req *http.Request
   393  
   394  	if req, err = http.NewRequest("GET", url, nil); err != nil {
   395  		outResponseProtoBufObjectPtr = nil
   396  		return 0, errors.New("Create New Http GET ProtoBuf Request Failed: " + err.Error())
   397  	}
   398  
   399  	// add headers to request if any
   400  	contentTypeConfigured := false
   401  
   402  	if len(headers) > 0 {
   403  		for _, v := range headers {
   404  			req.Header.Add(v.Key, v.Value)
   405  
   406  			if strings.ToUpper(v.Key) == "CONTENT-TYPE" {
   407  				contentTypeConfigured = true
   408  			}
   409  		}
   410  	}
   411  
   412  	if !contentTypeConfigured {
   413  		req.Header.Add("Content-Type", "application/x-protobuf")
   414  	}
   415  
   416  	// execute http request and assign response
   417  	var resp *http.Response
   418  
   419  	if resp, err = client.Do(req); err != nil {
   420  		outResponseProtoBufObjectPtr = nil
   421  		return 500, errors.New("[500 - Http Get ProtoBuf Error] " + err.Error())
   422  	}
   423  
   424  	// evaluate response
   425  	statusCode = resp.StatusCode
   426  
   427  	var respBytes []byte
   428  
   429  	respBytes, err = ioutil.ReadAll(resp.Body)
   430  	_ = resp.Body.Close()
   431  	resp.Close = true
   432  
   433  	// clean up stale connections
   434  	client.CloseIdleConnections()
   435  
   436  	if err != nil && statusCode == 400 {
   437  		outResponseProtoBufObjectPtr = nil
   438  		return statusCode, err
   439  	}
   440  
   441  	if statusCode != 200 {
   442  		outResponseProtoBufObjectPtr = nil
   443  		return statusCode, errors.New("[" + strconv.Itoa(statusCode) + " - Get ProtoBuf Not 200] Response ProtoBuf Bytes Length = " + strconv.Itoa(len(respBytes)))
   444  	}
   445  
   446  	// unmarshal bytes to protobuf object
   447  	if outResponseProtoBufObjectPtr != nil {
   448  		if err = proto.Unmarshal(respBytes, outResponseProtoBufObjectPtr); err != nil {
   449  			outResponseProtoBufObjectPtr = nil
   450  			return 500, errors.New("[500 - Http Get ProtoBuf Error] Unmarshal ProtoBuf Response Failed: " + err.Error())
   451  		}
   452  	}
   453  
   454  	// success if outResponseProtoBufObjectPtr is not nil
   455  	if outResponseProtoBufObjectPtr != nil {
   456  		return statusCode, nil
   457  	} else {
   458  		return 500, errors.New("[500 - Http Get ProtoBuf Error] Expected ProtoBuf Response Object Nil")
   459  	}
   460  }
   461  
   462  // POSTProtoBuf sends url post request to host, with body content in protobuf pointer object,
   463  // and retrieves response in protobuf object as output pointer parameter
   464  //
   465  // default header if not specified:
   466  //
   467  //	Content-Type: application/x-protobuf
   468  func POSTProtoBuf(url string, headers []*HeaderKeyValue, requestProtoBufObjectPtr proto.Message, outResponseProtoBufObjectPtr proto.Message) (statusCode int, err error) {
   469  	// create http client
   470  	var client *http.Client
   471  
   472  	if clientTlsConfig == nil {
   473  		client = &http.Client{}
   474  	} else {
   475  		tr := &http.Transport{
   476  			TLSClientConfig: clientTlsConfig,
   477  		}
   478  
   479  		client = &http.Client{
   480  			Transport: tr,
   481  		}
   482  	}
   483  
   484  	// marshal proto message to bytes
   485  	if requestProtoBufObjectPtr == nil {
   486  		outResponseProtoBufObjectPtr = nil
   487  		return 0, errors.New("Request ProtoBuf Object is Nil")
   488  	}
   489  
   490  	reqBytes, err2 := proto.Marshal(requestProtoBufObjectPtr)
   491  
   492  	if err2 != nil {
   493  		outResponseProtoBufObjectPtr = nil
   494  		return 0, errors.New("Request ProtoBuf Object Marshaling Failed: " + err2.Error())
   495  	}
   496  
   497  	// create http request from client
   498  	req, err3 := http.NewRequest("POST", url, bytes.NewReader(reqBytes))
   499  
   500  	if err3 != nil {
   501  		outResponseProtoBufObjectPtr = nil
   502  		return 0, errors.New("Create New Http Post ProtoBuf Request Failed: " + err3.Error())
   503  	}
   504  
   505  	// add headers to request if any
   506  	contentTypeConfigured := false
   507  
   508  	if len(headers) > 0 {
   509  		for _, v := range headers {
   510  			req.Header.Add(v.Key, v.Value)
   511  
   512  			if strings.ToUpper(v.Key) == "CONTENT-TYPE" {
   513  				contentTypeConfigured = true
   514  			}
   515  		}
   516  	}
   517  
   518  	if !contentTypeConfigured {
   519  		req.Header.Add("Content-Type", "application/x-protobuf")
   520  	}
   521  
   522  	// execute http request and assign response
   523  	var resp *http.Response
   524  
   525  	if resp, err = client.Do(req); err != nil {
   526  		outResponseProtoBufObjectPtr = nil
   527  		return 500, errors.New("[500 - Http Post ProtoBuf Error] " + err.Error())
   528  	}
   529  
   530  	// evaluate response
   531  	statusCode = resp.StatusCode
   532  
   533  	var respBytes []byte
   534  
   535  	respBytes, err = ioutil.ReadAll(resp.Body)
   536  	_ = resp.Body.Close()
   537  	resp.Close = true
   538  
   539  	// clean up stale connections
   540  	client.CloseIdleConnections()
   541  
   542  	if err != nil && statusCode == 400 {
   543  		outResponseProtoBufObjectPtr = nil
   544  		return statusCode, err
   545  	}
   546  
   547  	if statusCode != 200 {
   548  		return statusCode, errors.New("[" + strconv.Itoa(statusCode) + " - Post ProtoBuf Not 200] Response ProtoBuf Bytes Length = " + strconv.Itoa(len(respBytes)))
   549  	}
   550  
   551  	// unmarshal response bytes into protobuf object message
   552  	if outResponseProtoBufObjectPtr != nil {
   553  		if err = proto.Unmarshal(respBytes, outResponseProtoBufObjectPtr); err != nil {
   554  			outResponseProtoBufObjectPtr = nil
   555  			return 500, errors.New("[500 - Http Post ProtoBuf Error] Unmarshal ProtoBuf Response Failed: " + err.Error())
   556  		}
   557  	}
   558  
   559  	// success if outResponseProtoBufObjectPtr is not nil
   560  	if outResponseProtoBufObjectPtr != nil {
   561  		return statusCode, nil
   562  	} else {
   563  		return 500, errors.New("[500 - Http Post ProtoBuf Error] Expected ProtoBuf Response Object Nil")
   564  	}
   565  }
   566  
   567  // PUTProtoBuf sends url put request to host, with body content in protobuf pointer object,
   568  // and retrieves response in protobuf object as output pointer parameter
   569  //
   570  // default header if not specified:
   571  //
   572  //	Content-Type: application/x-protobuf
   573  func PUTProtoBuf(url string, headers []*HeaderKeyValue, requestProtoBufObjectPtr proto.Message, outResponseProtoBufObjectPtr proto.Message) (statusCode int, err error) {
   574  	// create http client
   575  	var client *http.Client
   576  
   577  	if clientTlsConfig == nil {
   578  		client = &http.Client{}
   579  	} else {
   580  		tr := &http.Transport{
   581  			TLSClientConfig: clientTlsConfig,
   582  		}
   583  
   584  		client = &http.Client{
   585  			Transport: tr,
   586  		}
   587  	}
   588  
   589  	// marshal proto message to bytes
   590  	if requestProtoBufObjectPtr == nil {
   591  		outResponseProtoBufObjectPtr = nil
   592  		return 0, errors.New("Request ProtoBuf Object is Nil")
   593  	}
   594  
   595  	reqBytes, err2 := proto.Marshal(requestProtoBufObjectPtr)
   596  
   597  	if err2 != nil {
   598  		outResponseProtoBufObjectPtr = nil
   599  		return 0, errors.New("Request ProtoBuf Object Marshaling Failed: " + err2.Error())
   600  	}
   601  
   602  	// create http request from client
   603  	req, err3 := http.NewRequest("PUT", url, bytes.NewReader(reqBytes))
   604  
   605  	if err3 != nil {
   606  		outResponseProtoBufObjectPtr = nil
   607  		return 0, errors.New("Create New Http PUT ProtoBuf Request Failed: " + err3.Error())
   608  	}
   609  
   610  	// add headers to request if any
   611  	contentTypeConfigured := false
   612  
   613  	if len(headers) > 0 {
   614  		for _, v := range headers {
   615  			req.Header.Add(v.Key, v.Value)
   616  
   617  			if strings.ToUpper(v.Key) == "CONTENT-TYPE" {
   618  				contentTypeConfigured = true
   619  			}
   620  		}
   621  	}
   622  
   623  	if !contentTypeConfigured {
   624  		req.Header.Add("Content-Type", "application/x-protobuf")
   625  	}
   626  
   627  	// execute http request and assign response
   628  	var resp *http.Response
   629  
   630  	if resp, err = client.Do(req); err != nil {
   631  		outResponseProtoBufObjectPtr = nil
   632  		return 500, errors.New("[500 - Http Put ProtoBuf Error] " + err.Error())
   633  	}
   634  
   635  	// evaluate response
   636  	statusCode = resp.StatusCode
   637  
   638  	var respBytes []byte
   639  
   640  	respBytes, err = ioutil.ReadAll(resp.Body)
   641  	_ = resp.Body.Close()
   642  	resp.Close = true
   643  
   644  	// clean up stale connections
   645  	client.CloseIdleConnections()
   646  
   647  	if err != nil && statusCode == 400 {
   648  		outResponseProtoBufObjectPtr = nil
   649  		return statusCode, err
   650  	}
   651  
   652  	if statusCode != 200 {
   653  		return statusCode, errors.New("[" + strconv.Itoa(statusCode) + " - Put ProtoBuf Not 200] Response ProtoBuf Bytes Length = " + strconv.Itoa(len(respBytes)))
   654  	}
   655  
   656  	// unmarshal response bytes into protobuf object message
   657  	if outResponseProtoBufObjectPtr != nil {
   658  		if err = proto.Unmarshal(respBytes, outResponseProtoBufObjectPtr); err != nil {
   659  			outResponseProtoBufObjectPtr = nil
   660  			return 500, errors.New("[500 - Http Put ProtoBuf Error] Unmarshal ProtoBuf Response Failed: " + err.Error())
   661  		}
   662  	}
   663  
   664  	// success if outResponseProtoBufObjectPtr is not nil
   665  	if outResponseProtoBufObjectPtr != nil {
   666  		return statusCode, nil
   667  	} else {
   668  		return 500, errors.New("[500 - Http Put ProtoBuf Error] Expected ProtoBuf Response Object Nil")
   669  	}
   670  }
   671  
   672  // DELETEProtoBuf sends url delete request to host, and retrieves response via protobuf object as an output pointer parameter
   673  //
   674  // default header if not specified:
   675  //
   676  //	Content-Type: application/x-protobuf
   677  func DELETEProtoBuf(url string, headers []*HeaderKeyValue, outResponseProtoBufObjectPtr proto.Message) (statusCode int, err error) {
   678  	// create http client
   679  	var client *http.Client
   680  
   681  	if clientTlsConfig == nil {
   682  		client = &http.Client{}
   683  	} else {
   684  		tr := &http.Transport{
   685  			TLSClientConfig: clientTlsConfig,
   686  		}
   687  
   688  		client = &http.Client{
   689  			Transport: tr,
   690  		}
   691  	}
   692  
   693  	// create http request from client
   694  	var req *http.Request
   695  
   696  	if req, err = http.NewRequest("DELETE", url, nil); err != nil {
   697  		outResponseProtoBufObjectPtr = nil
   698  		return 0, errors.New("Create New Http Delete ProtoBuf Request Failed: " + err.Error())
   699  	}
   700  
   701  	// add headers to request if any
   702  	contentTypeConfigured := false
   703  
   704  	if len(headers) > 0 {
   705  		for _, v := range headers {
   706  			req.Header.Add(v.Key, v.Value)
   707  
   708  			if strings.ToUpper(v.Key) == "CONTENT-TYPE" {
   709  				contentTypeConfigured = true
   710  			}
   711  		}
   712  	}
   713  
   714  	if !contentTypeConfigured {
   715  		req.Header.Add("Content-Type", "application/x-protobuf")
   716  	}
   717  
   718  	// execute http request and assign response
   719  	var resp *http.Response
   720  
   721  	if resp, err = client.Do(req); err != nil {
   722  		outResponseProtoBufObjectPtr = nil
   723  		return 500, errors.New("[500 - Http Delete ProtoBuf Error] " + err.Error())
   724  	}
   725  
   726  	// evaluate response
   727  	statusCode = resp.StatusCode
   728  
   729  	var respBytes []byte
   730  
   731  	respBytes, err = ioutil.ReadAll(resp.Body)
   732  	_ = resp.Body.Close()
   733  	resp.Close = true
   734  
   735  	// clean up stale connections
   736  	client.CloseIdleConnections()
   737  
   738  	if err != nil && statusCode == 400 {
   739  		outResponseProtoBufObjectPtr = nil
   740  		return statusCode, err
   741  	}
   742  
   743  	if statusCode != 200 {
   744  		outResponseProtoBufObjectPtr = nil
   745  		return statusCode, errors.New("[" + strconv.Itoa(statusCode) + " - Delete ProtoBuf Not 200] Response ProtoBuf Bytes Length = " + strconv.Itoa(len(respBytes)))
   746  	}
   747  
   748  	// unmarshal bytes to protobuf object
   749  	if outResponseProtoBufObjectPtr != nil {
   750  		if err = proto.Unmarshal(respBytes, outResponseProtoBufObjectPtr); err != nil {
   751  			outResponseProtoBufObjectPtr = nil
   752  			return 500, errors.New("[500 - Http Delete ProtoBuf Error] Unmarshal ProtoBuf Response Failed: " + err.Error())
   753  		}
   754  	}
   755  
   756  	// success if outResponseProtoBufObjectPtr is not nil
   757  	if outResponseProtoBufObjectPtr != nil {
   758  		return statusCode, nil
   759  	} else {
   760  		return 500, errors.New("[500 - Http Delete ProtoBuf Error] Expected ProtoBuf Response Object Nil")
   761  	}
   762  }