Added http sender SendJSON

This commit is contained in:
Quentin Renard
2020-10-19 11:51:12 +02:00
parent ae161d3d9c
commit b344292047
2 changed files with 129 additions and 6 deletions

67
http.go
View File

@@ -1,7 +1,10 @@
package astikit
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net"
@@ -14,6 +17,8 @@ import (
"time"
)
var ErrHTTPSenderUnmarshaledError = errors.New("astikit: unmarshaled error")
// ServeHTTPOptions represents serve options
type ServeHTTPOptions struct {
Addr string
@@ -179,6 +184,68 @@ func (s *HTTPSender) SendWithTimeout(req *http.Request, timeout time.Duration) (
return
}
// HTTPSendJSONOptions represents SendJSON options
type HTTPSendJSONOptions struct {
BodyError interface{}
BodyIn interface{}
BodyOut interface{}
Method string
URL string
}
// SendJSON sends a new JSON HTTP request
func (s *HTTPSender) SendJSON(o HTTPSendJSONOptions) (err error) {
// Marshal body in
var bi io.Reader
if o.BodyIn != nil {
bb := &bytes.Buffer{}
if err = json.NewEncoder(bb).Encode(o.BodyIn); err != nil {
err = fmt.Errorf("astikit: marshaling body in failed: %w", err)
return
}
bi = bb
}
// Create request
var req *http.Request
if req, err = http.NewRequest(o.Method, o.URL, bi); err != nil {
err = fmt.Errorf("astikit: creating request failed: %w", err)
return
}
// Send request
var resp *http.Response
if resp, err = s.Send(req); err != nil {
err = fmt.Errorf("astikit: sending request failed: %w", err)
return
}
defer resp.Body.Close()
// Process status code
if code := resp.StatusCode; code < 200 || code > 299 {
// Try unmarshaling error
if o.BodyError != nil {
if err2 := json.NewDecoder(resp.Body).Decode(o.BodyError); err2 == nil {
err = ErrHTTPSenderUnmarshaledError
return
}
}
// Default error
err = fmt.Errorf("astikit: invalid status code %d", code)
return
}
// Unmarshal body out
if o.BodyOut != nil {
if err = json.NewDecoder(resp.Body).Decode(o.BodyOut); err != nil {
err = fmt.Errorf("astikit: unmarshaling failed: %w", err)
return
}
}
return
}
// HTTPResponseFunc is a func that can process an $http.Response
type HTTPResponseFunc func(resp *http.Response) error

View File

@@ -3,6 +3,8 @@ package astikit
import (
"bytes"
"context"
"encoding/json"
"errors"
"io/ioutil"
"net"
"net/http"
@@ -60,8 +62,7 @@ func TestHTTPSender(t *testing.T) {
}),
RetryMax: 3,
})
_, err := s.Send(&http.Request{})
if err == nil {
if _, err := s.Send(&http.Request{}); err == nil {
t.Error("expected error, got nil")
}
if e := 4; c != e {
@@ -86,8 +87,7 @@ func TestHTTPSender(t *testing.T) {
}),
RetryMax: 3,
})
_, err = s.Send(&http.Request{})
if err != nil {
if _, err := s.Send(&http.Request{}); err != nil {
t.Errorf("expected no error, got %+v", err)
}
if e := 3; c != e {
@@ -103,10 +103,66 @@ func TestHTTPSender(t *testing.T) {
return
}),
})
_, err = s.SendWithTimeout(&http.Request{}, time.Millisecond)
if err == nil {
if _, err := s.SendWithTimeout(&http.Request{}, time.Millisecond); err == nil {
t.Error("expected error, got nil")
}
// JSON
const (
ebe = "error"
ebi = "body-in"
ebo = "body-out"
eu = "https://domain.com/url"
)
var gu, gbi string
s = NewHTTPSender(HTTPSenderOptions{
Client: mockedHTTPClient(func(req *http.Request) (resp *http.Response, err error) {
switch req.Method {
case http.MethodHead:
gu = req.URL.String()
resp = &http.Response{Body: ioutil.NopCloser(&bytes.Buffer{}), StatusCode: http.StatusBadRequest}
case http.MethodPost:
json.NewDecoder(req.Body).Decode(&gbi)
resp = &http.Response{Body: ioutil.NopCloser(bytes.NewBuffer([]byte("\"" + ebe + "\""))), StatusCode: http.StatusBadRequest}
case http.MethodGet:
resp = &http.Response{Body: ioutil.NopCloser(bytes.NewBuffer([]byte("\"" + ebo + "\""))), StatusCode: http.StatusOK}
}
return
}),
})
if err := s.SendJSON(HTTPSendJSONOptions{
Method: http.MethodHead,
URL: eu,
}); err == nil {
t.Error("expected error, got nil")
}
if gu != eu {
t.Errorf("expected %s, got %s", eu, gu)
}
var gbe string
if err := s.SendJSON(HTTPSendJSONOptions{
BodyError: &gbe,
BodyIn: ebi,
Method: http.MethodPost,
}); !errors.Is(err, ErrHTTPSenderUnmarshaledError) {
t.Errorf("expected ErrHTTPSenderUnmarshaledError, got %s", err)
}
if gbe != ebe {
t.Errorf("expected %s, got %s", ebe, gbe)
}
if gbi != ebi {
t.Errorf("expected %s, got %s", ebi, gbi)
}
var gbo string
if err := s.SendJSON(HTTPSendJSONOptions{
BodyOut: &gbo,
Method: http.MethodGet,
}); err != nil {
t.Errorf("expected no error, got %s", err)
}
if gbo != ebo {
t.Errorf("expected %s, go %s", ebo, gbo)
}
}
func TestHTTPDownloader(t *testing.T) {