1
0
mirror of https://github.com/kataras/iris.git synced 2026-01-22 19:36:00 +00:00

reorganization of _examples and add some new examples such as iris+groupcache+mysql+docker

Former-commit-id: ed635ee95de7160cde11eaabc0c1dcb0e460a620
This commit is contained in:
Gerasimos (Makis) Maropoulos
2020-06-07 15:26:06 +03:00
parent 9fdcb4c7fb
commit ed45c77be5
328 changed files with 4262 additions and 41621 deletions

View File

@@ -0,0 +1,58 @@
package main
import (
"github.com/kataras/iris/v12"
)
func main() {
app := newApp()
// See main_test.go for usage.
app.Listen(":8080")
}
func newApp() *iris.Application {
app := iris.New()
// To automatically decompress using gzip:
// app.Use(iris.GzipReader)
app.Use(setAllowedResponses)
app.Post("/", readBody)
return app
}
type payload struct {
Message string `json:"message" xml:"message" msgpack:"message" yaml:"Message" url:"message" form:"message"`
}
func readBody(ctx iris.Context) {
var p payload
// Bind request body to "p" depending on the content-type that client sends the data,
// e.g. JSON, XML, YAML, MessagePack, Form, URL Query.
err := ctx.ReadBody(&p)
if err != nil {
ctx.StopWithProblem(iris.StatusBadRequest,
iris.NewProblem().Title("Parser issue").Detail(err.Error()))
return
}
// For the sake of the example, log the received payload.
ctx.Application().Logger().Infof("Received: %#+v", p)
// Send back the payload depending on the accept content type and accept-encoding of the client,
// e.g. JSON, XML and so on.
ctx.Negotiate(p)
}
func setAllowedResponses(ctx iris.Context) {
// Indicate that the Server can send JSON, XML, YAML and MessagePack for this request.
ctx.Negotiation().JSON().XML().YAML().MsgPack()
// Add more, allowed by the server format of responses, mime types here...
// If client is missing an "Accept: " header then default it to JSON.
ctx.Negotiation().Accept.JSON()
ctx.Next()
}

View File

@@ -0,0 +1,53 @@
package main
import (
"testing"
"github.com/kataras/iris/v12/httptest"
)
func TestReadBodyAndNegotiate(t *testing.T) {
app := newApp()
e := httptest.New(t, app)
var (
expectedPayload = payload{Message: "a message"}
expectedMsgPackPayload = "\x81\xa7message\xa9a message"
expectedXMLPayload = `<payload>
<message>a message</message>
</payload>
`
expectedYAMLPayload = "Message: a message\n"
)
// Test send JSON and receive JSON.
e.POST("/").WithJSON(expectedPayload).Expect().Status(httptest.StatusOK).
JSON().Equal(expectedPayload)
// Test send Form and receive XML.
e.POST("/").WithForm(expectedPayload).
WithHeader("Accept", "application/xml").
Expect().Status(httptest.StatusOK).
Body().Equal(expectedXMLPayload)
// Test send URL Query and receive MessagePack.
e.POST("/").WithQuery("message", expectedPayload.Message).
WithHeader("Accept", "application/msgpack").
Expect().Status(httptest.StatusOK).ContentType("application/msgpack").
Body().Equal(expectedMsgPackPayload)
// Test send MessagePack and receive MessagePack.
e.POST("/").WithBytes([]byte(expectedMsgPackPayload)).
WithHeader("Content-Type", "application/msgpack").
WithHeader("Accept", "application/msgpack").
Expect().Status(httptest.StatusOK).
ContentType("application/msgpack").Body().Equal(expectedMsgPackPayload)
// Test send YAML and receive YAML.
e.POST("/").WithBytes([]byte(expectedYAMLPayload)).
WithHeader("Content-Type", "application/x-yaml").
WithHeader("Accept", "application/x-yaml").
Expect().Status(httptest.StatusOK).
ContentType("application/x-yaml").Body().Equal(expectedYAMLPayload)
}

View File

