Skip to content

Commit

Permalink
feat: Add the post with headers util function for HTTP clients (#955)
Browse files Browse the repository at this point in the history
* feat: Add the post with headers util function for HTTP clients

Fixes #954. Add the post with headers util function for HTTP clients.

Signed-off-by: Lindsey Cheng <[email protected]>

* fix: Add HTTP 403 code to errors.KindIOError func

Signed-off-by: Lindsey Cheng <[email protected]>

* fix: Add the KindForbidden ErrKind to errors pkg

Signed-off-by: Lindsey Cheng <[email protected]>

* fix: Return both response and error in sendRequest util func

Signed-off-by: Lindsey Cheng <[email protected]>

* fix: Export SendRequest util function

Export SendRequest and CreateRequestWithRawDataAndHeaders functions.

Signed-off-by: Lindsey Cheng <[email protected]>

* fix: Export all CreateRequest related methods

Signed-off-by: Lindsey Cheng <[email protected]>

---------

Signed-off-by: Lindsey Cheng <[email protected]>
  • Loading branch information
lindseysimple authored Nov 27, 2024
1 parent 3c1c392 commit 9164bc1
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 27 deletions.
32 changes: 23 additions & 9 deletions clients/http/utils/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func makeRequest(req *http.Request, authInjector interfaces.AuthenticationInject
return resp, nil
}

func createRequest(ctx context.Context, httpMethod string, baseUrl string, requestPath string, requestParams url.Values) (*http.Request, errors.EdgeX) {
func CreateRequest(ctx context.Context, httpMethod string, baseUrl string, requestPath string, requestParams url.Values) (*http.Request, errors.EdgeX) {
u, err := parseBaseUrlAndRequestPath(baseUrl, requestPath)
if err != nil {
return nil, errors.NewCommonEdgeX(errors.KindServerError, "failed to parse baseUrl and requestPath", err)
Expand All @@ -91,7 +91,7 @@ func createRequest(ctx context.Context, httpMethod string, baseUrl string, reque
return req, nil
}

func createRequestWithRawDataAndParams(ctx context.Context, httpMethod string, baseUrl string, requestPath string, requestParams url.Values, data interface{}) (*http.Request, errors.EdgeX) {
func CreateRequestWithRawDataAndParams(ctx context.Context, httpMethod string, baseUrl string, requestPath string, requestParams url.Values, data interface{}) (*http.Request, errors.EdgeX) {
u, err := parseBaseUrlAndRequestPath(baseUrl, requestPath)
if err != nil {
return nil, errors.NewCommonEdgeX(errors.KindServerError, "failed to parse baseUrl and requestPath", err)
Expand All @@ -118,7 +118,7 @@ func createRequestWithRawDataAndParams(ctx context.Context, httpMethod string, b
return req, nil
}

func createRequestWithRawData(ctx context.Context, httpMethod string, baseUrl string, requestPath string, requestParams url.Values, data interface{}) (*http.Request, errors.EdgeX) {
func CreateRequestWithRawData(ctx context.Context, httpMethod string, baseUrl string, requestPath string, requestParams url.Values, data interface{}) (*http.Request, errors.EdgeX) {
u, err := parseBaseUrlAndRequestPath(baseUrl, requestPath)
if err != nil {
return nil, errors.NewCommonEdgeX(errors.KindServerError, "failed to parse baseUrl and requestPath", err)
Expand Down Expand Up @@ -146,7 +146,21 @@ func createRequestWithRawData(ctx context.Context, httpMethod string, baseUrl st
return req, nil
}

func createRequestWithEncodedData(ctx context.Context, httpMethod string, baseUrl string, requestPath string, data []byte, encoding string) (*http.Request, errors.EdgeX) {
func CreateRequestWithRawDataAndHeaders(ctx context.Context, httpMethod string, baseUrl string, requestPath string, requestParams url.Values, data any, headers map[string]string) (*http.Request, errors.EdgeX) {
req, err := CreateRequestWithRawData(ctx, httpMethod, baseUrl, requestPath, requestParams, data)
if err != nil {
return nil, errors.NewCommonEdgeXWrapper(err)
}

// Add the additional headers from request
for name, value := range headers {
req.Header.Set(name, value)
}

return req, nil
}

func CreateRequestWithEncodedData(ctx context.Context, httpMethod string, baseUrl string, requestPath string, data []byte, encoding string) (*http.Request, errors.EdgeX) {
u, err := parseBaseUrlAndRequestPath(baseUrl, requestPath)
if err != nil {
return nil, errors.NewCommonEdgeX(errors.KindServerError, "failed to parse baseUrl and requestPath", err)
Expand All @@ -166,8 +180,8 @@ func createRequestWithEncodedData(ctx context.Context, httpMethod string, baseUr
return req, nil
}

// createRequestFromFilePath creates multipart/form-data request with the specified file
func createRequestFromFilePath(ctx context.Context, httpMethod string, baseUrl string, requestPath string, filePath string) (*http.Request, errors.EdgeX) {
// CreateRequestFromFilePath creates multipart/form-data request with the specified file
func CreateRequestFromFilePath(ctx context.Context, httpMethod string, baseUrl string, requestPath string, filePath string) (*http.Request, errors.EdgeX) {
u, err := parseBaseUrlAndRequestPath(baseUrl, requestPath)
if err != nil {
return nil, errors.NewCommonEdgeX(errors.KindServerError, "failed to parse baseUrl and requestPath", err)
Expand Down Expand Up @@ -199,9 +213,9 @@ func createRequestFromFilePath(ctx context.Context, httpMethod string, baseUrl s
return req, nil
}

// sendRequest will make a request with raw data to the specified URL.
// SendRequest will make a request with raw data to the specified URL.
// It returns the body as a byte array if successful and an error otherwise.
func sendRequest(ctx context.Context, req *http.Request, authInjector interfaces.AuthenticationInjector) ([]byte, errors.EdgeX) {
func SendRequest(ctx context.Context, req *http.Request, authInjector interfaces.AuthenticationInjector) ([]byte, errors.EdgeX) {
resp, err := makeRequest(req, authInjector)
if err != nil {
return nil, errors.NewCommonEdgeXWrapper(err)
Expand All @@ -220,7 +234,7 @@ func sendRequest(ctx context.Context, req *http.Request, authInjector interfaces
// Handle error response
msg := fmt.Sprintf("request failed, status code: %d, err: %s", resp.StatusCode, string(bodyBytes))
errKind := errors.KindMapping(resp.StatusCode)
return nil, errors.NewCommonEdgeX(errKind, msg, nil)
return bodyBytes, errors.NewCommonEdgeX(errKind, msg, nil)
}

// EscapeAndJoinPath escape and join the path variables
Expand Down
10 changes: 5 additions & 5 deletions clients/http/utils/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func TestCreateRequest(t *testing.T) {
}
for _, testCase := range tests {
t.Run(testCase.name, func(t *testing.T) {
_, err := createRequest(context.Background(), http.MethodGet, baseUrl, requestPath, nil)
_, err := CreateRequest(context.Background(), http.MethodGet, baseUrl, requestPath, nil)
assert.NoError(t, err)
})
}
Expand All @@ -48,7 +48,7 @@ func TestCreateRequestWithRawData(t *testing.T) {
}
for _, testCase := range tests {
t.Run(testCase.name, func(t *testing.T) {
_, err := createRequestWithRawData(context.Background(), http.MethodGet, baseUrl, requestPath, nil, models.Event{})
_, err := CreateRequestWithRawData(context.Background(), http.MethodGet, baseUrl, requestPath, nil, models.Event{})
assert.NoError(t, err)
})
}
Expand All @@ -67,7 +67,7 @@ func TestCreateRequestWithRawDataAndParams(t *testing.T) {
}
for _, testCase := range tests {
t.Run(testCase.name, func(t *testing.T) {
_, err := createRequestWithRawDataAndParams(context.Background(), http.MethodGet, baseUrl, requestPath, nil, models.Event{})
_, err := CreateRequestWithRawDataAndParams(context.Background(), http.MethodGet, baseUrl, requestPath, nil, models.Event{})
assert.NoError(t, err)
})
}
Expand All @@ -86,7 +86,7 @@ func TestCreateRequestWithEncodedData(t *testing.T) {
}
for _, testCase := range tests {
t.Run(testCase.name, func(t *testing.T) {
_, err := createRequestWithEncodedData(context.Background(), http.MethodGet, baseUrl, requestPath, nil, "")
_, err := CreateRequestWithEncodedData(context.Background(), http.MethodGet, baseUrl, requestPath, nil, "")
assert.NoError(t, err)
})
}
Expand All @@ -109,7 +109,7 @@ func TestCreateRequestFromFilePath(t *testing.T) {
}
for _, testCase := range tests {
t.Run(testCase.name, func(t *testing.T) {
_, err := createRequestFromFilePath(context.Background(), http.MethodGet, baseUrl, requestPath, f.Name())
_, err := CreateRequestFromFilePath(context.Background(), http.MethodGet, baseUrl, requestPath, f.Name())
assert.NoError(t, err)
})
}
Expand Down
41 changes: 29 additions & 12 deletions clients/http/utils/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (

// GetRequest makes the get request and return the body
func GetRequest(ctx context.Context, returnValuePointer interface{}, baseUrl string, requestPath string, requestParams url.Values, authInjector interfaces.AuthenticationInjector) errors.EdgeX {
req, err := createRequest(ctx, http.MethodGet, baseUrl, requestPath, requestParams)
req, err := CreateRequest(ctx, http.MethodGet, baseUrl, requestPath, requestParams)
if err != nil {
return errors.NewCommonEdgeXWrapper(err)
}
Expand All @@ -30,7 +30,7 @@ func GetRequest(ctx context.Context, returnValuePointer interface{}, baseUrl str

// GetRequestAndReturnBinaryRes makes the get request and return the binary response and content type(i.e., application/json, application/cbor, ... )
func GetRequestAndReturnBinaryRes(ctx context.Context, baseUrl string, requestPath string, requestParams url.Values, authInjector interfaces.AuthenticationInjector) (res []byte, contentType string, edgeXerr errors.EdgeX) {
req, edgeXerr := createRequest(ctx, http.MethodGet, baseUrl, requestPath, requestParams)
req, edgeXerr := CreateRequest(ctx, http.MethodGet, baseUrl, requestPath, requestParams)
if edgeXerr != nil {
return nil, "", errors.NewCommonEdgeXWrapper(edgeXerr)
}
Expand Down Expand Up @@ -60,7 +60,7 @@ func GetRequestAndReturnBinaryRes(ctx context.Context, baseUrl string, requestPa

// GetRequestWithBodyRawData makes the GET request with JSON raw data as request body and return the response
func GetRequestWithBodyRawData(ctx context.Context, returnValuePointer interface{}, baseUrl string, requestPath string, requestParams url.Values, data interface{}, authInjector interfaces.AuthenticationInjector) errors.EdgeX {
req, err := createRequestWithRawDataAndParams(ctx, http.MethodGet, baseUrl, requestPath, requestParams, data)
req, err := CreateRequestWithRawDataAndParams(ctx, http.MethodGet, baseUrl, requestPath, requestParams, data)
if err != nil {
return errors.NewCommonEdgeXWrapper(err)
}
Expand All @@ -76,7 +76,7 @@ func PostRequest(
data []byte,
encoding string, authInjector interfaces.AuthenticationInjector) errors.EdgeX {

req, err := createRequestWithEncodedData(ctx, http.MethodPost, baseUrl, requestPath, data, encoding)
req, err := CreateRequestWithEncodedData(ctx, http.MethodPost, baseUrl, requestPath, data, encoding)
if err != nil {
return errors.NewCommonEdgeXWrapper(err)
}
Expand All @@ -92,7 +92,24 @@ func PostRequestWithRawData(
requestParams url.Values,
data interface{}, authInjector interfaces.AuthenticationInjector) errors.EdgeX {

req, err := createRequestWithRawData(ctx, http.MethodPost, baseUrl, requestPath, requestParams, data)
req, err := CreateRequestWithRawData(ctx, http.MethodPost, baseUrl, requestPath, requestParams, data)
if err != nil {
return errors.NewCommonEdgeXWrapper(err)
}

return processRequest(ctx, returnValuePointer, req, authInjector)
}

// PostRequestWithRawDataAndHeaders makes the post JSON request with raw data and request headers, and returns the body
func PostRequestWithRawDataAndHeaders(
ctx context.Context,
returnValuePointer interface{},
baseUrl string, requestPath string,
requestParams url.Values,
data interface{}, authInjector interfaces.AuthenticationInjector,
headers map[string]string) errors.EdgeX {

req, err := CreateRequestWithRawDataAndHeaders(ctx, http.MethodPost, baseUrl, requestPath, requestParams, data, headers)
if err != nil {
return errors.NewCommonEdgeXWrapper(err)
}
Expand All @@ -108,7 +125,7 @@ func PutRequest(
requestParams url.Values,
data interface{}, authInjector interfaces.AuthenticationInjector) errors.EdgeX {

req, err := createRequestWithRawData(ctx, http.MethodPut, baseUrl, requestPath, requestParams, data)
req, err := CreateRequestWithRawData(ctx, http.MethodPut, baseUrl, requestPath, requestParams, data)
if err != nil {
return errors.NewCommonEdgeXWrapper(err)
}
Expand All @@ -124,7 +141,7 @@ func PatchRequest(
requestParams url.Values,
data interface{}, authInjector interfaces.AuthenticationInjector) errors.EdgeX {

req, err := createRequestWithRawData(ctx, http.MethodPatch, baseUrl, requestPath, requestParams, data)
req, err := CreateRequestWithRawData(ctx, http.MethodPatch, baseUrl, requestPath, requestParams, data)
if err != nil {
return errors.NewCommonEdgeXWrapper(err)
}
Expand All @@ -139,7 +156,7 @@ func PostByFileRequest(
baseUrl string, requestPath string,
filePath string, authInjector interfaces.AuthenticationInjector) errors.EdgeX {

req, err := createRequestFromFilePath(ctx, http.MethodPost, baseUrl, requestPath, filePath)
req, err := CreateRequestFromFilePath(ctx, http.MethodPost, baseUrl, requestPath, filePath)
if err != nil {
return errors.NewCommonEdgeXWrapper(err)
}
Expand All @@ -154,7 +171,7 @@ func PutByFileRequest(
baseUrl string, requestPath string,
filePath string, authInjector interfaces.AuthenticationInjector) errors.EdgeX {

req, err := createRequestFromFilePath(ctx, http.MethodPut, baseUrl, requestPath, filePath)
req, err := CreateRequestFromFilePath(ctx, http.MethodPut, baseUrl, requestPath, filePath)
if err != nil {
return errors.NewCommonEdgeXWrapper(err)
}
Expand All @@ -164,7 +181,7 @@ func PutByFileRequest(

// DeleteRequest makes the delete request and return the body
func DeleteRequest(ctx context.Context, returnValuePointer interface{}, baseUrl string, requestPath string, authInjector interfaces.AuthenticationInjector) errors.EdgeX {
req, err := createRequest(ctx, http.MethodDelete, baseUrl, requestPath, nil)
req, err := CreateRequest(ctx, http.MethodDelete, baseUrl, requestPath, nil)
if err != nil {
return errors.NewCommonEdgeXWrapper(err)
}
Expand All @@ -174,7 +191,7 @@ func DeleteRequest(ctx context.Context, returnValuePointer interface{}, baseUrl

// DeleteRequestWithParams makes the delete request with URL query params and return the body
func DeleteRequestWithParams(ctx context.Context, returnValuePointer interface{}, baseUrl string, requestPath string, requestParams url.Values, authInjector interfaces.AuthenticationInjector) errors.EdgeX {
req, err := createRequest(ctx, http.MethodDelete, baseUrl, requestPath, requestParams)
req, err := CreateRequest(ctx, http.MethodDelete, baseUrl, requestPath, requestParams)
if err != nil {
return errors.NewCommonEdgeXWrapper(err)
}
Expand All @@ -185,7 +202,7 @@ func DeleteRequestWithParams(ctx context.Context, returnValuePointer interface{}
// processRequest is a helper function to process the request and get the return value
func processRequest(ctx context.Context,
returnValuePointer any, req *http.Request, authInjector interfaces.AuthenticationInjector) errors.EdgeX {
resp, err := sendRequest(ctx, req, authInjector)
resp, err := SendRequest(ctx, req, authInjector)
if err != nil {
return errors.NewCommonEdgeXWrapper(err)
}
Expand Down
5 changes: 4 additions & 1 deletion errors/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const (
KindOverflowError ErrKind = "OverflowError"
KindNaNError ErrKind = "NaNError"
KindUnauthorized ErrKind = "Unauthorized"
KindForbidden ErrKind = "Forbidden"
)

// EdgeX provides an abstraction for all internal EdgeX errors.
Expand Down Expand Up @@ -209,7 +210,7 @@ func codeMapping(kind ErrKind) int {
return http.StatusMethodNotAllowed
case KindRangeNotSatisfiable:
return http.StatusRequestedRangeNotSatisfiable
case KindIOError:
case KindIOError, KindForbidden:
return http.StatusForbidden
case KindUnauthorized:
return http.StatusUnauthorized
Expand Down Expand Up @@ -245,6 +246,8 @@ func KindMapping(code int) ErrKind {
return KindRangeNotSatisfiable
case http.StatusUnauthorized:
return KindUnauthorized
case http.StatusForbidden:
return KindForbidden
default:
return KindUnknown
}
Expand Down

0 comments on commit 9164bc1

Please sign in to comment.