Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Version 11.2.3 #1316

Merged
merged 5 commits into from Aug 3, 2019
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

add content negotiation feature, add context.ReadYAML and fix kataras…

  • Loading branch information...
kataras committed Aug 3, 2019
commit 8ee0de51c593fe0483fbea38117c3c88e065f2ef
@@ -224,6 +224,7 @@ You can serve [quicktemplate](https://github.com/valyala/quicktemplate) and [her
- [Read JSON](http_request/read-json/main.go)
* [Struct Validation](http_request/read-json-struct-validation/main.go)
- [Read XML](http_request/read-xml/main.go)
- [Read YAML](http_request/read-yaml/main.go) **NEW**
- [Read Form](http_request/read-form/main.go)
- [Read Query](http_request/read-query/main.go) **NEW**
- [Read Custom per type](http_request/read-custom-per-type/main.go)
@@ -237,6 +238,7 @@ You can serve [quicktemplate](https://github.com/valyala/quicktemplate) and [her
### How to Write to `context.ResponseWriter() http.ResponseWriter`
- [Content Negotiation](http_responsewriter/content-negotiation) **NEW**
- [Write `valyala/quicktemplate` templates](http_responsewriter/quicktemplate)
- [Write `shiyanhui/hero` templates](http_responsewriter/herotemplate)
- [Text, Markdown, HTML, JSON, JSONP, XML, Binary](http_responsewriter/write-rest/main.go)
@@ -330,6 +330,7 @@ You can serve [quicktemplate](https://github.com/valyala/quicktemplate) and [her
- [读取JSON](http_request/read-json/main.go)
- [读取XML](http_request/read-xml/main.go)
- [读取YAML](http_request/read-yaml/main.go) **更新**
- [读取Form](http_request/read-form/main.go)
- [读取Query](http_request/read-query/main.go) **更新**
- [读取每个类型的自定义结果Custom per type](http_request/read-custom-per-type/main.go)
@@ -342,6 +343,7 @@ You can serve [quicktemplate](https://github.com/valyala/quicktemplate) and [her
### 如何写入`context.ResponseWriter() http.ResponseWriter`
- [Content Negotiation](http_responsewriter/content-negotiation) **更新**
- [`valyala/quicktemplate`模版](http_responsewriter/quicktemplate)
- [`shiyanhui/hero`模版](http_responsewriter/herotemplate)
- [Text, Markdown, HTML, JSON, JSONP, XML, Binary](http_responsewriter/write-rest/main.go)
@@ -0,0 +1,36 @@
package main

import (
"github.com/kataras/iris"
)

func newApp() *iris.Application {
app := iris.New()
app.Post("/", handler)

return app
}

// simple yaml stuff, read more at https://yaml.org/start.html
type product struct {
Invoice int `yaml:"invoice"`
Tax float32 `yaml:"tax"`
Total float32 `yaml:"total"`
Comments string `yaml:"comments"`
}

func handler(ctx iris.Context) {
var p product
if err := ctx.ReadYAML(&p); err != nil {
ctx.StatusCode(iris.StatusBadRequest)
ctx.WriteString(err.Error())
return
}

ctx.Writef("Received: %#+v", p)
}

func main() {
app := newApp()
app.Run(iris.Addr(":8080"))
}
@@ -0,0 +1,24 @@
package main

import (
"testing"

"github.com/kataras/iris/httptest"
)

func TestReadYAML(t *testing.T) {
app := newApp()
e := httptest.New(t, app)

expectedResponse := `Received: main.product{Invoice:34843, Tax:251.42, Total:4443.52, Comments:"Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338."}`
send := `invoice: 34843
tax : 251.42
total: 4443.52
comments: >
Late afternoon is best.
Backup contact is Nancy
Billsmer @ 338-4338.`

e.POST("/").WithHeader("Content-Type", "application/x-yaml").WithBytes([]byte(send)).Expect().
Status(httptest.StatusOK).Body().Equal(expectedResponse)
}
@@ -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)
}

}
@@ -53,6 +53,8 @@
};
}
const username = window.prompt("Your username?");
async function runExample() {
// You can omit the "default" and simply define only Events, the namespace will be an empty string"",
// however if you decide to make any changes on this example make sure the changes are reflecting inside the ../server.go file as well.
@@ -70,6 +72,10 @@
addMessage(msg.Body);
}
}
},{
headers: {
"X-Username": username,
}
});
// You can either wait to conenct or just conn.connect("connect")
@@ -42,7 +42,10 @@ func main() {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(dialAndConnectTimeout))
defer cancel()

client, err := websocket.Dial(ctx, websocket.DefaultGorillaDialer, endpoint, clientEvents)
// username := "my_username"
// dialer := websocket.GobwasDialer(websocket.GobwasDialerOptions{Header: websocket.GobwasHeader{"X-Username": []string{username}}})
dialer := websocket.DefaultGobwasDialer
client, err := websocket.Dial(ctx, dialer, endpoint, clientEvents)
if err != nil {
panic(err)
}
@@ -68,8 +68,17 @@ func main() {
SigningMethod: jwt.SigningMethodHS256,
})

idGen := func(ctx iris.Context) string {
if username := ctx.GetHeader("X-Username"); username != "" {
return username
}

return websocket.DefaultIDGenerator(ctx)
}

// serves the endpoint of ws://localhost:8080/echo
websocketRoute := app.Get("/echo", websocket.Handler(websocketServer))
// with optional custom ID generator.
websocketRoute := app.Get("/echo", websocket.Handler(websocketServer, idGen))

if enableJWT {
// Register the jwt middleware (on handshake):
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.