@@ -0,0 +1,64 @@
package main
import (
"gopkg.in/yaml.v3"
"github.com/kataras/iris/v12"
)
func main() {
app := newApp()
// use Postman or whatever to do a POST request
// (however you are always free to use app.Get and GET http method requests to read body of course)
// to the http://localhost:8080 with RAW BODY:
/*
addr: localhost:8080
serverName: Iris
*/
//
// The response should be:
// Received: main.config{Addr:"localhost:8080", ServerName:"Iris"}
app.Listen(":8080", iris.WithOptimizations)
}
func newApp() *iris.Application {
app := iris.New()
app.Post("/", handler)
return app
}
// simple yaml stuff, read more at https://github.com/go-yaml/yaml
type config struct {
Addr string `yaml:"addr"`
ServerName string `yaml:"serverName"`
}
// Decode implements the `kataras/iris/context#BodyDecoder` optional interface
// that any go type can implement in order to be self-decoded when reading the request's body.
func (c *config) Decode(body []byte) error {
return yaml.Unmarshal(body, c)
}
func handler(ctx iris.Context) {
var c config
//
// Note:
// second parameter is nil because our &c implements the `context#BodyDecoder`
// which has a priority over the context#Unmarshaler (which can be a more global option for reading request's body)
// see the `request-body/read-custom-via-unmarshaler/main.go` example to learn how to use the context#Unmarshaler too.
//
// Note 2:
// If you need to read the body again for any reason
// you should disable the body consumption via `app.Run(..., iris.WithoutBodyConsumptionOnUnmarshal)`.
//
if err := ctx.UnmarshalBody(&c, nil); err != nil {
ctx.StopWithError(iris.StatusBadRequest, err)
return
}
ctx.Writef("Received: %#+v", c)
}

View File

@@ -0,0 +1,17 @@
package main
import (
"testing"
"github.com/kataras/iris/v12/httptest"
)
func TestReadCustomPerType(t *testing.T) {
app := newApp()
e := httptest.New(t, app)
expectedResponse := `Received: main.config{Addr:"localhost:8080", ServerName:"Iris"}`
e.POST("/").WithText("addr: localhost:8080\nserverName: Iris").Expect().
Status(httptest.StatusOK).Body().Equal(expectedResponse)
}

View File

@@ -0,0 +1,72 @@
package main
import (
"gopkg.in/yaml.v3"
"github.com/kataras/iris/v12"
)
func main() {
app := newApp()
// use Postman or whatever to do a POST request
// (however you are always free to use app.Get and GET http method requests to read body of course)
// to the http://localhost:8080 with RAW BODY:
/*
addr: localhost:8080
serverName: Iris
*/
//
// The response should be:
// Received: main.config{Addr:"localhost:8080", ServerName:"Iris"}
app.Listen(":8080", iris.WithOptimizations)
}
func newApp() *iris.Application {
app := iris.New()
app.Post("/", handler)
return app
}
// simple yaml stuff, read more at https://github.com/go-yaml/yaml
type config struct {
Addr string `yaml:"addr"`
ServerName string `yaml:"serverName"`
}
/*
type myBodyDecoder struct{}
var DefaultBodyDecoder = myBodyDecoder{}
// Implements the `kataras/iris/context#Unmarshaler` but at our example
// we will use the simplest `context#UnmarshalerFunc` to pass just the yaml.Unmarshal.
//
// Can be used as: ctx.UnmarshalBody(&c, DefaultBodyDecoder)
func (r *myBodyDecoder) Unmarshal(data []byte, outPtr interface{}) error {
return yaml.Unmarshal(data, outPtr)
}
*/
func handler(ctx iris.Context) {
var c config
//
// Note:
// yaml.Unmarshal already implements the `context#Unmarshaler`
// so we can use it directly, like the json.Unmarshal(ctx.ReadJSON), xml.Unmarshal(ctx.ReadXML)
// and every library which follows the best practises and is aligned with the Go standards.
//
// Note 2:
// If you need to read the body again for any reason
// you should disable the body consumption via `app.Run(..., iris.WithoutBodyConsumptionOnUnmarshal)`.
//
if err := ctx.UnmarshalBody(&c, iris.UnmarshalerFunc(yaml.Unmarshal)); err != nil {
ctx.StopWithError(iris.StatusBadRequest, err)
return
}
ctx.Writef("Received: %#+v", c)
}

