👷 Add JSONEncoder and JSONDecoder

pull/1177/head
Kiyon 2021-02-20 16:45:13 +08:00
parent c477128e5b
commit c34ca83c06
6 changed files with 97 additions and 34 deletions

View File

@ -16,6 +16,8 @@ import (
"sync" "sync"
"time" "time"
"github.com/gofiber/fiber/v2/utils"
"github.com/gofiber/fiber/v2/internal/encoding/json" "github.com/gofiber/fiber/v2/internal/encoding/json"
"github.com/valyala/fasthttp" "github.com/valyala/fasthttp"
) )
@ -59,6 +61,18 @@ type Client struct {
// NoDefaultUserAgentHeader when set to true, causes the default // NoDefaultUserAgentHeader when set to true, causes the default
// User-Agent header to be excluded from the Request. // User-Agent header to be excluded from the Request.
NoDefaultUserAgentHeader bool NoDefaultUserAgentHeader bool
// When set by an external client of Fiber it will use the provided implementation of a
// JSONMarshal
//
// Allowing for flexibility in using another json library for encoding
JSONEncoder utils.JSONMarshal
// When set by an external client of Fiber it will use the provided implementation of a
// JSONUnmarshal
//
// Allowing for flexibility in using another json library for decoding
JSONDecoder utils.JSONUnmarshal
} }
// Get returns a agent with http method GET. // Get returns a agent with http method GET.
@ -116,6 +130,8 @@ func (c *Client) createAgent(method, url string) *Agent {
a.Name = c.UserAgent a.Name = c.UserAgent
a.NoDefaultUserAgentHeader = c.NoDefaultUserAgentHeader a.NoDefaultUserAgentHeader = c.NoDefaultUserAgentHeader
a.jsonDecoder = c.JSONDecoder
a.jsonEncoder = c.JSONEncoder
if err := a.Parse(); err != nil { if err := a.Parse(); err != nil {
a.errs = append(a.errs, err) a.errs = append(a.errs, err)
@ -135,6 +151,8 @@ type Agent struct {
formFiles []*FormFile formFiles []*FormFile
debugWriter io.Writer debugWriter io.Writer
mw multipartWriter mw multipartWriter
jsonEncoder utils.JSONMarshal
jsonDecoder utils.JSONUnmarshal
maxRedirectsCount int maxRedirectsCount int
boundary string boundary string
Name string Name string
@ -450,9 +468,13 @@ func (a *Agent) Request(req *Request) *Agent {
// JSON sends a JSON request. // JSON sends a JSON request.
func (a *Agent) JSON(v interface{}) *Agent { func (a *Agent) JSON(v interface{}) *Agent {
if a.jsonEncoder == nil {
a.jsonEncoder = json.Marshal
}
a.req.Header.SetContentType(MIMEApplicationJSON) a.req.Header.SetContentType(MIMEApplicationJSON)
if body, err := json.Marshal(v); err != nil { if body, err := a.jsonEncoder(v); err != nil {
a.errs = append(a.errs, err) a.errs = append(a.errs, err)
} else { } else {
a.req.SetBody(body) a.req.SetBody(body)
@ -658,6 +680,20 @@ func (a *Agent) MaxRedirectsCount(count int) *Agent {
return a return a
} }
// JSONEncoder sets custom json encoder.
func (a *Agent) JSONEncoder(jsonEncoder utils.JSONMarshal) *Agent {
a.jsonEncoder = jsonEncoder
return a
}
// JSONDecoder sets custom json decoder.
func (a *Agent) JSONDecoder(jsonDecoder utils.JSONUnmarshal) *Agent {
a.jsonDecoder = jsonDecoder
return a
}
/************************** End Agent Setting **************************/ /************************** End Agent Setting **************************/
// Bytes returns the status code, bytes body and errors of url. // Bytes returns the status code, bytes body and errors of url.
@ -738,9 +774,13 @@ func (a *Agent) String(resp ...*Response) (int, string, []error) {
// Struct returns the status code, bytes body and errors of url. // Struct returns the status code, bytes body and errors of url.
// And bytes body will be unmarshalled to given v. // And bytes body will be unmarshalled to given v.
func (a *Agent) Struct(v interface{}, resp ...*Response) (code int, body []byte, errs []error) { func (a *Agent) Struct(v interface{}, resp ...*Response) (code int, body []byte, errs []error) {
if a.jsonDecoder == nil {
a.jsonDecoder = json.Unmarshal
}
code, body, errs = a.Bytes(resp...) code, body, errs = a.Bytes(resp...)
if err := json.Unmarshal(body, v); err != nil { if err := a.jsonDecoder(body, v); err != nil {
errs = append(errs, err) errs = append(errs, err)
} }

View File

@ -15,6 +15,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/gofiber/fiber/v2/internal/encoding/json"
"github.com/gofiber/fiber/v2/utils" "github.com/gofiber/fiber/v2/utils"
"github.com/valyala/fasthttp/fasthttputil" "github.com/valyala/fasthttp/fasthttputil"
) )
@ -532,6 +534,7 @@ func Test_Client_Agent_Json(t *testing.T) {
func Test_Client_Agent_Json_Error(t *testing.T) { func Test_Client_Agent_Json_Error(t *testing.T) {
a := Get("http://example.com"). a := Get("http://example.com").
JSONEncoder(json.Marshal).
JSON(complex(1, 1)) JSON(complex(1, 1))
_, body, errs := a.String() _, body, errs := a.String()
@ -947,7 +950,8 @@ func Test_Client_Agent_Struct(t *testing.T) {
var d data var d data
code, body, errs := a.Struct(&d) code, body, errs := a.JSONDecoder(json.Unmarshal).
Struct(&d)
utils.AssertEqual(t, StatusOK, code) utils.AssertEqual(t, StatusOK, code)
utils.AssertEqual(t, `{"success"`, string(body)) utils.AssertEqual(t, `{"success"`, string(body))

9
utils/json.go Normal file
View File

@ -0,0 +1,9 @@
package utils
// JSONMarshal returns the JSON encoding of v.
type JSONMarshal func(v interface{}) ([]byte, error)
// JSONUnmarshal parses the JSON-encoded data and stores the result
// in the value pointed to by v. If v is nil or not a pointer,
// Unmarshal returns an InvalidUnmarshalError.
type JSONUnmarshal func(data []byte, v interface{}) error

View File

@ -1,5 +0,0 @@
package utils
// JSONMarshal is the standard definition of representing a Go structure in
// json format
type JSONMarshal func(interface{}) ([]byte, error)

View File

@ -1,26 +0,0 @@
package utils
import (
"encoding/json"
"testing"
)
func TestDefaultJSONEncoder(t *testing.T) {
type SampleStructure struct {
ImportantString string `json:"important_string"`
}
var (
sampleStructure = &SampleStructure{
ImportantString: "Hello World",
}
importantString = `{"important_string":"Hello World"}`
jsonEncoder JSONMarshal = json.Marshal
)
raw, err := jsonEncoder(sampleStructure)
AssertEqual(t, err, nil)
AssertEqual(t, string(raw), importantString)
}

41
utils/json_test.go Normal file
View File

@ -0,0 +1,41 @@
package utils
import (
"encoding/json"
"testing"
)
type sampleStructure struct {
ImportantString string `json:"important_string"`
}
func Test_DefaultJSONEncoder(t *testing.T) {
t.Parallel()
var (
ss = &sampleStructure{
ImportantString: "Hello World",
}
importantString = `{"important_string":"Hello World"}`
jsonEncoder JSONMarshal = json.Marshal
)
raw, err := jsonEncoder(ss)
AssertEqual(t, err, nil)
AssertEqual(t, string(raw), importantString)
}
func Test_DefaultJSONDecoder(t *testing.T) {
t.Parallel()
var (
ss sampleStructure
importantString = []byte(`{"important_string":"Hello World"}`)
jsonDecoder JSONUnmarshal = json.Unmarshal
)
err := jsonDecoder(importantString, &ss)
AssertEqual(t, err, nil)
AssertEqual(t, "Hello World", ss.ImportantString)
}