mirror of https://github.com/gofiber/fiber.git
✨ feature: add XML to context. (#2003)
* ✨ feature: add XML to context.
* Update app.go
pull/2017/head
parent
6669ec4486
commit
95abdacba0
11
app.go
11
app.go
|
@ -23,6 +23,7 @@ import (
|
|||
"time"
|
||||
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
|
||||
"github.com/gofiber/fiber/v2/utils"
|
||||
"github.com/valyala/fasthttp"
|
||||
|
@ -324,6 +325,13 @@ type Config struct {
|
|||
// Default: json.Unmarshal
|
||||
JSONDecoder utils.JSONUnmarshal `json:"-"`
|
||||
|
||||
// XMLEncoder set by an external client of Fiber it will use the provided implementation of a
|
||||
// XMLMarshal
|
||||
//
|
||||
// Allowing for flexibility in using another XML library for encoding
|
||||
// Default: xml.Marshal
|
||||
XMLEncoder utils.XMLMarshal `json:"-"`
|
||||
|
||||
// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only)
|
||||
// WARNING: When prefork is set to true, only "tcp4" and "tcp6" can be chose.
|
||||
//
|
||||
|
@ -513,6 +521,9 @@ func New(config ...Config) *App {
|
|||
if app.config.JSONDecoder == nil {
|
||||
app.config.JSONDecoder = json.Unmarshal
|
||||
}
|
||||
if app.config.XMLEncoder == nil {
|
||||
app.config.XMLEncoder = xml.Marshal
|
||||
}
|
||||
if app.config.Network == "" {
|
||||
app.config.Network = NetworkTCP4
|
||||
}
|
||||
|
|
19
ctx.go
19
ctx.go
|
@ -518,12 +518,7 @@ func (c *Ctx) Format(body interface{}) error {
|
|||
case "txt":
|
||||
return c.SendString(b)
|
||||
case "xml":
|
||||
raw, err := xml.Marshal(body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error serializing xml: %v", body)
|
||||
}
|
||||
c.fasthttp.Response.SetBody(raw)
|
||||
return nil
|
||||
return c.XML(body)
|
||||
}
|
||||
return c.SendString(b)
|
||||
}
|
||||
|
@ -736,6 +731,18 @@ func (c *Ctx) JSONP(data interface{}, callback ...string) error {
|
|||
return c.SendString(result)
|
||||
}
|
||||
|
||||
// XML converts any interface or string to XML.
|
||||
// This method also sets the content header to application/xml.
|
||||
func (c *Ctx) XML(data interface{}) error {
|
||||
raw, err := c.app.config.XMLEncoder(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.fasthttp.Response.SetBodyRaw(raw)
|
||||
c.fasthttp.Response.Header.SetContentType(MIMEApplicationXML)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Links joins the links followed by the property to populate the response's Link HTTP header field.
|
||||
func (c *Ctx) Links(link ...string) {
|
||||
if len(link) == 0 {
|
||||
|
|
60
ctx_test.go
60
ctx_test.go
|
@ -12,6 +12,7 @@ import (
|
|||
"bytes"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -2134,6 +2135,65 @@ func Benchmark_Ctx_JSONP(b *testing.B) {
|
|||
utils.AssertEqual(b, `emit({"Name":"Grame","Age":20});`, string(c.Response().Body()))
|
||||
}
|
||||
|
||||
// go test -run Test_Ctx_XML
|
||||
func Test_Ctx_XML(t *testing.T) {
|
||||
t.Parallel()
|
||||
app := New()
|
||||
c := app.AcquireCtx(&fasthttp.RequestCtx{})
|
||||
defer app.ReleaseCtx(c)
|
||||
|
||||
utils.AssertEqual(t, true, c.JSON(complex(1, 1)) != nil)
|
||||
|
||||
type xmlResult struct {
|
||||
XMLName xml.Name `xml:"Users"`
|
||||
Names []string `xml:"Names"`
|
||||
Ages []int `xml:"Ages"`
|
||||
}
|
||||
|
||||
c.XML(xmlResult{
|
||||
Names: []string{"Grame", "John"},
|
||||
Ages: []int{1, 12, 20},
|
||||
})
|
||||
|
||||
utils.AssertEqual(t, `<Users><Names>Grame</Names><Names>John</Names><Ages>1</Ages><Ages>12</Ages><Ages>20</Ages></Users>`, string(c.Response().Body()))
|
||||
utils.AssertEqual(t, "application/xml", string(c.Response().Header.Peek("content-type")))
|
||||
|
||||
testEmpty := func(v interface{}, r string) {
|
||||
err := c.XML(v)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, r, string(c.Response().Body()))
|
||||
}
|
||||
|
||||
testEmpty(nil, "")
|
||||
testEmpty("", `<string></string>`)
|
||||
testEmpty(0, "<int>0</int>")
|
||||
testEmpty([]int{}, "")
|
||||
}
|
||||
|
||||
// go test -run=^$ -bench=Benchmark_Ctx_XML -benchmem -count=4
|
||||
func Benchmark_Ctx_XML(b *testing.B) {
|
||||
app := New()
|
||||
c := app.AcquireCtx(&fasthttp.RequestCtx{})
|
||||
defer app.ReleaseCtx(c)
|
||||
type SomeStruct struct {
|
||||
Name string `xml:"Name"`
|
||||
Age uint8 `xml:"Age"`
|
||||
}
|
||||
data := SomeStruct{
|
||||
Name: "Grame",
|
||||
Age: 20,
|
||||
}
|
||||
var err error
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
err = c.XML(data)
|
||||
}
|
||||
|
||||
utils.AssertEqual(b, nil, err)
|
||||
utils.AssertEqual(b, `<SomeStruct><Name>Grame</Name><Age>20</Age></SomeStruct>`, string(c.Response().Body()))
|
||||
}
|
||||
|
||||
// go test -run Test_Ctx_Links
|
||||
func Test_Ctx_Links(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
package utils
|
||||
|
||||
// XMLMarshal returns the XML encoding of v.
|
||||
type XMLMarshal func(v interface{}) ([]byte, error)
|
|
@ -0,0 +1,59 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type serversXMLStructure struct {
|
||||
XMLName xml.Name `xml:"servers"`
|
||||
Version string `xml:"version,attr"`
|
||||
Servers []serverXMLStructure `xml:"server"`
|
||||
}
|
||||
|
||||
type serverXMLStructure struct {
|
||||
XMLName xml.Name `xml:"server"`
|
||||
Name string `xml:"name"`
|
||||
}
|
||||
|
||||
var xmlString = `<servers version="1"><server><name>fiber one</name></server><server><name>fiber two</name></server></servers>`
|
||||
|
||||
func Test_GolangXMLEncoder(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var (
|
||||
ss = &serversXMLStructure{
|
||||
Version: "1",
|
||||
Servers: []serverXMLStructure{
|
||||
{Name: "fiber one"},
|
||||
{Name: "fiber two"},
|
||||
},
|
||||
}
|
||||
xmlEncoder XMLMarshal = xml.Marshal
|
||||
)
|
||||
|
||||
raw, err := xmlEncoder(ss)
|
||||
AssertEqual(t, err, nil)
|
||||
|
||||
AssertEqual(t, string(raw), xmlString)
|
||||
}
|
||||
|
||||
func Test_DefaultXMLEncoder(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var (
|
||||
ss = &serversXMLStructure{
|
||||
Version: "1",
|
||||
Servers: []serverXMLStructure{
|
||||
{Name: "fiber one"},
|
||||
{Name: "fiber two"},
|
||||
},
|
||||
}
|
||||
xmlEncoder XMLMarshal = xml.Marshal
|
||||
)
|
||||
|
||||
raw, err := xmlEncoder(ss)
|
||||
AssertEqual(t, err, nil)
|
||||
|
||||
AssertEqual(t, string(raw), xmlString)
|
||||
}
|
Loading…
Reference in New Issue