View File

@@ -0,0 +1,17 @@
package main
import (
"testing"
"github.com/kataras/iris/v12/httptest"
)
func TestReadCustomViaUnmarshaler(t *testing.T) {
app := newApp()
e := httptest.New(t, app)
expectedResponse := `Received: main.config{Addr:"localhost:8080", ServerName:"Iris"}`
e.POST("/").WithText("addr: localhost:8080\nserverName: Iris").Expect().
Status(httptest.StatusOK).Body().Equal(expectedResponse)
}

View File

@@ -0,0 +1,44 @@
// package main contains an example on how to use the ReadForm, but with the same way you can do the ReadJSON & ReadJSON
package main
import (
"github.com/kataras/iris/v12"
)
type Visitor struct {
Username string
Mail string
Data []string `form:"mydata"`
}
func main() {
app := iris.New()
// set the view html template engine
app.RegisterView(iris.HTML("./templates", ".html").Reload(true))
app.Get("/", func(ctx iris.Context) {
if err := ctx.View("form.html"); err != nil {
ctx.StopWithError(iris.StatusInternalServerError, err)
return
}
})
app.Post("/form_action", func(ctx iris.Context) {
visitor := Visitor{}
err := ctx.ReadForm(&visitor)
if err != nil && !iris.IsErrPath(err) /* see: https://github.com/kataras/iris/issues/1157 */ {
ctx.StopWithError(iris.StatusInternalServerError, err)
return
}
ctx.Writef("Visitor: %#v", visitor)
})
app.Post("/post_value", func(ctx iris.Context) {
username := ctx.PostValueDefault("Username", "iris")
ctx.Writef("Username: %s", username)
})
app.Listen(":8080")
}

View File

@@ -0,0 +1,22 @@
<!DOCTYPE html>
<head>
<meta charset="utf-8">
</head>
<body>
<form action="/form_action" method="post">
Username: <input type="text" name="Username" /> <br />
Mail: <input type="text" name="Mail" /> <br />
Select one or more: <br/>
<select multiple="multiple" name="mydata">
<option value='one'>One</option>
<option value='two'>Two</option>
<option value='three'>Three</option>
<option value='four'>Four</option>
</select>
<hr />
<input type="submit" value="Send data" />
</form>
</body>
</html>

View File

@@ -0,0 +1,44 @@
package main
import (
"github.com/kataras/iris/v12"
)
func main() {
app := newApp()
app.Logger().SetLevel("debug")
app.Listen(":8080")
}
type payload struct {
Message string `json:"message"`
}
func newApp() *iris.Application {
app := iris.New()
// GzipReader is a middleware which enables gzip decompression,
// when client sends gzip compressed data.
//
// A shortcut of:
// func(ctx iris.Context) {
// ctx.GzipReader(true)
// ctx.Next()
// }
app.Use(iris.GzipReader)
app.Post("/", func(ctx iris.Context) {
// Bind incoming gzip compressed JSON to "p".
var p payload
if err := ctx.ReadJSON(&p); err != nil {
ctx.StopWithError(iris.StatusBadRequest, err)
return
}
// Send back the message as plain text.
ctx.WriteString(p.Message)
})
return app
}

View File

