Skip to content

Commit 1bf3b58

Browse files
add wrapper files
1 parent 625f28a commit 1bf3b58

File tree

3 files changed

+249
-0
lines changed

3 files changed

+249
-0
lines changed

HTTPWrapper.go

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
package http_wrapper
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/json"
7+
"fmt"
8+
error "github.com/abhinav-codealchemist/custom-error-go"
9+
"github.com/ajg/form"
10+
"io"
11+
"io/ioutil"
12+
"net/http"
13+
"net/url"
14+
"strings"
15+
"time"
16+
)
17+
18+
const (
19+
NOT_ASSIGNED = ""
20+
DEFAULT_TIMEOUT = 20 * time.Second
21+
AUTHORIZATION_TOKEN_PREFIX = "Token"
22+
CONTENT_TYPE_APP_JSON ContentType = "application/json"
23+
CONTENT_TYPE_FORM_URL_ENCODED ContentType = "application/x-www-form-urlencoded"
24+
)
25+
26+
type ContentType string
27+
28+
type HttpRequestParams struct {
29+
endpoint string // the api endpoint
30+
method string // the http request method, get/post
31+
body interface{} // the request body, should be json serializable
32+
queryParams map[string]string // the request query url params
33+
authUserName string // basic auth user name
34+
authPassword string // basic auth password
35+
basicAuth string // basic auth
36+
authToken string // to be used in cases where token based authentication is required
37+
host string // to specify host header
38+
customHeaders map[string]string // to set any custom headers, if any
39+
contentType ContentType // to set content type
40+
timeout time.Duration // to set custom request timeout if needed, default is 20 secs
41+
}
42+
43+
func NewHttpRequestParams(endpoint string, method string) *HttpRequestParams {
44+
return &HttpRequestParams{endpoint: endpoint, method: method, body: nil, queryParams: make(map[string]string, 0), customHeaders: make(map[string]string, 0), contentType: CONTENT_TYPE_APP_JSON}
45+
}
46+
47+
func (a *HttpRequestParams) SetAuthPassword(authPassword string) {
48+
a.authPassword = authPassword
49+
}
50+
51+
func (a *HttpRequestParams) SetAuthUserName(authUserName string) {
52+
a.authUserName = authUserName
53+
}
54+
55+
func (a *HttpRequestParams) SetAuth(username string, password string) {
56+
a.authPassword = password
57+
a.authUserName = username
58+
}
59+
60+
func (a *HttpRequestParams) SetAuthToken(authToken string) {
61+
a.authToken = authToken
62+
}
63+
64+
func (a *HttpRequestParams) SetBody(requestBody interface{}) {
65+
a.body = requestBody
66+
}
67+
68+
func (a *HttpRequestParams) SetQueryParams(requestQueryParams map[string]string) {
69+
a.queryParams = requestQueryParams
70+
}
71+
72+
func (a *HttpRequestParams) AddQueryParam(key, val string) {
73+
if a.queryParams == nil {
74+
a.queryParams = make(map[string]string, 0)
75+
}
76+
a.queryParams[key] = val
77+
}
78+
79+
func (a *HttpRequestParams) AddHeader(key, val string) {
80+
if a.customHeaders == nil {
81+
a.customHeaders = make(map[string]string, 0)
82+
}
83+
a.customHeaders[key] = val
84+
}
85+
86+
func (a *HttpRequestParams) Host() string {
87+
return a.host
88+
}
89+
90+
func (a *HttpRequestParams) SetHost(host string) {
91+
a.host = host
92+
}
93+
94+
func (a *HttpRequestParams) SetContentType(contentType ContentType) {
95+
a.contentType = contentType
96+
}
97+
98+
func (a *HttpRequestParams) BasicAuth() string {
99+
return a.basicAuth
100+
}
101+
102+
func (a *HttpRequestParams) SetBasicAuth(basicAuth string) {
103+
a.basicAuth = basicAuth
104+
}
105+
106+
func (a *HttpRequestParams) SetTimeout(timeout time.Duration) {
107+
a.timeout = timeout
108+
}
109+
110+
func MakeApiCallWithRetries(ctx context.Context, request *HttpRequestParams, responseAddr interface{}, retriesCount int) (customError error.CustomError) {
111+
for i := 0; i <= retriesCount; i++ {
112+
customError = MakeApiCall(ctx, request, responseAddr)
113+
if customError.Exists() && (customError.ErrorCode() == error.API_REQUEST_ERROR || customError.ErrorCode() == error.API_REQUEST_STATUS_ERROR) {
114+
continue
115+
} else {
116+
return
117+
}
118+
}
119+
return
120+
}
121+
122+
// responseAddr is the the address of the struct to put the api response
123+
func MakeApiCall(ctx context.Context, request *HttpRequestParams, responseAddr interface{}) (customError error.CustomError) {
124+
body, customError := MakeApiCallWithRawResponse(ctx, request)
125+
if customError.Exists() {
126+
return
127+
}
128+
err := json.Unmarshal(body, &responseAddr)
129+
if err != nil {
130+
customError = error.NewCustomError(error.JSON_DESERIALIZATION_ERROR, err.Error()).
131+
WithParam("response", string(body)).
132+
WithParam("request", fmt.Sprintf("%+v", request))
133+
customError.Log()
134+
}
135+
return customError
136+
}
137+
138+
func MakeApiCallWithRawResponse(ctx context.Context, request *HttpRequestParams) (body []byte, customError error.CustomError) {
139+
var requestBuffer io.Reader
140+
if request.body != nil {
141+
switch request.contentType {
142+
case CONTENT_TYPE_FORM_URL_ENCODED:
143+
values, err := form.EncodeToValues(request.body)
144+
if err != nil {
145+
customError = error.NewCustomError(error.FORM_SERIALIZATION_ERROR, fmt.Sprintf("request: %+v, error: %s", request.body, err.Error()))
146+
customError.Log()
147+
return
148+
}
149+
requestBuffer = strings.NewReader(values.Encode())
150+
case CONTENT_TYPE_APP_JSON:
151+
requestJSONForm, err := json.Marshal(request.body)
152+
if err != nil {
153+
customError = error.NewCustomError(error.JSON_SERIALIZATION_ERROR, fmt.Sprintf("request: %+v, error: %s", request.body, err.Error()))
154+
customError.Log()
155+
return
156+
}
157+
requestBuffer = bytes.NewBuffer(requestJSONForm)
158+
}
159+
} else {
160+
requestBuffer = nil
161+
}
162+
163+
url, err := url.Parse(request.endpoint)
164+
if err != nil {
165+
customError = error.NewCustomError(error.API_URL_PARSING_ERROR, fmt.Sprintf("url: %s; error: %s", request.endpoint, err.Error()))
166+
customError.Log()
167+
return
168+
}
169+
170+
httpRequest, err := http.NewRequest(request.method, url.String(), requestBuffer)
171+
if request.queryParams != nil {
172+
q := httpRequest.URL.Query()
173+
for k, v := range request.queryParams {
174+
q.Add(k, v)
175+
}
176+
httpRequest.URL.RawQuery = q.Encode()
177+
}
178+
179+
if err != nil {
180+
customError = error.NewCustomError(error.API_REQUEST_CREATION_ERROR, fmt.Sprintf("url: %s; error: %s", url.String(), err.Error()))
181+
customError.Log()
182+
return
183+
}
184+
185+
client := &http.Client{Timeout: DEFAULT_TIMEOUT}
186+
if request.timeout != time.Duration(0) {
187+
client.Timeout = request.timeout
188+
}
189+
190+
httpRequest.Header.Set("Content-Type", string(request.contentType))
191+
192+
if request.authToken != NOT_ASSIGNED {
193+
httpRequest.Header.Set("Authorization", fmt.Sprintf("%s %s", AUTHORIZATION_TOKEN_PREFIX, request.authToken))
194+
}
195+
196+
if request.host != NOT_ASSIGNED {
197+
httpRequest.Host = request.host
198+
}
199+
200+
if request.authUserName != NOT_ASSIGNED && request.authPassword != NOT_ASSIGNED {
201+
httpRequest.SetBasicAuth(request.authUserName, request.authPassword) // move to config
202+
}
203+
204+
if request.basicAuth != NOT_ASSIGNED {
205+
httpRequest.Header.Set("Authorization", "Basic "+request.basicAuth)
206+
}
207+
208+
if request.customHeaders != nil {
209+
for k, v := range request.customHeaders {
210+
httpRequest.Header.Add(k, v)
211+
}
212+
}
213+
214+
response, httpErr := client.Do(httpRequest)
215+
216+
if httpErr != nil {
217+
customError = error.NewCustomError(error.API_REQUEST_ERROR, fmt.Sprintf("url: %s; error: %s", url.String(), httpErr.Error())).
218+
WithParam("request", fmt.Sprintf("%+v", request))
219+
customError.Log()
220+
return
221+
}
222+
223+
defer response.Body.Close()
224+
225+
if response.StatusCode != http.StatusOK {
226+
body, _ = ioutil.ReadAll(response.Body)
227+
responseMap := map[string]string{}
228+
err = json.Unmarshal(body, &responseMap)
229+
customError = error.NewCustomError(error.API_REQUEST_STATUS_ERROR, fmt.Sprintf("url: %s; status code: %d; status: %s; body: %+v", url.String(), response.StatusCode, response.Status, responseMap)).
230+
WithParam("response", string(body)).
231+
WithParam("request", fmt.Sprintf("%+v", request))
232+
customError.WithParam("response-json", string(body))
233+
customError.Log()
234+
return
235+
}
236+
237+
body, _ = ioutil.ReadAll(response.Body)
238+
return
239+
}

go.mod

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module github.com/abhinav-codealchemist/http-wrapper-go
2+
3+
go 1.16
4+
5+
require (
6+
github.com/abhinav-codealchemist/custom-error-go v0.0.0-20210502113441-01e78117fd9d
7+
github.com/ajg/form v1.5.1
8+
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
github.com/abhinav-codealchemist/custom-error-go v0.0.0-20210502113441-01e78117fd9d/go.mod h1:80nTTGlA2EzKuRRm2yTGRTlATo0o4BIUhV3LoJdh9aM=
2+
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=

0 commit comments

Comments
 (0)