diff --git a/HISTORY.md b/HISTORY.md
index a4b0f2fb..7f98dd2c 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -2,6 +2,19 @@
**How to upgrade**: remove your `$GOPATH/src/github.com/kataras/iris` folder, open your command-line and execute this command: `go get -u github.com/kataras/iris`.
+## 4.2.0 -> 4.2.1
+
+- **CHANGE**: No front-end changes if you used the default response engines before. Response Engines to Serializers, `iris.ResponseEngine` `serializer.Serializer`, comes from `kataras/go-serializer` which is installed automatically when you upgrade iris with `-u` flag.
+
+ - the repo "github.com/iris-contrib/response" is a clone of "github.com/kataras/go-serializer", to keep compatibility state. examples and gitbook updated to work with the last.
+
+ - `iris.UseResponse(iris.ResponseEngine, ...string)func (string)` was used to register custom response engines, now you use: `iris.UseSerializer(key string, s serializer.Serializer)`.
+
+ - `iris.ResponseString` same defintion but differnet name now: `iris.SerializeToString`
+
+[Serializer examples](https://github.com/iris-contrib/examples/tree/master/serialize_engines) and [Book section](https://kataras.gitbooks.io/iris/content/serialize-engines.html) updated.
+
+
## 4.1.7 -> 4.2.0
- **ADDED**: `iris.TemplateSourceString(src string, binding interface{}) string` this will parse the src raw contents to the template engine and return the string result & `context.RenderTemplateSource(status int, src string, binding interface{}, options ...map[string]interface{}) error` this will parse the src raw contents to the template engine and render the result to the client, as requseted [here](https://github.com/kataras/iris/issues/409).
diff --git a/README.md b/README.md
index 6d33e3e1..613baf8f 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@
-
+
@@ -178,7 +178,7 @@ I recommend writing your API tests using this new library, [httpexpect](https://
Versioning
------------
-Current: **v4.2.0**
+Current: **v4.2.1**
> Iris is an active project
@@ -221,7 +221,7 @@ License can be found [here](LICENSE).
[Travis]: http://travis-ci.org/kataras/iris
[License Widget]: https://img.shields.io/badge/license-MIT%20%20License%20-E91E63.svg?style=flat-square
[License]: https://github.com/kataras/iris/blob/master/LICENSE
-[Release Widget]: https://img.shields.io/badge/release-v4.2.0-blue.svg?style=flat-square
+[Release Widget]: https://img.shields.io/badge/release-v4.2.1-blue.svg?style=flat-square
[Release]: https://github.com/kataras/iris/releases
[Chat Widget]: https://img.shields.io/badge/community-chat-00BCD4.svg?style=flat-square
[Chat]: https://kataras.rocket.chat/channel/iris
diff --git a/context.go b/context.go
index 6a29e03c..746459df 100644
--- a/context.go
+++ b/context.go
@@ -534,6 +534,47 @@ func (ctx *Context) Gzip(b []byte, status int) {
}
}
+// renderSerialized renders contents with a serializer with status OK which you can change using RenderWithStatus or ctx.SetStatusCode(iris.StatusCode)
+func (ctx *Context) renderSerialized(contentType string, obj interface{}, options ...map[string]interface{}) error {
+ s := ctx.framework.serializers
+ finalResult, err := s.Serialize(contentType, obj, options...)
+ if err != nil {
+ return err
+ }
+
+ gzipEnabled := ctx.framework.Config.Gzip
+ charset := ctx.framework.Config.Charset
+ if len(options) > 0 {
+ gzipEnabled = getGzipOption(gzipEnabled, options[0]) // located to the template.go below the RenderOptions
+ charset = getCharsetOption(charset, options[0])
+ }
+ ctype := contentType
+
+ if ctype == contentMarkdown { // remember the text/markdown is just a custom internal iris content type, which in reallity renders html
+ ctype = contentHTML
+ }
+
+ if ctype != contentBinary { // set the charset only on non-binary data
+ ctype += "; charset=" + charset
+ }
+ ctx.SetContentType(ctype)
+
+ if gzipEnabled && ctx.clientAllowsGzip() {
+ _, err := fasthttp.WriteGzip(ctx.RequestCtx.Response.BodyWriter(), finalResult)
+ if err != nil {
+ return err
+ }
+ ctx.RequestCtx.Response.Header.Add(varyHeader, acceptEncodingHeader)
+ ctx.SetHeader(contentEncodingHeader, "gzip")
+ } else {
+ ctx.Response.SetBody(finalResult)
+ }
+
+ ctx.SetStatusCode(StatusOK)
+
+ return nil
+}
+
// RenderTemplateSource serves a template source(raw string contents) from the first template engines which supports raw parsing returns its result as string
func (ctx *Context) RenderTemplateSource(status int, src string, binding interface{}, options ...map[string]interface{}) error {
err := ctx.framework.templates.renderSource(ctx, src, binding, options...)
@@ -544,13 +585,14 @@ func (ctx *Context) RenderTemplateSource(status int, src string, binding interfa
return err
}
-// RenderWithStatus builds up the response from the specified template or a response engine.
-// Note: the options: "gzip" and "charset" are built'n support by Iris, so you can pass these on any template engine or response engine
+// RenderWithStatus builds up the response from the specified template or a serialize engine.
+// Note: the options: "gzip" and "charset" are built'n support by Iris, so you can pass these on any template engine or serialize engines
func (ctx *Context) RenderWithStatus(status int, name string, binding interface{}, options ...map[string]interface{}) (err error) {
if strings.IndexByte(name, '.') > -1 { //we have template
err = ctx.framework.templates.render(ctx, name, binding, options...)
+ } else {
+ err = ctx.renderSerialized(name, binding, options...)
}
- err = ctx.framework.responses.getBy(name).render(ctx, binding, options...)
if err == nil {
ctx.SetStatusCode(status)
@@ -560,8 +602,8 @@ func (ctx *Context) RenderWithStatus(status int, name string, binding interface{
}
// Render same as .RenderWithStatus but with status to iris.StatusOK (200) if no previous status exists
-// builds up the response from the specified template or a response engine.
-// Note: the options: "gzip" and "charset" are built'n support by Iris, so you can pass these on any template engine or response engine
+// builds up the response from the specified template or a serialize engine.
+// Note: the options: "gzip" and "charset" are built'n support by Iris, so you can pass these on any template engine or serialize engine
func (ctx *Context) Render(name string, binding interface{}, options ...map[string]interface{}) error {
errCode := ctx.RequestCtx.Response.StatusCode()
if errCode <= 0 {
@@ -571,8 +613,8 @@ func (ctx *Context) Render(name string, binding interface{}, options ...map[stri
}
// MustRender same as .Render but returns 500 internal server http status (error) if rendering fail
-// builds up the response from the specified template or a response engine.
-// Note: the options: "gzip" and "charset" are built'n support by Iris, so you can pass these on any template engine or response engine
+// builds up the response from the specified template or a serialize engine.
+// Note: the options: "gzip" and "charset" are built'n support by Iris, so you can pass these on any template engine or serialize engine
func (ctx *Context) MustRender(name string, binding interface{}, options ...map[string]interface{}) {
if err := ctx.Render(name, binding, options...); err != nil {
ctx.Panic()
@@ -591,7 +633,7 @@ func (ctx *Context) TemplateString(name string, binding interface{}, options ...
// HTML writes html string with a http status
func (ctx *Context) HTML(status int, htmlContents string) {
if err := ctx.RenderWithStatus(status, contentHTML, htmlContents); err != nil {
- // if no response engine found for text/html
+ // if no serialize engine found for text/html
ctx.SetContentType(contentHTML + "; charset=" + ctx.framework.Config.Charset)
ctx.RequestCtx.SetStatusCode(status)
ctx.RequestCtx.WriteString(htmlContents)
@@ -625,7 +667,7 @@ func (ctx *Context) XML(status int, v interface{}) error {
// MarkdownString parses the (dynamic) markdown string and returns the converted html string
func (ctx *Context) MarkdownString(markdownText string) string {
- return ctx.framework.ResponseString(contentMarkdown, markdownText)
+ return ctx.framework.SerializeToString(contentMarkdown, markdownText)
}
// Markdown parses and renders to the client a particular (dynamic) markdown string
diff --git a/iris.go b/iris.go
index c3d3001b..b952174d 100644
--- a/iris.go
+++ b/iris.go
@@ -65,14 +65,9 @@ import (
"time"
"github.com/gavv/httpexpect"
- "github.com/iris-contrib/response/data"
- "github.com/iris-contrib/response/json"
- "github.com/iris-contrib/response/jsonp"
- "github.com/iris-contrib/response/markdown"
- "github.com/iris-contrib/response/text"
- "github.com/iris-contrib/response/xml"
"github.com/kataras/go-errors"
"github.com/kataras/go-fs"
+ "github.com/kataras/go-serializer"
"github.com/kataras/go-sessions"
"github.com/kataras/go-template"
"github.com/kataras/go-template/html"
@@ -83,7 +78,7 @@ import (
const (
// Version of the iris
- Version = "4.2.0"
+ Version = "4.2.1"
banner = ` _____ _
|_ _| (_)
@@ -152,7 +147,7 @@ type (
Go() error
Close() error
UseSessionDB(sessions.Database)
- UseResponse(ResponseEngine, ...string) func(string)
+ UseSerializer(string, serializer.Serializer)
UseTemplate(template.Engine) *template.Loader
UseGlobal(...Handler)
UseGlobalFunc(...HandlerFunc)
@@ -162,7 +157,7 @@ type (
URL(string, ...interface{}) string
TemplateString(string, interface{}, ...map[string]interface{}) string
TemplateSourceString(string, interface{}) string
- ResponseString(string, interface{}, ...map[string]interface{}) string
+ SerializeToString(string, interface{}, ...map[string]interface{}) string
Tester(*testing.T) *httpexpect.Expect
}
@@ -174,7 +169,7 @@ type (
contextPool sync.Pool
Config *Configuration
sessions sessions.Sessions
- responses *responseEngines
+ serializers serializer.Serializers
templates *templateEngines
// fields which are useful to the user/dev
// the last added server is the main server
@@ -214,7 +209,7 @@ func New(setters ...OptionSetter) *Framework {
// rendering
{
- s.responses = newResponseEngines()
+ s.serializers = serializer.Serializers{}
// set the templates
s.templates = newTemplateEngines(map[string]interface{}{
"url": s.URL,
@@ -262,28 +257,8 @@ func (s *Framework) Set(setters ...OptionSetter) {
}
func (s *Framework) initialize() {
- // prepare the response engines, if no response engines setted for the default content-types
- // then add them
-
- for _, ctype := range defaultResponseKeys {
- if rengine := s.responses.getBy(ctype); rengine == nil {
- // if not exists
- switch ctype {
- case contentText:
- s.UseResponse(text.New(), ctype)
- case contentBinary:
- s.UseResponse(data.New(), ctype)
- case contentJSON:
- s.UseResponse(json.New(), ctype)
- case contentJSONP:
- s.UseResponse(jsonp.New(), ctype)
- case contentXML:
- s.UseResponse(xml.New(), ctype)
- case contentMarkdown:
- s.UseResponse(markdown.New(), ctype)
- }
- }
- }
+ // prepare the serializers, if not any other serializers setted for the default serializer types(json,jsonp,xml,markdown,text,data) then the defaults are setted:
+ serializer.RegisterDefaults(s.serializers)
// prepare the templates if enabled
if !s.Config.DisableTemplateEngines {
@@ -606,56 +581,38 @@ func (s *Framework) UseSessionDB(db sessions.Database) {
s.sessions.UseDatabase(db)
}
-// UseResponse accepts a ResponseEngine and the key or content type on which the developer wants to register this response engine
+// UseSerializer accepts a Serializer and the key or content type on which the developer wants to register this serializer
// the gzip and charset are automatically supported by Iris, by passing the iris.RenderOptions{} map on the context.Render
// context.Render renders this response or a template engine if no response engine with the 'key' found
// with these engines you can inject the context.JSON,Text,Data,JSONP,XML also
-// to do that just register with UseResponse(myEngine,"application/json") and so on
-// look at the https://github.com/iris-contrib/response for examples
+// to do that just register with UseSerializer(mySerializer,"application/json") and so on
+// look at the https://github.com/kataras/go-serializer for examples
//
-// if more than one respone engine with the same key/content type exists then the results will be appended to the final request's body
+// if more than one serializer with the same key/content type exists then the results will be appended to the final request's body
// this allows the developer to be able to create 'middleware' responses engines
//
// Note: if you pass an engine which contains a dot('.') as key, then the engine will not be registered.
// you don't have to import and use github.com/iris-contrib/json, jsonp, xml, data, text, markdown
// because iris uses these by default if no other response engine is registered for these content types
-//
-// Note 2:
-// one key has one content type but many response engines ( one to many)
-//
-// returns a function(string) which you can set the content type, if it's not already declared from the key.
-// careful you should call this in the same execution.
-// one last thing, you can have unlimited number of response engines for the same key and same content type.
-// key and content type may be different, but one key is only for one content type,
-// Do not use different content types with more than one response engine on the same key
-func UseResponse(e ResponseEngine, forContentTypesOrKeys ...string) func(string) {
- return Default.UseResponse(e, forContentTypesOrKeys...)
+func UseSerializer(forContentType string, e serializer.Serializer) {
+ Default.UseSerializer(forContentType, e)
}
-// UseResponse accepts a ResponseEngine and the key or content type on which the developer wants to register this response engine
+// UseSerializer accepts a Serializer and the key or content type on which the developer wants to register this serializer
// the gzip and charset are automatically supported by Iris, by passing the iris.RenderOptions{} map on the context.Render
// context.Render renders this response or a template engine if no response engine with the 'key' found
// with these engines you can inject the context.JSON,Text,Data,JSONP,XML also
-// to do that just register with UseResponse(myEngine,"application/json") and so on
-// look at the https://github.com/iris-contrib/response for examples
+// to do that just register with UseSerializer(mySerializer,"application/json") and so on
+// look at the https://github.com/kataras/go-serializer for examples
//
-// if more than one respone engine with the same key/content type exists then the results will be appended to the final request's body
+// if more than one serializer with the same key/content type exists then the results will be appended to the final request's body
// this allows the developer to be able to create 'middleware' responses engines
//
// Note: if you pass an engine which contains a dot('.') as key, then the engine will not be registered.
// you don't have to import and use github.com/iris-contrib/json, jsonp, xml, data, text, markdown
// because iris uses these by default if no other response engine is registered for these content types
-//
-// Note 2:
-// one key has one content type but many response engines ( one to many)
-//
-// returns a function(string) which you can set the content type, if it's not already declared from the key.
-// careful you should call this in the same execution.
-// one last thing, you can have unlimited number of response engines for the same key and same content type.
-// key and content type may be different, but one key is only for one content type,
-// Do not use different content types with more than one response engine on the same key
-func (s *Framework) UseResponse(e ResponseEngine, forContentTypesOrKeys ...string) func(string) {
- return s.responses.add(e, forContentTypesOrKeys...)
+func (s *Framework) UseSerializer(forContentType string, e serializer.Serializer) {
+ s.serializers.For(forContentType, e)
}
// UseTemplate adds a template engine to the iris view system
@@ -939,18 +896,18 @@ func (s *Framework) TemplateSourceString(src string, pageContext interface{}) st
return res
}
-// ResponseString returns the string of a response engine,
+// SerializeToString returns the string of a serializer,
// does not render it to the client
// returns empty string on error
-func ResponseString(keyOrContentType string, obj interface{}, options ...map[string]interface{}) string {
- return Default.ResponseString(keyOrContentType, obj, options...)
+func SerializeToString(keyOrContentType string, obj interface{}, options ...map[string]interface{}) string {
+ return Default.SerializeToString(keyOrContentType, obj, options...)
}
-// ResponseString returns the string of a response engine,
+// SerializeToString returns the string of a serializer,
// does not render it to the client
// returns empty string on error
-func (s *Framework) ResponseString(keyOrContentType string, obj interface{}, options ...map[string]interface{}) string {
- res, err := s.responses.getBy(keyOrContentType).toString(obj, options...)
+func (s *Framework) SerializeToString(keyOrContentType string, obj interface{}, options ...map[string]interface{}) string {
+ res, err := s.serializers.SerializeToString(keyOrContentType, obj, options...)
if err != nil {
return ""
}
diff --git a/response.go b/response.go
deleted file mode 100644
index 8310c776..00000000
--- a/response.go
+++ /dev/null
@@ -1,251 +0,0 @@
-package iris
-
-import (
- "strings"
-
- "github.com/kataras/go-errors"
- "github.com/kataras/go-template"
- "github.com/valyala/fasthttp"
-)
-
-type (
- // notes for me:
- // edw an kai kalh idea alla den 9a borw na exw ta defaults mesa sto iris
- // kai 9a prepei na to metaferw auto sto context i sto utils kai pragmatika den leei
- // na kanoun import auto gia na kanoun to response engine, ara na prospa9isw kapws aliws mesw context.IContext mono
- // ektos an metaferw ta defaults mesa sto iris
- // alla an to kanw auto 9a prepei na vrw tropo na kanoun configuration ta defaults
- // kai to idio prepei na kanw kai sto template engine html tote...
- // diladi na kanw prwta to render tou real engine kai meta na parw
- // ta contents tou body kai na ta kanw gzip ? na kanw resetbody kai na ta ksanasteilw?
- // alla auto einai argh methodos kai gia ton poutso dn m aresei
- // kai ola auta gia na mh valw ena property parapanw? 9a valw ...
- // 9a einai writer,headers,object,options... anagastika.
-
- /* notes for me:
- english 'final' thoughs' results now:
-
- the response engine will be registered with its content type
- for example: iris.UseResponse("application/json", the engine or func here, optionalOptions...)
- if more than one response engines registered for the same content type
- then all the content results will be sent to the client
- there will be available a system something like middleware but for the response engines
- this will be useful when one response engine's job is only to add more content to the existing/parent response engine's results .
- for example when you want to add a standard json object like a last_fetch { "year":...,"month":...,"day":...} for all json responses.
- The engine will not have access to context or something like that.
- The default engines will registered when no other engine with the same content type
- already registered, like I did with template engines, so if someone wants to make a 'middleware' for the default response engines
- must register them explicit and after register his/her response engine too, for that reason
- the default engines will not be located inside iris but inside iris-contrib (like the default,and others, template engine),
- the reason is to be easier to the user/dev to remember what import path should use when he/she wants to edit something,
- for templates it's 'iris-contrib/template', for response engines will be 'iris-contrib/response'.
- The body content will return as []byte, al/mong with an error if something bad happened.
- Now you may ask why not set the header inside from response engine? because to do that we could have one of these four downsides:
- 1.to have access to context.IContext or *Context(if *Context then default engines should live here in iris repo)
- and if we have context.IContext or *Context we will not be able to set a fast built'n gzip option,
- because we would copy the contents to the gzip writer, and after copy these contents back to the response body's writer
- but with an io.Writer as parameter we can simple change this writer to gzip writer and continue to the response engine after.
- 2. we could make something like ResponseWriter struct { io.Writer,Header *fasthttp.ResponseHeader}
- inside iris repo(then the default response engines should exists in the iris repo and configuration will depends on the iris' configs )
- or inside context/ folder inside iris repo, then the user/dev should import this path to
- do his/her response engine, and I want simple things as usual, also we would make a pool for this response writer and create new if not available exist,
- and this is performarnce downs witch I dissalow on Iris whne no need.
- 3. to have 4 parameters, the writer, the headers(again the user should import the fasthttp to do his/her response engine and I want simple things, as I told before),
- the object and the optional parameters
- 4. one more function to implement like 'ContentType() string', but if we select this we lose the functionality for ResponseEngine created as simple function,
- and the biggest issue will be that one response engine must explicit exists for one content type, the user/dev will not be available (to easly)
- to set the content type for the engine.
- these were the reasons I decide to set the content type by the frontend iris API itself and not taken by the response engine.
-
- The Response will have two parameters (one required only) interface{], ...options}, and two return values([]byte,error)
- The (first) parameter will be an interface{}, for json a json struct, for xml an xml struct, for binary data .([]byte) and so on
- There will be available a second optional parameter, map of options, the "gzip" option will be built'n implemented by iris
- so the response engines no need to manually add gzip support(same with template engines).
- The Charset will be added to the headers automatically, for the previous example of json and the default charset which is UTF-8
- the end "Content-Type" header content will be: "application/json; charset=UTF-8"
- if the registered content type is not a $content/type then the text/plain will be sent to the client.
-
- OR WAIT, some engines maybe want to set the content type or other headers dynamically or render a response depends on cookies or some other existence headers
- on that situtions it will be impossible with this implementation I explained before, so...
- access to context.IContext and return the []byte, in order to be able to add the built'n gzip support
- the dev/user will have to make this import no no no we stick to the previous though, because
- if the user wants to check all that he/she can just use a middleware with .Use/.UseFunc
- this is not a middleware implementation, this is a custom content rendering, let's stick to that.
-
- Ok I did that and I realized that template and response engines, final method structure (string,interface{},options...) is the same
- so I make the ctx.Render/RenderWithStatus to work with both engines, so the developer can use any type of response engine and render it with ease.
- Maybe at the future I could have one file 'render.go' which will contain the template engines and response engines, we will see, these all are unique so excuse me if something goes wrong xD
-
- That's all. Hope some one (other than me) will understand the english here...
- */
-
- // ResponseEngine is the interface which all response engines should implement to send responses
- // ResponseEngine(s) can be registered with,for example: iris.UseResponse(json.New(), "application/json")
- ResponseEngine interface {
- Response(interface{}, ...map[string]interface{}) ([]byte, error)
- }
- // ResponseEngineFunc is the alternative way to implement a ResponseEngine using a simple function
- ResponseEngineFunc func(interface{}, ...map[string]interface{}) ([]byte, error)
-
- // responseEngineMap is a wrapper with key (content type or name) values(engines) for the registered response engine
- // it contains all response engines for a specific contentType and two functions, render and toString
- // these will be used by the iris' context and iris' ResponseString, yes like TemplateToString
- // it's an internal struct, no need to be exported and return that on registration,
- // because the two top funcs will be easier to use by the user/dev for multiple engines
- responseEngineMap struct {
- values []ResponseEngine
- // this is used in order to the wrapper to be gettable by the responseEngines iteral,
- // if key is not a $content/type and contentType is not changed by the user/dev then the text/plain will be sent to the client
- key string
- contentType string
- }
-)
-
-var (
- // markdown is custom type, used inside iris to initialize the defaults response engines if no other engine registered with these keys
- defaultResponseKeys = [...]string{contentText, contentXML, contentBinary, contentJSON, contentJSONP, contentMarkdown}
-)
-
-// Response returns a response to the client(request's body content)
-func (r ResponseEngineFunc) Response(obj interface{}, options ...map[string]interface{}) ([]byte, error) {
- return r(obj, options...)
-}
-
-var errNoResponseEngineFound = errors.New("No response engine found")
-
-// on context: Send(contentType string, obj interface{}, ...options)
-
-func (r *responseEngineMap) add(engine ResponseEngine) {
- r.values = append(r.values, engine)
-}
-
-// the gzip and charset options are built'n with iris
-func (r *responseEngineMap) render(ctx *Context, obj interface{}, options ...map[string]interface{}) error {
-
- if r == nil {
- //render, but no response engine registered, this caused by context.RenderWithStatus, and responseEngines. getBy
- return errNoResponseEngineFound
- }
-
- var finalResult []byte
-
- for i, n := 0, len(r.values); i < n; i++ {
- result, err := r.values[i].Response(obj, options...)
- if err != nil { // fail on first the first error
- return err
- }
- finalResult = append(finalResult, result...)
- }
-
- gzipEnabled := ctx.framework.Config.Gzip
- charset := ctx.framework.Config.Charset
- if len(options) > 0 {
- gzipEnabled = template.GetGzipOption(gzipEnabled, options[0]) // located to the template.go below the RenderOptions
- charset = template.GetCharsetOption(charset, options[0])
- }
- ctype := r.contentType
-
- if r.contentType != contentBinary { // set the charset only on non-binary data
- ctype += "; charset=" + charset
- }
- ctx.SetContentType(ctype)
-
- if gzipEnabled && ctx.clientAllowsGzip() {
- _, err := fasthttp.WriteGzip(ctx.RequestCtx.Response.BodyWriter(), finalResult)
- if err != nil {
- return err
- }
- ctx.RequestCtx.Response.Header.Add(varyHeader, acceptEncodingHeader)
- ctx.SetHeader(contentEncodingHeader, "gzip")
- } else {
- ctx.Response.SetBody(finalResult)
- }
-
- return nil
-}
-
-func (r *responseEngineMap) toString(obj interface{}, options ...map[string]interface{}) (string, error) {
- if r == nil {
- //render, but no response engine registered, this caused by context.RenderWithStatus, and responseEngines. getBy
- return "", errNoResponseEngineFound
- }
- var finalResult []byte
- for i, n := 0, len(r.values); i < n; i++ {
- result, err := r.values[i].Response(obj, options...)
- if err != nil {
- return "", err
- }
- finalResult = append(finalResult, result...)
- }
- return string(finalResult), nil
-}
-
-type responseEngines struct {
- engines []*responseEngineMap
-}
-
-func newResponseEngines() *responseEngines {
- return &responseEngines{}
-}
-
-// add accepts a simple response engine with its content type or key, key should not contains a dot('.').
-// if key is a content type then it's the content type, but if it not, set the content type from the returned function,
-// if it not called/changed then the default content type text/plain will be used.
-// different content types for the same key will produce bugs, as it should!
-// one key has one content type but many response engines ( one to many)
-// note that the func should be used on the same call
-func (r *responseEngines) add(engine ResponseEngine, forContentTypesOrKeys ...string) func(string) {
- if r.engines == nil {
- r.engines = make([]*responseEngineMap, 0)
- }
-
- var engineMap *responseEngineMap
- for _, key := range forContentTypesOrKeys {
- if strings.IndexByte(key, '.') != -1 { // the dot is not allowed as key
- continue // skip this engine
- }
-
- defaultCtypeAndKey := contentText
- if len(key) == 0 {
- //if empty key, then set it to text/plain
- key = defaultCtypeAndKey
- }
-
- engineMap = r.getBy(key)
- if engineMap == nil {
-
- ctype := defaultCtypeAndKey
- if strings.IndexByte(key, slashByte) != -1 { // pure check, but developer should know the content types at least.
- // we have 'valid' content type
- ctype = key
- }
- // the context.Markdown works without it but with .Render we will have problems without this:
- if key == contentMarkdown { // remember the text/markdown is just a custom internal iris content type, which in reallity renders html
- ctype = contentHTML
- }
- engineMap = &responseEngineMap{values: make([]ResponseEngine, 0), key: key, contentType: ctype}
- r.engines = append(r.engines, engineMap)
- }
- engineMap.add(engine)
- }
-
- return func(theContentType string) {
- // and this
- if theContentType == contentMarkdown {
- theContentType = contentHTML
- }
-
- engineMap.contentType = theContentType
- }
-
-}
-
-func (r *responseEngines) getBy(key string) *responseEngineMap {
- for i, n := 0, len(r.engines); i < n; i++ {
- if r.engines[i].key == key {
- return r.engines[i]
- }
-
- }
- return nil
-}
diff --git a/template.go b/template.go
index 7d6cdb6e..575af69f 100644
--- a/template.go
+++ b/template.go
@@ -33,6 +33,24 @@ func newTemplateEngines(sharedFuncs map[string]interface{}) *templateEngines {
return &templateEngines{Mux: template.NewMux(sharedFuncs)}
}
+// getGzipOption receives a default value and the render options map and returns if gzip is enabled for this render action
+func getGzipOption(defaultValue bool, options map[string]interface{}) bool {
+ gzipOpt := options["gzip"] // we only need that, so don't create new map to keep the options.
+ if b, isBool := gzipOpt.(bool); isBool {
+ return b
+ }
+ return defaultValue
+}
+
+// gtCharsetOption receives a default value and the render options map and returns the correct charset for this render action
+func getCharsetOption(defaultValue string, options map[string]interface{}) string {
+ charsetOpt := options["charset"]
+ if s, isString := charsetOpt.(string); isString {
+ return s
+ }
+ return defaultValue
+}
+
// render executes a template and write its result to the context's body
// options are the optional runtime options can be passed by user and catched by the template engine when render
// an example of this is the "layout"
@@ -43,8 +61,8 @@ func (t *templateEngines) render(ctx *Context, filename string, binding interfac
gzipEnabled := ctx.framework.Config.Gzip
charset := ctx.framework.Config.Charset
if len(options) > 0 {
- gzipEnabled = template.GetGzipOption(gzipEnabled, options[0])
- charset = template.GetCharsetOption(charset, options[0])
+ gzipEnabled = getGzipOption(gzipEnabled, options[0])
+ charset = getCharsetOption(charset, options[0])
}
ctxLayout := ctx.GetString(TemplateLayoutContextKey)