Skip to content

Commit db614ca

Browse files
authored
feat: add XML methods to context (#25)
1 parent 0ae9901 commit db614ca

File tree

4 files changed

+143
-4
lines changed

4 files changed

+143
-4
lines changed

context.go

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,17 +80,17 @@ func (c *Context) QueryParams() url.Values {
8080

8181
// JSON sends JSON response with the given status code.
8282
//
83-
// Returns an error happenedd during sending response.
83+
// Returns an error if an error happened during sending response otherwise returns nil.
8484
func (c *Context) JSON(code int, obj any) error {
8585
c.writeContentType("application/json")
8686
c.response.WriteHeader(code)
8787
return c.kid.jsonSerializer.Write(c.Response(), obj, "")
8888
}
8989

9090
// JSONIndent sends JSON response with the given status code.
91-
// Creates response with the given indent.
91+
// Sends response with the given indent.
9292
//
93-
// Returns an error happenedd during sending response.
93+
// Returns an error if an error happened during sending response otherwise returns nil.
9494
func (c *Context) JSONIndent(code int, obj any, indent string) error {
9595
c.writeContentType("application/json")
9696
c.response.WriteHeader(code)
@@ -112,12 +112,47 @@ func (c *Context) ReadJSON(out any) error {
112112
return c.kid.jsonSerializer.Read(c.Request(), out)
113113
}
114114

115+
// XML sends XML response with the given status code.
116+
//
117+
// Returns an error if an error happened during sending response otherwise returns nil.
118+
func (c *Context) XML(code int, obj any) error {
119+
c.writeContentType("application/xml")
120+
c.response.WriteHeader(code)
121+
return c.kid.xmlSerializer.Write(c.Response(), obj, "")
122+
}
123+
124+
// XMLIndent sends XML response with the given status code.
125+
// Sends response with the given indent.
126+
//
127+
// Returns an error if an error happened during sending response otherwise returns nil.
128+
func (c *Context) XMLIndent(code int, obj any, indent string) error {
129+
c.writeContentType("application/xml")
130+
c.response.WriteHeader(code)
131+
return c.kid.xmlSerializer.Write(c.Response(), obj, indent)
132+
}
133+
134+
// XMLByte sends XML response with the given status code.
135+
// Writes JSON blob untouched to response.
136+
func (c *Context) XMLByte(code int, blob []byte) error {
137+
c.writeContentType("application/xml")
138+
c.response.WriteHeader(code)
139+
_, err := c.Response().Write(blob)
140+
return err
141+
}
142+
143+
// ReadXML reads request's body as XML and stores it in the given object.
144+
// The object must be a pointer.
145+
func (c *Context) ReadXML(out any) error {
146+
return c.kid.xmlSerializer.Read(c.Request(), out)
147+
}
148+
115149
// NoContent returns an empty response with the given status code.
116150
func (c *Context) NoContent(code int) {
117151
c.response.WriteHeader(code)
118152
}
119153

120-
// writeContentType sets content type of response.
154+
// writeContentType sets content type header for response.
155+
// It won't overwrite content type if it's already set.
121156
func (c *Context) writeContentType(contentType string) {
122157
contentTypeHeader := "Content-Type"
123158
header := c.response.Header()

context_test.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package kid
22

33
import (
44
"encoding/json"
5+
"encoding/xml"
56
"net/http"
67
"net/http/httptest"
78
"net/url"
@@ -247,6 +248,7 @@ func TestContextJSON(t *testing.T) {
247248
err := ctx.JSON(http.StatusCreated, &p)
248249

249250
assert.NoError(t, err)
251+
assert.Equal(t, http.StatusCreated, res.Code)
250252
assert.Equal(t, "application/json", res.Header().Get("Content-Type"))
251253
assert.Equal(t, "{\"name\":\"foo\",\"age\":1999}\n", res.Body.String())
252254

@@ -272,6 +274,7 @@ func TestContextJSONIndent(t *testing.T) {
272274
err := ctx.JSONIndent(http.StatusCreated, &p, " ")
273275

274276
assert.NoError(t, err)
277+
assert.Equal(t, http.StatusCreated, res.Code)
275278
assert.Equal(t, "application/json", res.Header().Get("Content-Type"))
276279
assert.Equal(t, "{\n \"name\": \"foo\",\n \"age\": 1999\n}\n", res.Body.String())
277280

@@ -301,6 +304,104 @@ func TestContextJSONByte(t *testing.T) {
301304
err = ctx.JSONByte(http.StatusOK, blob)
302305

303306
assert.NoError(t, err)
307+
assert.Equal(t, http.StatusOK, res.Code)
304308
assert.Equal(t, "application/json", res.Header().Get("Content-Type"))
305309
assert.Equal(t, "{\"name\":\"foo\",\"age\":1999}", res.Body.String())
306310
}
311+
312+
func TestContextReadXML(t *testing.T) {
313+
ctx := newContext(New())
314+
315+
req := httptest.NewRequest(http.MethodGet, "/", strings.NewReader("<person><name>Mojix</name><age>22</age></person>"))
316+
317+
ctx.reset(req, nil)
318+
319+
var p person
320+
err := ctx.ReadXML(&p)
321+
assert.NoError(t, err)
322+
323+
assert.Equal(t, person{Name: "Mojix", Age: 22}, p)
324+
325+
req = httptest.NewRequest(http.MethodGet, "/", strings.NewReader("<person><name>Mojix</name><age>22</age></person"))
326+
327+
ctx.reset(req, nil)
328+
329+
var p2 person
330+
httpErr := ctx.ReadXML(&p2).(*errors.HTTPError)
331+
332+
assert.Error(t, httpErr)
333+
assert.Error(t, httpErr.Err)
334+
assert.Equal(t, http.StatusBadRequest, httpErr.Code)
335+
}
336+
337+
func TestContextXML(t *testing.T) {
338+
ctx := newContext(New())
339+
340+
res := httptest.NewRecorder()
341+
342+
ctx.reset(nil, res)
343+
344+
p := person{Name: "foo", Age: 1999}
345+
err := ctx.XML(http.StatusCreated, &p)
346+
347+
assert.NoError(t, err)
348+
assert.Equal(t, http.StatusCreated, res.Code)
349+
assert.Equal(t, "application/xml", res.Header().Get("Content-Type"))
350+
assert.Equal(t, "<person><name>foo</name><age>1999</age></person>", res.Body.String())
351+
352+
res = httptest.NewRecorder()
353+
354+
ctx.reset(nil, res)
355+
356+
httpErr := ctx.XML(http.StatusCreated, make(chan bool)).(*errors.HTTPError)
357+
358+
assert.Error(t, httpErr)
359+
assert.Error(t, httpErr.Err)
360+
assert.Equal(t, http.StatusInternalServerError, httpErr.Code)
361+
}
362+
363+
func TestContextXMLIndent(t *testing.T) {
364+
ctx := newContext(New())
365+
366+
res := httptest.NewRecorder()
367+
368+
ctx.reset(nil, res)
369+
370+
p := person{Name: "foo", Age: 1999}
371+
err := ctx.XMLIndent(http.StatusCreated, &p, " ")
372+
373+
assert.NoError(t, err)
374+
assert.Equal(t, http.StatusCreated, res.Code)
375+
assert.Equal(t, "application/xml", res.Header().Get("Content-Type"))
376+
assert.Equal(t, "<person>\n <name>foo</name>\n <age>1999</age>\n</person>", res.Body.String())
377+
378+
res = httptest.NewRecorder()
379+
380+
ctx.reset(nil, res)
381+
382+
httpErr := ctx.XMLIndent(http.StatusCreated, make(chan bool), " ").(*errors.HTTPError)
383+
384+
assert.Error(t, httpErr)
385+
assert.Error(t, httpErr.Err)
386+
assert.Equal(t, http.StatusInternalServerError, httpErr.Code)
387+
}
388+
389+
func TestContextXMLByte(t *testing.T) {
390+
ctx := newContext(New())
391+
392+
res := httptest.NewRecorder()
393+
394+
ctx.reset(nil, res)
395+
396+
p := person{Name: "foo", Age: 1999}
397+
398+
blob, err := xml.Marshal(p)
399+
assert.NoError(t, err)
400+
401+
err = ctx.XMLByte(http.StatusOK, blob)
402+
403+
assert.NoError(t, err)
404+
assert.Equal(t, http.StatusOK, res.Code)
405+
assert.Equal(t, "application/xml", res.Header().Get("Content-Type"))
406+
assert.Equal(t, "<person><name>foo</name><age>1999</age></person>", res.Body.String())
407+
}

kid.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ type (
3030
methodNotAllowedHandler HandlerFunc
3131
errorHandler ErrorHandler
3232
jsonSerializer serializer.Serializer
33+
xmlSerializer serializer.Serializer
3334
pool sync.Pool
3435
}
3536
)
@@ -43,6 +44,7 @@ func New() *Kid {
4344
methodNotAllowedHandler: defaultMethodNotAllowedHandler,
4445
errorHandler: defaultErrorHandler,
4546
jsonSerializer: serializer.NewJSONSerializer(),
47+
xmlSerializer: serializer.NewXMLSerializer(),
4648
}
4749

4850
kid.pool.New = func() any {

kid_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ func TestNew(t *testing.T) {
1818
assert.Equal(t, newRouter(), k.router)
1919
assert.Equal(t, 0, len(k.middlewares))
2020
assert.Equal(t, serializer.NewJSONSerializer(), k.jsonSerializer)
21+
assert.Equal(t, serializer.NewXMLSerializer(), k.xmlSerializer)
2122
assert.True(t, funcsAreEqual(defaultErrorHandler, k.errorHandler))
2223
assert.True(t, funcsAreEqual(defaultNotFoundHandler, k.notFoundHandler))
2324
assert.True(t, funcsAreEqual(defaultMethodNotAllowedHandler, k.methodNotAllowedHandler))

0 commit comments

Comments
 (0)