@@ -0,0 +1,38 @@
package main
import (
"bytes"
"compress/gzip"
"encoding/json"
"testing"
"github.com/kataras/iris/v12/httptest"
)
func TestGzipReader(t *testing.T) {
app := newApp()
expected := payload{Message: "test"}
b, err := json.Marshal(expected)
if err != nil {
t.Fatal(err)
}
buf := new(bytes.Buffer)
w := gzip.NewWriter(buf)
_, err = w.Write(b)
if err != nil {
t.Fatal(err)
}
err = w.Close()
if err != nil {
t.Fatal(err)
}
e := httptest.New(t, app)
// send gzip compressed.
e.POST("/").WithHeader("Content-Encoding", "gzip").WithHeader("Content-Type", "application/json").
WithBytes(buf.Bytes()).Expect().Status(httptest.StatusOK).Body().Equal(expected.Message)
// raw.
e.POST("/").WithJSON(expected).Expect().Status(httptest.StatusOK).Body().Equal(expected.Message)
}

View File

@@ -0,0 +1,146 @@
// Package main shows the validator(latest, version 10) integration with Iris' Context methods of
// `ReadJSON`, `ReadXML`, `ReadMsgPack`, `ReadYAML`, `ReadForm`, `ReadQuery`, `ReadBody`.
//
// You can find more examples of this 3rd-party library at:
// https://github.com/go-playground/validator/blob/master/_examples
package main
import (
"fmt"
"github.com/kataras/iris/v12"
// $ go get github.com/go-playground/validator/v10@latest
"github.com/go-playground/validator/v10"
)
func main() {
app := iris.New()
app.Validator = validator.New()
userRouter := app.Party("/user")
{
userRouter.Get("/validation-errors", resolveErrorsDocumentation)
userRouter.Post("/", postUser)
}
// Use Postman or any tool to perform a POST request
// to the http://localhost:8080/user with RAW BODY of:
/*
{
"fname": "",
"lname": "",
"age": 45,
"email": "mail@example.com",
"favColor": "#000",
"addresses": [{
"street": "Eavesdown Docks",
"planet": "Persphone",
"phone": "none",
"city": "Unknown"
}]
}
*/
/* The response should be:
{
"title": "Validation error",
"detail": "One or more fields failed to be validated",
"type": "http://localhost:8080/user/validation-errors",
"status": 400,
"fields": [
{
"tag": "required",
"namespace": "User.FirstName",
"kind": "string",
"type": "string",
"value": "",
"param": ""
},
{
"tag": "required",
"namespace": "User.LastName",
"kind": "string",
"type": "string",
"value": "",
"param": ""
}
]
}
*/
app.Listen(":8080")
}
// User contains user information.
type User struct {
FirstName string `json:"fname" validate:"required"`
LastName string `json:"lname" validate:"required"`
Age uint8 `json:"age" validate:"gte=0,lte=130"`
Email string `json:"email" validate:"required,email"`
FavouriteColor string `json:"favColor" validate:"hexcolor|rgb|rgba"`
Addresses []*Address `json:"addresses" validate:"required,dive,required"` // a User can have a home and cottage...
}
// Address houses a users address information.
type Address struct {
Street string `json:"street" validate:"required"`
City string `json:"city" validate:"required"`
Planet string `json:"planet" validate:"required"`
Phone string `json:"phone" validate:"required"`
}
type validationError struct {
ActualTag string `json:"tag"`
Namespace string `json:"namespace"`
Kind string `json:"kind"`
Type string `json:"type"`
Value string `json:"value"`
Param string `json:"param"`
}
func wrapValidationErrors(errs validator.ValidationErrors) []validationError {
validationErrors := make([]validationError, 0, len(errs))
for _, validationErr := range errs {
validationErrors = append(validationErrors, validationError{
ActualTag: validationErr.ActualTag(),
Namespace: validationErr.Namespace(),
Kind: validationErr.Kind().String(),
Type: validationErr.Type().String(),
Value: fmt.Sprintf("%v", validationErr.Value()),
Param: validationErr.Param(),
})
}
return validationErrors
}
func postUser(ctx iris.Context) {
var user User
err := ctx.ReadJSON(&user)
if err != nil {
// Handle the error, below you will find the right way to do that...
if errs, ok := err.(validator.ValidationErrors); ok {
// Wrap the errors with JSON format, the underline library returns the errors as interface.
validationErrors := wrapValidationErrors(errs)
// Fire an application/json+problem response and stop the handlers chain.
ctx.StopWithProblem(iris.StatusBadRequest, iris.NewProblem().
Title("Validation error").
Detail("One or more fields failed to be validated").
Type("/user/validation-errors").
Key("errors", validationErrors))
return
}
// It's probably an internal JSON error, let's dont give more info here.
ctx.StopWithStatus(iris.StatusInternalServerError)
return
}
ctx.JSON(iris.Map{"message": "OK"})
}
func resolveErrorsDocumentation(ctx iris.Context) {
ctx.WriteString("A page that should document to web developers or users of the API on how to resolve the validation errors")
}

