github.com/sharovik/devbot@v1.0.1-0.20240308094637-4a0387c40516/internal/client/http.go (about) 1 package client 2 3 import ( 4 "bytes" 5 "encoding/base64" 6 "errors" 7 "fmt" 8 "io" 9 "net/http" 10 "net/url" 11 "strings" 12 13 "github.com/sharovik/devbot/internal/log" 14 ) 15 16 // BaseHTTPClientInterface base interface for all http clients 17 type BaseHTTPClientInterface interface { 18 //Configuration methods 19 SetOauthToken(token string) 20 SetBaseURL(baseURL string) 21 BasicAuth(username string, password string) string 22 GetClientID() string 23 GetClientSecret() string 24 GetOAuthToken() string 25 26 //Http methods 27 Request(string, string, interface{}, map[string]string) ([]byte, int, error) 28 Post(string, interface{}, map[string]string) ([]byte, int, error) 29 Get(string, map[string]string) ([]byte, int, error) 30 Put(string, interface{}, map[string]string) ([]byte, int, error) 31 } 32 33 // HTTPClient main http client 34 type HTTPClient struct { 35 Client *http.Client 36 37 //Configuration of client 38 OAuthToken string 39 BaseURL string 40 ClientID string 41 ClientSecret string 42 } 43 44 // SetOauthToken method sets the oauth token and retrieves its self 45 func (client *HTTPClient) SetOauthToken(token string) { 46 client.OAuthToken = token 47 } 48 49 // GetClientID method retrieves the clientID 50 func (client HTTPClient) GetClientID() string { 51 return client.ClientID 52 } 53 54 // GetClientSecret method retrieves the clientSecret 55 func (client HTTPClient) GetClientSecret() string { 56 return client.ClientSecret 57 } 58 59 // GetOAuthToken method retrieves the oauth token 60 func (client HTTPClient) GetOAuthToken() string { 61 return client.OAuthToken 62 } 63 64 // SetBaseURL method sets the base url and retrieves its self 65 func (client *HTTPClient) SetBaseURL(baseURL string) { 66 client.BaseURL = baseURL 67 } 68 69 // BasicAuth retrieves encode string for basic auth 70 func (client HTTPClient) BasicAuth(username string, password string) string { 71 return base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", username, password))) 72 } 73 74 // Request method for API requests 75 // 76 // This method accepts parameters: 77 // method - the method of request. Ex: POST, GET, PUT, DELETE, and etc 78 // endpoint - endpoint to which we should do a request 79 // body - it's a request body. Accepted types of body: string, url.Values(for form_data requests), byte 80 // headers - request headers 81 func (client HTTPClient) Request(method string, endpoint string, body interface{}, headers map[string]string) ([]byte, int, error) { 82 83 log.Logger().StartMessage("Http request") 84 85 var ( 86 resp *http.Response 87 request *http.Request 88 err error 89 ) 90 91 switch b := body.(type) { 92 case string: 93 log.Logger().Debug(). 94 Str("endpoint", endpoint). 95 Str("method", method). 96 Str("body", b). 97 Msg("Endpoint call") 98 request, err = http.NewRequest(method, endpoint, strings.NewReader(b)) 99 if err != nil { 100 log.Logger().AddError(err).Msg("Error during the request generation") 101 log.Logger().FinishMessage("Http request") 102 return nil, 0, err 103 } 104 105 request.Header.Set("Content-Type", "application/json") 106 case url.Values: 107 log.Logger().Debug(). 108 Str("endpoint", endpoint). 109 Str("method", method). 110 Interface("body", b). 111 Msg("Endpoint call") 112 113 request, err = http.NewRequest(method, endpoint, strings.NewReader(b.Encode())) 114 if err != nil { 115 log.Logger().AddError(err).Msg("Error during the request generation") 116 log.Logger().FinishMessage("Http request") 117 return nil, 0, err 118 } 119 request.Header.Set("Content-Type", "application/x-www-form-urlencoded") 120 case bytes.Buffer: 121 log.Logger().Debug(). 122 Str("endpoint", endpoint). 123 Str("method", method). 124 Interface("body", b). 125 Msg("Endpoint call") 126 127 buff := b 128 request, err = http.NewRequest(method, endpoint, &buff) 129 if err != nil { 130 log.Logger().AddError(err).Msg("Error during the request generation") 131 log.Logger().FinishMessage("Http request") 132 return nil, 0, err 133 } 134 request.Header.Set("Content-Type", "multipart/form-data") 135 default: 136 log.Logger().Debug(). 137 Str("endpoint", endpoint). 138 Str("method", method). 139 Str("body", string(body.([]byte))). 140 Msg("Endpoint call") 141 request, err = http.NewRequest(method, endpoint, bytes.NewReader(body.([]byte))) 142 if err != nil { 143 log.Logger().AddError(err).Msg("Error during the request generation") 144 log.Logger().FinishMessage("Http request") 145 return nil, 0, err 146 } 147 request.Header.Set("Content-Type", "application/json") 148 } 149 150 for attribute, value := range headers { 151 request.Header.Set(attribute, value) 152 } 153 154 if client.OAuthToken != "" { 155 request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", client.OAuthToken)) 156 } 157 158 resp, errorResponse := client.Client.Do(request) 159 160 if resp == nil { 161 err = errors.New("ResponseInterface cannot be null ") 162 errMsg := err.Error() 163 if errorResponse != nil { 164 errMsg = errorResponse.Error() 165 } 166 log.Logger().AddError(errorResponse). 167 Str("response_error", errMsg). 168 Msg("Error during response body parse") 169 170 log.Logger().FinishMessage("Http request") 171 return nil, 0, err 172 } 173 174 defer resp.Body.Close() 175 byteResp, errorConversion := io.ReadAll(resp.Body) 176 if errorConversion != nil { 177 log.Logger().AddError(errorConversion). 178 Err(errorConversion). 179 Msg("Error during response body parse") 180 log.Logger().FinishMessage("Http request") 181 return byteResp, 0, errorConversion 182 } 183 184 var response []byte 185 if string(byteResp) == "" { 186 response = []byte(`{}`) 187 } else { 188 response = byteResp 189 } 190 191 log.Logger().FinishMessage("Http request") 192 return response, resp.StatusCode, nil 193 } 194 195 // Post method for POST http requests 196 func (client HTTPClient) Post(endpoint string, body interface{}, headers map[string]string) ([]byte, int, error) { 197 return client.Request(http.MethodPost, client.generateAPIUrl(endpoint), body, headers) 198 } 199 200 // Put method for PUT http requests 201 func (client HTTPClient) Put(endpoint string, body interface{}, headers map[string]string) ([]byte, int, error) { 202 return client.Request(http.MethodPut, client.generateAPIUrl(endpoint), body, headers) 203 } 204 205 // Get method for GET http requests 206 func (client *HTTPClient) Get(endpoint string, query map[string]string) ([]byte, int, error) { 207 if client.OAuthToken != "" { 208 query["access_token"] = client.OAuthToken 209 } 210 211 var queryString = "" 212 for fieldName, value := range query { 213 if queryString == "" { 214 queryString += "?" 215 } else { 216 queryString += "&" 217 } 218 219 queryString += fmt.Sprintf("%s=%s", fieldName, value) 220 } 221 222 return client.Request(http.MethodGet, client.generateAPIUrl(endpoint)+queryString, []byte(``), map[string]string{}) 223 } 224 225 func (client HTTPClient) generateAPIUrl(endpoint string) string { 226 log.Logger().Debug(). 227 Str("base_url", client.BaseURL). 228 Str("endpoint", endpoint). 229 Msg("Generate API url") 230 231 return client.BaseURL + endpoint 232 }