mirror of
https://github.com/kataras/iris.git
synced 2025-12-20 11:27:06 +00:00
add content negotiation feature, add context.ReadYAML and fix https://github.com/kataras/neffos/issues/1#issuecomment-515698536
Former-commit-id: 9753e3e45c7c24788b97814d3ecfb4b03f5ff414
This commit is contained in:
114
_examples/http_responsewriter/content-negotiation/main.go
Normal file
114
_examples/http_responsewriter/content-negotiation/main.go
Normal file
@@ -0,0 +1,114 @@
|
||||
// Package main contains three different ways to render content based on the client's accepted.
|
||||
package main
|
||||
|
||||
import "github.com/kataras/iris"
|
||||
|
||||
type testdata struct {
|
||||
Name string `json:"name" xml:"Name"`
|
||||
Age int `json:"age" xml:"Age"`
|
||||
}
|
||||
|
||||
func newApp() *iris.Application {
|
||||
app := iris.New()
|
||||
app.Logger().SetLevel("debug")
|
||||
|
||||
// app.Use(func(ctx iris.Context) {
|
||||
// requestedMime := ctx.URLParamDefault("type", "application/json")
|
||||
//
|
||||
// ctx.Negotiation().Accept.Override().MIME(requestedMime, nil)
|
||||
// ctx.Next()
|
||||
// })
|
||||
|
||||
app.Get("/resource", func(ctx iris.Context) {
|
||||
data := testdata{
|
||||
Name: "test name",
|
||||
Age: 26,
|
||||
}
|
||||
|
||||
// Server allows response only JSON and XML. These values
|
||||
// are compared with the clients mime needs. Iris comes with default mime types responses
|
||||
// but you can add a custom one by the `Negotiation().Mime(mime, content)` method,
|
||||
// same for the "accept".
|
||||
// You can also pass a custom ContentSelector(mime string) or ContentNegotiator to the
|
||||
// `Context.Negotiate` method if you want to perform more advanced things.
|
||||
//
|
||||
//
|
||||
// By-default the client accept mime is retrieved by the "Accept" header
|
||||
// Indeed you can override or update it by `Negotiation().Accept.XXX` i.e
|
||||
// ctx.Negotiation().Accept.Override().XML()
|
||||
//
|
||||
// All these values can change inside middlewares, the `Negotiation().Override()` and `.Accept.Override()`
|
||||
// can override any previously set values.
|
||||
// Order matters, if the client accepts anything (*/*)
|
||||
// then the first prioritized mime's response data will be rendered.
|
||||
ctx.Negotiation().JSON().XML()
|
||||
// Accept-Charset vs:
|
||||
ctx.Negotiation().Charset("utf-8", "iso-8859-7")
|
||||
// Alternatively you can define the content/data per mime type
|
||||
// anywhere in the handlers chain using the optional "v" variadic
|
||||
// input argument of the Context.Negotiation().JSON,XML,YAML,Binary,Text,HTML(...) and e.t.c
|
||||
// example (order matters):
|
||||
// ctx.Negotiation().JSON(data).XML(data).Any("content for */*")
|
||||
// ctx.Negotiate(nil)
|
||||
|
||||
// if not nil passed in the `Context.Negotiate` method
|
||||
// then it overrides any contents made by the negotitation builder above.
|
||||
_, err := ctx.Negotiate(data)
|
||||
if err != nil {
|
||||
ctx.Writef("%v", err)
|
||||
}
|
||||
})
|
||||
|
||||
app.Get("/resource2", func(ctx iris.Context) {
|
||||
jsonAndXML := testdata{
|
||||
Name: "test name",
|
||||
Age: 26,
|
||||
}
|
||||
|
||||
// I prefer that one, as it gives me the freedom to modify
|
||||
// response data per accepted mime content type on middlewares as well.
|
||||
ctx.Negotiation().
|
||||
JSON(jsonAndXML).
|
||||
XML(jsonAndXML).
|
||||
HTML("<h1>Test Name</h1><h2>Age 26</h2>")
|
||||
|
||||
ctx.Negotiate(nil)
|
||||
})
|
||||
|
||||
app.Get("/resource3", func(ctx iris.Context) {
|
||||
// If that line is missing and the requested
|
||||
// mime type of content is */* or application/xml or application/json
|
||||
// then 406 Not Acceptable http error code will be rendered instead.
|
||||
//
|
||||
// We also add the "gzip" algorithm as an option to encode
|
||||
// resources on send.
|
||||
ctx.Negotiation().JSON().XML().HTML().EncodingGzip()
|
||||
|
||||
jsonAndXML := testdata{
|
||||
Name: "test name",
|
||||
Age: 26,
|
||||
}
|
||||
|
||||
// Prefer that way instead of the '/resource2' above
|
||||
// if "iris.N" is a static one and can be declared
|
||||
// outside of a handler.
|
||||
ctx.Negotiate(iris.N{
|
||||
// Text: for text/plain,
|
||||
// Markdown: for text/mardown,
|
||||
// Binary: for application/octet-stream,
|
||||
// YAML: for application/x-yaml,
|
||||
// JSONP: for application/javascript
|
||||
// Other: for anything else,
|
||||
JSON: jsonAndXML, // for application/json
|
||||
XML: jsonAndXML, // for application/xml or text/xml
|
||||
HTML: "<h1>Test Name</h1><h2>Age 26</h2>", // for text/html
|
||||
})
|
||||
})
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
func main() {
|
||||
app := newApp()
|
||||
app.Run(iris.Addr(":8080"))
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/xml"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris/httptest"
|
||||
)
|
||||
|
||||
func TestContentNegotiation(t *testing.T) {
|
||||
var (
|
||||
expectedJSONResponse = testdata{
|
||||
Name: "test name",
|
||||
Age: 26,
|
||||
}
|
||||
expectedXMLResponse, _ = xml.Marshal(expectedJSONResponse)
|
||||
expectedHTMLResponse = "<h1>Test Name</h1><h2>Age 26</h2>"
|
||||
)
|
||||
|
||||
e := httptest.New(t, newApp())
|
||||
|
||||
e.GET("/resource").WithHeader("Accept", "application/json").
|
||||
Expect().Status(httptest.StatusOK).
|
||||
ContentType("application/json", "utf-8").
|
||||
JSON().Equal(expectedJSONResponse)
|
||||
e.GET("/resource").WithHeader("Accept", "application/xml").WithHeader("Accept-Charset", "iso-8859-7").
|
||||
Expect().Status(httptest.StatusOK).
|
||||
ContentType("application/xml", "iso-8859-7").
|
||||
Body().Equal(string(expectedXMLResponse))
|
||||
|
||||
e.GET("/resource2").WithHeader("Accept", "application/json").
|
||||
Expect().Status(httptest.StatusOK).
|
||||
ContentType("application/json", "utf-8").
|
||||
JSON().Equal(expectedJSONResponse)
|
||||
e.GET("/resource2").WithHeader("Accept", "application/xml").
|
||||
Expect().Status(httptest.StatusOK).
|
||||
ContentType("application/xml", "utf-8").
|
||||
Body().Equal(string(expectedXMLResponse))
|
||||
e.GET("/resource2").WithHeader("Accept", "text/html").
|
||||
Expect().Status(httptest.StatusOK).
|
||||
ContentType("text/html", "utf-8").
|
||||
Body().Equal(expectedHTMLResponse)
|
||||
|
||||
e.GET("/resource3").WithHeader("Accept", "application/json").
|
||||
Expect().Status(httptest.StatusOK).
|
||||
ContentType("application/json", "utf-8").
|
||||
JSON().Equal(expectedJSONResponse)
|
||||
e.GET("/resource3").WithHeader("Accept", "application/xml").
|
||||
Expect().Status(httptest.StatusOK).
|
||||
ContentType("application/xml", "utf-8").
|
||||
Body().Equal(string(expectedXMLResponse))
|
||||
|
||||
// test html with "gzip" encoding algorithm.
|
||||
rawGzipResponse := e.GET("/resource3").WithHeader("Accept", "text/html").
|
||||
WithHeader("Accept-Encoding", "gzip").
|
||||
Expect().Status(httptest.StatusOK).
|
||||
ContentType("text/html", "utf-8").
|
||||
ContentEncoding("gzip").
|
||||
Body().Raw()
|
||||
|
||||
zr, err := gzip.NewReader(bytes.NewReader([]byte(rawGzipResponse)))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
rawResponse, err := ioutil.ReadAll(zr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if expected, got := expectedHTMLResponse, string(rawResponse); expected != got {
|
||||
t.Fatalf("expected response to be:\n%s but got:\n%s", expected, got)
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user