Try to bind body into different structs

The normal methods for binding request body consumes ctx.Request().Body and they cannot be called multiple times, unless the iris.WithoutBodyConsumptionOnUnmarshal configurator is passed to app.Run/Listen.

  1. package main
  2. import "github.com/kataras/iris/v12"
  3. func main() {
  4. app := iris.New()
  5. app.Post("/", logAllBody, logJSON, logFormValues, func(ctx iris.Context) {
  6. // body, err := ioutil.ReadAll(ctx.Request().Body) once or
  7. body, err := ctx.GetBody() // as many times as you need.
  8. if err != nil {
  9. ctx.StopWithError(iris.StatusInternalServerError, err)
  10. return
  11. }
  12. if len(body) == 0 {
  13. ctx.WriteString(`The body was empty.`)
  14. } else {
  15. ctx.WriteString("OK body is still:\n")
  16. ctx.Write(body)
  17. }
  18. })
  19. app.Listen(":8080", iris.WithoutBodyConsumptionOnUnmarshal)
  20. }
  21. func logAllBody(ctx iris.Context) {
  22. body, err := ctx.GetBody()
  23. if err == nil && len(body) > 0 {
  24. ctx.Application().Logger().Infof("logAllBody: %s", string(body))
  25. }
  26. ctx.Next()
  27. }
  28. func logJSON(ctx iris.Context) {
  29. var p interface{}
  30. if err := ctx.ReadJSON(&p); err == nil {
  31. ctx.Application().Logger().Infof("logJSON: %#+v", p)
  32. }
  33. ctx.Next()
  34. }
  35. func logFormValues(ctx iris.Context) {
  36. values := ctx.FormValues()
  37. if values != nil {
  38. ctx.Application().Logger().Infof("logFormValues: %v", values)
  39. }
  40. ctx.Next()
  41. }

You can use the ReadBody to bind a struct to a request based on the client’s content-type. You can also use Content Negotiation. Here’s a full example:

  1. package main
  2. import (
  3. "github.com/kataras/iris/v12"
  4. )
  5. func main() {
  6. app := newApp()
  7. // See main_test.go for usage.
  8. app.Listen(":8080")
  9. }
  10. func newApp() *iris.Application {
  11. app := iris.New()
  12. // To automatically decompress using gzip:
  13. // app.Use(iris.GzipReader)
  14. app.Use(setAllowedResponses)
  15. app.Post("/", readBody)
  16. return app
  17. }
  18. type payload struct {
  19. Message string `json:"message" xml:"message" msgpack:"message" yaml:"Message" url:"message" form:"message"`
  20. }
  21. func readBody(ctx iris.Context) {
  22. var p payload
  23. // Bind request body to "p" depending on the content-type that client sends the data,
  24. // e.g. JSON, XML, YAML, MessagePack, Protobuf, Form and URL Query.
  25. err := ctx.ReadBody(&p)
  26. if err != nil {
  27. ctx.StopWithProblem(iris.StatusBadRequest,
  28. iris.NewProblem().Title("Parser issue").Detail(err.Error()))
  29. return
  30. }
  31. // For the sake of the example, log the received payload.
  32. ctx.Application().Logger().Infof("Received: %#+v", p)
  33. // Send back the payload depending on the accept content type and accept-encoding of the client,
  34. // e.g. JSON, XML and so on.
  35. ctx.Negotiate(p)
  36. }
  37. func setAllowedResponses(ctx iris.Context) {
  38. // Indicate that the Server can send JSON, XML, YAML and MessagePack for this request.
  39. ctx.Negotiation().JSON().XML().YAML().MsgPack()
  40. // Add more, allowed by the server format of responses, mime types here...
  41. // If client is missing an "Accept: " header then default it to JSON.
  42. ctx.Negotiation().Accept.JSON()
  43. ctx.Next()
  44. }