mirror of
https://github.com/asticode/go-astikit.git
synced 2025-12-24 11:50:53 +08:00
Added http sender SendJSON
This commit is contained in:
67
http.go
67
http.go
@@ -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
|
||||
|
||||
|
||||
68
http_test.go
68
http_test.go
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user