1
0
mirror of https://github.com/kataras/iris.git synced 2026-01-08 12:31:58 +00:00

add context.Protobuf, MsgPack, ReadProtobuf, ReadMsgPack methods

Former-commit-id: 39d547ecfb1516505a1eb76a12a1f6e9e4111962
This commit is contained in:
Gerasimos (Makis) Maropoulos
2020-04-08 16:48:22 +03:00
parent ee4213f72d
commit 837787104b
16 changed files with 215 additions and 40 deletions

View File

@@ -28,10 +28,12 @@ import (
"github.com/Shopify/goreferrer"
"github.com/fatih/structs"
"github.com/golang/protobuf/proto"
"github.com/iris-contrib/blackfriday"
"github.com/iris-contrib/schema"
jsoniter "github.com/json-iterator/go"
"github.com/microcosm-cc/bluemonday"
"github.com/vmihailenco/msgpack/v5"
"gopkg.in/yaml.v3"
)
@@ -607,17 +609,21 @@ type Context interface {
//
// Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-yaml/main.go
ReadYAML(outPtr interface{}) error
// ReadForm binds the formObject with the form data
// it supports any kind of type, including custom structs.
// ReadForm binds the request body of a form to the "formObject".
// It supports any kind of type, including custom structs.
// It will return nothing if request data are empty.
// The struct field tag is "form".
//
// Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-form/main.go
ReadForm(formObject interface{}) error
// ReadQuery binds the "ptr" with the url query string. The struct field tag is "url".
// ReadQuery binds url query to "ptr". The struct field tag is "url".
//
// Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-query/main.go
ReadQuery(ptr interface{}) error
// ReadProtobuf binds the body to the "ptr" of a proto Message and returns any error.
ReadProtobuf(ptr proto.Message) error
// ReadMsgPack binds the request body of msgpack format to the "ptr" and returns any error.
ReadMsgPack(ptr interface{}) error
// +------------------------------------------------------------+
// | Body (raw) Writers |
// +------------------------------------------------------------+
@@ -815,6 +821,10 @@ type Context interface {
Markdown(markdownB []byte, options ...Markdown) (int, error)
// YAML parses the "v" using the yaml parser and renders its result to the client.
YAML(v interface{}) (int, error)
// Protobuf parses the "v" of proto Message and renders its result to the client.
Protobuf(v proto.Message) (int, error)
// MsgPack parses the "v" of msgpack format and renders its result to the client.
MsgPack(v interface{}) (int, error)
// +-----------------------------------------------------------------------+
// | Content Νegotiation |
@@ -2650,8 +2660,8 @@ func (ctx *context) ReadYAML(outPtr interface{}) error {
// A shortcut for the `schema#IsErrPath`.
var IsErrPath = schema.IsErrPath
// ReadForm binds the formObject with the form data
// it supports any kind of type, including custom structs.
// ReadForm binds the request body of a form to the "formObject".
// It supports any kind of type, including custom structs.
// It will return nothing if request data are empty.
// The struct field tag is "form".
//
@@ -2665,7 +2675,7 @@ func (ctx *context) ReadForm(formObject interface{}) error {
return schema.DecodeForm(values, formObject)
}
// ReadQuery binds the "ptr" with the url query string. The struct field tag is "url".
// ReadQuery binds url query to "ptr". The struct field tag is "url".
//
// Example: https://github.com/kataras/iris/blob/master/_examples/http_request/read-query/main.go
func (ctx *context) ReadQuery(ptr interface{}) error {
@@ -2677,6 +2687,26 @@ func (ctx *context) ReadQuery(ptr interface{}) error {
return schema.DecodeQuery(values, ptr)
}
// ReadProtobuf binds the body to the "ptr" of a proto Message and returns any error.
func (ctx *context) ReadProtobuf(ptr proto.Message) error {
rawData, err := ctx.GetBody()
if err != nil {
return err
}
return proto.Unmarshal(rawData, ptr)
}
// ReadMsgPack binds the request body of msgpack format to the "ptr" and returns any error.
func (ctx *context) ReadMsgPack(ptr interface{}) error {
rawData, err := ctx.GetBody()
if err != nil {
return err
}
return msgpack.Unmarshal(rawData, ptr)
}
// +------------------------------------------------------------+
// | Body (raw) Writers |
// +------------------------------------------------------------+
@@ -3140,6 +3170,12 @@ const (
ContentMarkdownHeaderValue = "text/markdown"
// ContentYAMLHeaderValue header value for YAML data.
ContentYAMLHeaderValue = "application/x-yaml"
// ContentProtobufHeaderValue header value for Protobuf messages data.
ContentProtobufHeaderValue = "application/x-protobuf"
// ContentMsgPackHeaderValue header value for MsgPack data.
ContentMsgPackHeaderValue = "application/msgpack"
// ContentMsgPack2HeaderValue alternative header value for MsgPack data.
ContentMsgPack2HeaderValue = "application/x-msgpack"
// ContentFormHeaderValue header value for post form data.
ContentFormHeaderValue = "application/x-www-form-urlencoded"
// ContentFormMultipartHeaderValue header value for post multipart form data.
@@ -3583,6 +3619,28 @@ func (ctx *context) YAML(v interface{}) (int, error) {
return ctx.Write(out)
}
// Protobuf parses the "v" of proto Message and renders its result to the client.
func (ctx *context) Protobuf(v proto.Message) (int, error) {
out, err := proto.Marshal(v)
if err != nil {
return 0, err
}
ctx.ContentType(ContentProtobufHeaderValue)
return ctx.Write(out)
}
// MsgPack parses the "v" of msgpack format and renders its result to the client.
func (ctx *context) MsgPack(v interface{}) (int, error) {
out, err := msgpack.Marshal(v)
if err != nil {
return 0, err
}
ctx.ContentType(ContentMsgPackHeaderValue)
return ctx.Write(out)
}
// +-----------------------------------------------------------------------+
// | Content Νegotiation |
// | https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation | |
@@ -3628,11 +3686,13 @@ type N struct {
Markdown []byte
Binary []byte
JSON interface{}
Problem Problem
JSONP interface{}
XML interface{}
YAML interface{}
JSON interface{}
Problem Problem
JSONP interface{}
XML interface{}
YAML interface{}
Protobuf interface{}
MsgPack interface{}
Other []byte // custom content types.
}
@@ -3658,12 +3718,16 @@ func (n N) SelectContent(mime string) interface{} {
return n.XML
case ContentYAMLHeaderValue:
return n.YAML
case ContentProtobufHeaderValue:
return n.Protobuf
case ContentMsgPackHeaderValue, ContentMsgPack2HeaderValue:
return n.MsgPack
default:
return n.Other
}
}
const negotiationContextKey = "_iris_negotiation_builder"
const negotiationContextKey = "iris.negotiation_builder"
// Negotiation creates once and returns the negotiation builder
// to build server-side available prioritized content
@@ -3706,7 +3770,7 @@ func parseHeader(headerValue string) []string {
// The "v" can be a single `N` struct value.
// The "v" can be any value completes the `ContentSelector` interface.
// The "v" can be any value completes the `ContentNegotiator` interface.
// The "v" can be any value of struct(JSON, JSONP, XML, YAML) or
// The "v" can be any value of struct(JSON, JSONP, XML, YAML, Protobuf, MsgPack) or
// string(TEXT, HTML) or []byte(Markdown, Binary) or []byte with any matched mime type.
//
// If the "v" is nil, the `Context.Negotitation()` builder's
@@ -3791,6 +3855,15 @@ func (ctx *context) Negotiate(v interface{}) (int, error) {
return ctx.XML(v)
case ContentYAMLHeaderValue:
return ctx.YAML(v)
case ContentProtobufHeaderValue:
msg, ok := v.(proto.Message)
if !ok {
return -1, ErrContentNotSupported
}
return ctx.Protobuf(msg)
case ContentMsgPackHeaderValue, ContentMsgPack2HeaderValue:
return ctx.MsgPack(v)
default:
// maybe "Other" or v is []byte or string but not a built-in framework mime,
// for custom content types,
@@ -3966,6 +4039,32 @@ func (n *NegotiationBuilder) YAML(v ...interface{}) *NegotiationBuilder {
return n.MIME(ContentYAMLHeaderValue, content)
}
// Protobuf registers the "application/x-protobuf" content type and, optionally,
// a value that `Context.Negotiate` will render
// when a client accepts the "application/x-protobuf" content type.
//
// Returns itself for recursive calls.
func (n *NegotiationBuilder) Protobuf(v ...interface{}) *NegotiationBuilder {
var content interface{}
if len(v) > 0 {
content = v[0]
}
return n.MIME(ContentProtobufHeaderValue, content)
}
// MsgPack registers the "application/x-msgpack" and "application/msgpack" content types and, optionally,
// a value that `Context.Negotiate` will render
// when a client accepts one of the "application/x-msgpack" or "application/msgpack" content types.
//
// Returns itself for recursive calls.
func (n *NegotiationBuilder) MsgPack(v ...interface{}) *NegotiationBuilder {
var content interface{}
if len(v) > 0 {
content = v[0]
}
return n.MIME(ContentMsgPackHeaderValue+","+ContentMsgPack2HeaderValue, content)
}
// Any registers a wildcard that can match any client's accept content type.
//
// Returns itself for recursive calls.