View File

@@ -0,0 +1,62 @@
package main
import (
"github.com/kataras/iris/v12"
)
type Company struct {
Name string
City string
Other string
}
func MyHandler(ctx iris.Context) {
var c Company
if err := ctx.ReadJSON(&c); err != nil {
ctx.StopWithError(iris.StatusBadRequest, err)
return
}
ctx.Writef("Received: %#+v\n", c)
}
// simple json stuff, read more at https://golang.org/pkg/encoding/json
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
// MyHandler2 reads a collection of Person from JSON post body.
func MyHandler2(ctx iris.Context) {
var persons []Person
err := ctx.ReadJSON(&persons)
if err != nil {
ctx.StopWithError(iris.StatusBadRequest, err)
return
}
ctx.Writef("Received: %#+v\n", persons)
}
func main() {
app := iris.New()
app.Post("/", MyHandler)
app.Post("/slice", MyHandler2)
// use Postman or whatever to do a POST request
// to the http://localhost:8080 with RAW BODY:
/*
{
"Name": "iris-Go",
"City": "New York",
"Other": "Something here"
}
*/
// and Content-Type to application/json (optionally but good practise)
//
// The response should be:
// Received: main.Company{Name:"iris-Go", City:"New York", Other:"Something here"}
app.Listen(":8080", iris.WithOptimizations)
}

View File

@@ -0,0 +1,60 @@
package main
import (
"github.com/kataras/iris/v12"
)
func main() {
app := iris.New()
app.Post("/", logAllBody, logJSON, logFormValues, func(ctx iris.Context) {
// body, err := ioutil.ReadAll(ctx.Request().Body) once or
body, err := ctx.GetBody() // as many times as you need.
if err != nil {
ctx.StopWithError(iris.StatusInternalServerError, err)
return
}
if len(body) == 0 {
ctx.WriteString(`The body was empty
or iris.WithoutBodyConsumptionOnUnmarshal option is missing from app.Run.
Check the terminal window for any queries logs.`)
} else {
ctx.WriteString("OK body is still:\n")
ctx.Write(body)
}
})
// With ctx.UnmarshalBody, ctx.ReadJSON, ctx.ReadXML, ctx.ReadForm, ctx.FormValues
// and ctx.GetBody methods the default golang and net/http behavior
// is to consume the readen data - they are not available on any next handlers in the chain -
// to change that behavior just pass the `WithoutBodyConsumptionOnUnmarshal` option.
app.Listen(":8080", iris.WithoutBodyConsumptionOnUnmarshal)
}
func logAllBody(ctx iris.Context) {
body, err := ctx.GetBody()
if err == nil && len(body) > 0 {
ctx.Application().Logger().Infof("logAllBody: %s", string(body))
}
ctx.Next()
}
func logJSON(ctx iris.Context) {
var p interface{}
if err := ctx.ReadJSON(&p); err == nil {
ctx.Application().Logger().Infof("logJSON: %#+v", p)
}
ctx.Next()
}
func logFormValues(ctx iris.Context) {
values := ctx.FormValues()
if values != nil {
ctx.Application().Logger().Infof("logFormValues: %v", values)
}
ctx.Next()
}

View File

