Skip to content

Commit

Permalink
add headers
Browse files Browse the repository at this point in the history
  • Loading branch information
mattkasun committed Nov 11, 2022
1 parent a38ed1d commit f40d7b8
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 39 deletions.
13 changes: 8 additions & 5 deletions examples/functions/json/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"log"
"net/http"
"strings"

"github.com/devilcove/httpclient"
)
Expand All @@ -15,12 +16,14 @@ type Answer struct {
// equivalient of curl api.ipify.org?format=json
func main() {
var answer Answer
ip, code, err := httpclient.GetJSON(nil, answer, http.MethodGet, "http://api.ipify.org?format=json", "")
var errResp any
ip, err := httpclient.GetJSON(nil, answer, errResp, http.MethodGet, "http://api.ipify.org?format=json", "", nil)
if err != nil {
log.Fatal(err)
}
if code != http.StatusOK {
log.Fatal(err, code)
if strings.Contains(err.Error(), "non ok status") {
fmt.Println(ip, err)
} else {
log.Fatal(err)
}
}
fmt.Println(ip)
}
2 changes: 1 addition & 1 deletion examples/functions/response/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

func main() {
response, err := httpclient.GetResponse(nil, http.MethodGet, "http://ifconfig.me", "")
response, err := httpclient.GetResponse(nil, http.MethodGet, "http://ifconfig.me", "", nil)
if err != nil {
log.Fatal(err)
}
Expand Down
9 changes: 4 additions & 5 deletions examples/method/json/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,20 @@ type Response struct {

func main() {
var response Response
endpoint := httpclient.JSONEndpoint[Response]{
var errResponse any
endpoint := httpclient.JSONEndpoint[Response, any]{
URL: "https://api.ipify.org?format=json",
Route: "",
Method: http.MethodGet,
Authorization: "",
Data: nil,
Response: response,
ErrorResponse: errResponse,
}
answer, code, err := endpoint.GetJSON(response)
answer, err := endpoint.GetJSON(response, errResponse)
if err != nil {
log.Fatal(err)
}
if code != http.StatusOK {
log.Fatal(err, code)
}
fmt.Println(answer)

}
51 changes: 36 additions & 15 deletions httpclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,39 @@ import (
"bytes"
"encoding/json"
"errors"
"fmt"
"net/http"
"time"
)

var Client http.Client
var ErrJSON = errors.New("httpclient: json error")
var ErrRequest = errors.New("httpclient: error creating http request")
var ErrStatus = errors.New("httpclient: http.Status not OK")

// Endpoint struct for an http endpoint
type Endpoint struct {
URL string
Method string
Route string
Authorization string
Headers []Header
Data any
}

type JSONEndpoint[T any] struct {
type JSONEndpoint[T any, R any] struct {
URL string
Method string
Route string
Authorization string
Headers []Header
Data any
Response T
ErrorResponse R
}

type Header struct {
Name string
Value string
}

func init() {
Expand All @@ -36,54 +46,65 @@ func init() {
}

// GetResponse returns respnse from http request to url
func GetResponse(data any, method, url, auth string) (*http.Response, error) {
func GetResponse(data any, method, url, auth string, headers []Header) (*http.Response, error) {
var request *http.Request
var response *http.Response
var err error
if data != nil {
payload, err := json.Marshal(data)
if err != nil {
return response, fmt.Errorf("error encoding data %w", err)
return response, ErrJSON
}
request, err = http.NewRequest(method, url, bytes.NewBuffer(payload))
if err != nil {
return response, fmt.Errorf("error creating http request %w", err)
return response, ErrRequest
}
request.Header.Set("Content-Type", "application/json")
} else {
request, err = http.NewRequest(method, url, nil)
if err != nil {
return response, fmt.Errorf("error creating http request %w", err)
return response, ErrRequest
}
}
if auth != "" {
request.Header.Set("Authorization", auth)
}
for _, header := range headers {
request.Header.Set(header.Name, header.Value)
}
return Client.Do(request)
}

// JSON returns JSON response from http request
func GetJSON[T any](data any, resp T, method, url, auth string) (any, int, error) {
response, err := GetResponse(data, method, url, auth)
// if response.code is http.StatusOK (200) returns body decoded to resp
// if response.code is not http.Status ok returns response(*http.Response) with err set to
// 'non ok response code'
// if json decode err returns response and err set to 'json decode err'
// for any other err returns nil and err
func GetJSON[T any, R any](data any, resp T, errResponse R, method, url, auth string, headers []Header) (any, error) {
response, err := GetResponse(data, method, url, auth, headers)
if err != nil {
return nil, response.StatusCode, err
return nil, err
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
return response, response.StatusCode, errors.New("non 200 response code")
if err := json.NewDecoder(response.Body).Decode(&errResponse); err != nil {
return response, ErrJSON
}
return errResponse, ErrStatus
}
if err := json.NewDecoder(response.Body).Decode(&resp); err != nil {
return nil, response.StatusCode, err
return response, ErrJSON
}
return resp, response.StatusCode, nil
return resp, nil
}

// GetResponse returns response from http endpoint
func (e *Endpoint) GetResponse() (*http.Response, error) {
return GetResponse(e.Data, e.Method, e.URL+e.Route, e.Authorization)
return GetResponse(e.Data, e.Method, e.URL+e.Route, e.Authorization, e.Headers)
}

// GetJSON returns JSON received from http endpoint
func (e *JSONEndpoint[T]) GetJSON(response T) (any, int, error) {
return GetJSON(e.Data, response, e.Method, e.URL+e.Route, e.Authorization)
func (e *JSONEndpoint[T, R]) GetJSON(response T, errResponse R) (any, error) {
return GetJSON(e.Data, response, errResponse, e.Method, e.URL+e.Route, e.Authorization, e.Headers)
}
27 changes: 14 additions & 13 deletions httpclient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (

func TestGetResponse(t *testing.T) {
t.Run("ip endpoint", func(t *testing.T) {
response, err := GetResponse(nil, http.MethodGet, "https://firefly.nusak.ca/ip", "")
response, err := GetResponse(nil, http.MethodGet, "https://firefly.nusak.ca/ip", "", nil)
is := is.New(t)
is.NoErr(err)
is.Equal(response.StatusCode, http.StatusOK)
Expand All @@ -26,7 +26,7 @@ func TestGetResponse(t *testing.T) {
}
})
t.Run("invalid endpoint", func(t *testing.T) {
response, err := GetResponse(nil, http.MethodGet, "https://firefly.nusak.ca/invalidendpoint", "")
response, err := GetResponse(nil, http.MethodGet, "https://firefly.nusak.ca/invalidendpoint", "", nil)
is := is.New(t)
is.NoErr(err)
is.Equal(response.StatusCode, http.StatusNotFound)
Expand All @@ -42,12 +42,12 @@ func TestGetResponse(t *testing.T) {
jwt := struct {
JWT string
}{}
response, err := GetResponse(data, http.MethodPost, "https://firefly.nusak.ca/login", "")
response, err := GetResponse(data, http.MethodPost, "https://firefly.nusak.ca/login", "", nil)
is := is.New(t)
is.NoErr(err)
defer response.Body.Close()
is.NoErr(json.NewDecoder(response.Body).Decode(&jwt))
response, err = GetResponse("", http.MethodGet, "https://firefly.nusak.ca/api/hello", jwt.JWT)
response, err = GetResponse("", http.MethodGet, "https://firefly.nusak.ca/api/hello", jwt.JWT, nil)
is.NoErr(err)
is.Equal(response.StatusCode, http.StatusOK)
defer response.Body.Close()
Expand All @@ -70,7 +70,7 @@ func TestGetResponse(t *testing.T) {
}{}
var data Data
data.Pass = "badpass"
response, err := GetResponse(data, http.MethodPost, "https://firefly.nusak.ca/login", "")
response, err := GetResponse(data, http.MethodPost, "https://firefly.nusak.ca/login", "", nil)
is := is.New(t)
is.NoErr(err)
defer response.Body.Close()
Expand All @@ -96,16 +96,17 @@ func TestGetJSON(t *testing.T) {
response := struct {
JWT string
}{}
e := JSONEndpoint[struct{ JWT string }]{
URL: "http://firefly.nusak.ca",
Route: "/login",
Method: http.MethodPost,
Data: data,
Response: response,
var errResponse any
e := JSONEndpoint[struct{ JWT string }, any]{
URL: "http://firefly.nusak.ca",
Route: "/login",
Method: http.MethodPost,
Data: data,
Response: response,
ErrorResponse: errResponse,
}
answer, code, err := e.GetJSON(response)
answer, err := e.GetJSON(response, errResponse)
is.NoErr(err)
is.Equal(code, http.StatusOK)
answerType := fmt.Sprintf("%T", answer)
is.True(answerType == "struct { JWT string }")
})
Expand Down

0 comments on commit f40d7b8

Please sign in to comment.