@@ -0,0 +1,37 @@
package main
import "github.com/kataras/iris/v12"
// User example struct to bind to.
type User struct {
Firstname string `msgpack:"firstname"`
Lastname string `msgpack:"lastname"`
City string `msgpack:"city"`
Age int `msgpack:"age"`
}
// readMsgPack reads a `User` from MsgPack post body.
func readMsgPack(ctx iris.Context) {
var u User
err := ctx.ReadMsgPack(&u)
if err != nil {
ctx.StopWithError(iris.StatusBadRequest, err)
return
}
ctx.Writef("Received: %#+v\n", u)
}
func main() {
app := iris.New()
app.Post("/", readMsgPack)
// POST: http://localhost:8080
//
// To run the example, use a tool like Postman:
// 1. Body: Binary
// 2. Select File, select the one from "_examples/response-writer/write-rest" example.
// The output should be:
// Received: main.User{Firstname:"John", Lastname:"Doe", City:"Neither FBI knows!!!", Age:25}
app.Listen(":8080")
}

View File

@@ -0,0 +1,29 @@
// package main contains an example on how to use the ReadForm, but with the same way you can do the ReadJSON & ReadJSON
package main
import (
"github.com/kataras/iris/v12"
)
type MyType struct {
Name string `url:"name"`
Age int `url:"age"`
}
func main() {
app := iris.New()
app.Get("/", func(ctx iris.Context) {
var t MyType
err := ctx.ReadQuery(&t)
if err != nil && !iris.IsErrPath(err) {
ctx.StopWithError(iris.StatusInternalServerError, err)
return
}
ctx.Writef("MyType: %#v", t)
})
// http://localhost:8080?name=iris&age=3
app.Listen(":8080")
}

View File

@@ -0,0 +1,49 @@
package main
import (
"encoding/xml"
"github.com/kataras/iris/v12"
)
func main() {
app := newApp()
// use Postman or whatever to do a POST request
// to the http://localhost:8080 with RAW BODY:
/*
<person name="Winston Churchill" age="90">
<description>Description of this person, the body of this inner element.</description>
</person>
*/
// and Content-Type to application/xml (optionally but good practise)
//
// The response should be:
// Received: main.person{XMLName:xml.Name{Space:"", Local:"person"}, Name:"Winston Churchill", Age:90, Description:"Description of this person, the body of this inner element."}
app.Listen(":8080", iris.WithOptimizations)
}
func newApp() *iris.Application {
app := iris.New()
app.Post("/", handler)
return app
}
// simple xml stuff, read more at https://golang.org/pkg/encoding/xml
type person struct {
XMLName xml.Name `xml:"person"` // element name
Name string `xml:"name,attr"` // ,attr for attribute.
Age int `xml:"age,attr"` // ,attr attribute.
Description string `xml:"description"` // inner element name, value is its body.
}
func handler(ctx iris.Context) {
var p person
if err := ctx.ReadXML(&p); err != nil {
ctx.StopWithError(iris.StatusBadRequest, err)
return
}
ctx.Writef("Received: %#+v", p)
}

View File

@@ -0,0 +1,18 @@
package main
import (
"testing"
"github.com/kataras/iris/v12/httptest"
)
func TestReadXML(t *testing.T) {
app := newApp()
e := httptest.New(t, app)
expectedResponse := `Received: main.person{XMLName:xml.Name{Space:"", Local:"person"}, Name:"Winston Churchill", Age:90, Description:"Description of this person, the body of this inner element."}`
send := `<person name="Winston Churchill" age="90"><description>Description of this person, the body of this inner element.</description></person>`
e.POST("/").WithText(send).Expect().
Status(httptest.StatusOK).Body().Equal(expectedResponse)
}

View File

@@ -0,0 +1,35 @@
package main
import (
"github.com/kataras/iris/v12"
)
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.StopWithError(iris.StatusBadRequest, err)
return
}
ctx.Writef("Received: %#+v", p)
}
func main() {
app := newApp()
app.Listen(":8080")
}

View File

@@ -0,0 +1,24 @@
package main
import (
"testing"
"github.com/kataras/iris/v12/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)
}