diff --git a/README.md b/README.md index adf5fd45..62c890aa 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,9 @@ The fastest web framework for Go. - [![Alt: Benchmark results with pipeline and 500ms processing time](https://raw.githubusercontent.com/iris-contrib/website/gh-pages/assets/benchmark_horizontal_transparent.png)](#benchmarks) - - ```bash $ cat render_json.go ``` @@ -30,14 +27,6 @@ func main() { ``` > Learn more about [render](https://kataras.gitbooks.io/iris/content/render.html) -```bash -$ iris run render_json.go -``` - -> Runs & monitors for file changes, learn more about [cli](https://github.com/kataras/iris/tree/master/iris). - - - Installation ------------ The only requirement is the [Go Programming Language](https://golang.org/dl), at least v1.6 @@ -58,6 +47,7 @@ Features - Focus on high performance - Robust routing supports static and wildcard subdomains - View system supporting [6+](https://kataras.gitbooks.io/iris/content/render_templates.html) template engines +- Add custom [renders/responses](https://github.com/iris-contrib/examples/tree/master/response_engines/my_custom_response/main.go) or customize & replace the [defaults](https://github.com/iris-contrib/response/) (`context.JSON/JSONP/XML/Markdown/Text/Binary(...)`) - Highly scalable Websocket API with custom events - Sessions support with GC, memory & redis providers - Middlewares & Plugins were never be easier @@ -76,12 +66,18 @@ Features | Name | Description | Usage | | ------------------|:---------------------:|-------:| -| [HTML/Default Engine ](https://github.com/iris-contrib/template/tree/master/html) | HTML Template Engine (Default) |[example 1](https://github.com/iris-contrib/examples/blob/master/template_engines/template_html_1/main.go), [book section](https://kataras.gitbooks.io/iris/content/render_templates.html) -| [Django Engine ](https://github.com/iris-contrib/template/tree/master/django) | Django Template Engine |[example 1](https://github.com/iris-contrib/examples/blob/master/template_engines/template_django_1/main.go), [book section](https://kataras.gitbooks.io/iris/content/brender_templates.html) -| [Pug/Jade Engine ](https://github.com/iris-contrib/template/tree/master/pug) | Pug Template Engine |[example 1](https://github.com/iris-contrib/examples/blob/master/template_engines/template_pug_1/main.go), [book section](https://kataras.gitbooks.io/iris/content/render_templates.html) -| [Handlebars Engine ](https://github.com/iris-contrib/template/tree/master/handlebars) | Handlebars Template Engine |[example 1](https://github.com/iris-contrib/examples/blob/master/template_engines/template_handlebars_1/main.go), [book section](https://kataras.gitbooks.io/iris/content/render_templates.html) -| [Amber Engine ](https://github.com/iris-contrib/template/tree/master/amber) | Amber Template Engine |[example 1](https://github.com/iris-contrib/examples/blob/master/template_engines/template_amber_1/main.go), [book section](https://kataras.gitbooks.io/iris/content/render_templates.html) -| [Markdown Engine ](https://github.com/iris-contrib/template/tree/master/markdown) | Markdown Template Engine |[example 1](https://github.com/iris-contrib/examples/blob/master/template_engines/template_markdown_1/main.go), [book section](https://kataras.gitbooks.io/iris/content/render_templates.html) +| [JSON ](https://github.com/iris-contrib/response/tree/master/json) | JSON Response Engine (Default) |[example 1](https://github.com/iris-contrib/examples/blob/master/response_engines/json_1/main.go),[example 2](https://github.com/iris-contrib/examples/blob/master/response_engines/json_2/main.go), [book section](https://kataras.gitbooks.io/iris/content/render_response.html) +| [JSONP ](https://github.com/iris-contrib/response/tree/master/jsonp) | JSONP Response Engine (Default) |[example 1](https://github.com/iris-contrib/examples/blob/master/response_engines/jsonp_1/main.go),[example 2](https://github.com/iris-contrib/examples/blob/master/response_engines/jsonp_2/main.go), [book section](https://kataras.gitbooks.io/iris/content/render_response.html) +| [XML ](https://github.com/iris-contrib/response/tree/master/xml) | XML Response Engine (Default) |[example 1](https://github.com/iris-contrib/examples/blob/master/response_engines/xml_1/main.go),[example 2](https://github.com/iris-contrib/examples/blob/master/response_engines/xml_2/main.go), [book section](https://kataras.gitbooks.io/iris/content/render_response.html) +| [Markdown ](https://github.com/iris-contrib/response/tree/master/markdown) | Markdown Response Engine (Default) |[example 1](https://github.com/iris-contrib/examples/blob/master/response_engines/markdown_1/main.go),[example 2](https://github.com/iris-contrib/examples/blob/master/response_engines/markdown_2/main.go), [book section](https://kataras.gitbooks.io/iris/content/render_response.html) +| [Text](https://github.com/iris-contrib/response/tree/master/text) | Text Response Engine (Default) |[example 1](https://github.com/iris-contrib/examples/blob/master/response_engines/text_1/main.go), [book section](https://kataras.gitbooks.io/iris/content/render_response.html) +| [Binary Data ](https://github.com/iris-contrib/response/tree/master/data) | Binary Data Response Engine (Default) |[example 1](https://github.com/iris-contrib/examples/blob/master/response_engines/data_1/main.go), [book section](https://kataras.gitbooks.io/iris/content/render_response.html) +| [HTML/Default Engine ](https://github.com/iris-contrib/template/tree/master/html) | HTML Template Engine (Default) |[example ](https://github.com/iris-contrib/examples/blob/master/template_engines/template_html_0/main.go), [book section](https://kataras.gitbooks.io/iris/content/render_templates.html) +| [Django Engine ](https://github.com/iris-contrib/template/tree/master/django) | Django Template Engine |[example ](https://github.com/iris-contrib/examples/blob/master/template_engines/template_django_1/main.go), [book section](https://kataras.gitbooks.io/iris/content/brender_templates.html) +| [Pug/Jade Engine ](https://github.com/iris-contrib/template/tree/master/pug) | Pug Template Engine |[example ](https://github.com/iris-contrib/examples/blob/master/template_engines/template_pug_1/main.go), [book section](https://kataras.gitbooks.io/iris/content/render_templates.html) +| [Handlebars Engine ](https://github.com/iris-contrib/template/tree/master/handlebars) | Handlebars Template Engine |[example ](https://github.com/iris-contrib/examples/blob/master/template_engines/template_handlebars_1/main.go), [book section](https://kataras.gitbooks.io/iris/content/render_templates.html) +| [Amber Engine ](https://github.com/iris-contrib/template/tree/master/amber) | Amber Template Engine |[example ](https://github.com/iris-contrib/examples/blob/master/template_engines/template_amber_1/main.go), [book section](https://kataras.gitbooks.io/iris/content/render_templates.html) +| [Markdown Engine ](https://github.com/iris-contrib/template/tree/master/markdown) | Markdown Template Engine |[example ](https://github.com/iris-contrib/examples/blob/master/template_engines/template_markdown_1/main.go), [book section](https://kataras.gitbooks.io/iris/content/render_templates.html) | [Basicauth Middleware ](https://github.com/iris-contrib/middleware/tree/master/basicauth) | HTTP Basic authentication |[example 1](https://github.com/iris-contrib/examples/blob/master/middleware_basicauth_1/main.go), [example 2](https://github.com/iris-contrib/examples/blob/master/middleware_basicauth_2/main.go), [book section](https://kataras.gitbooks.io/iris/content/basic-authentication.html) | | [JWT Middleware ](https://github.com/iris-contrib/middleware/tree/master/jwt) | JSON Web Tokens |[example ](https://github.com/iris-contrib/examples/blob/master/middleware_jwt/main.go), [book section](https://kataras.gitbooks.io/iris/content/jwt.html) | | [Cors Middleware ](https://github.com/iris-contrib/middleware/tree/master/cors) | Cross Origin Resource Sharing W3 specification | [how to use ](https://github.com/iris-contrib/middleware/tree/master/cors#how-to-use) | @@ -149,17 +145,15 @@ Current: **v4.0.0-alpha.3** > Iris is an active project -- For a more 'stable' release take a look at the [version 3](https://github.com/kataras/iris/tree/v3), which keeps its [e-book](http://iris-go.com/assets/v3-book/iris.pdf) and [examples](https://github.com/iris-contrib/examples/tree/v3). - Todo ------------ > for 'v4' -- [x] Refactor & extend view engine, separate the engines from the main code base, easier for the community to create new view engines -- [x] Refactor & extend sessions, split the different databases functionality to the iris-contrib -- [ ] Refactor & extends the rest render engine in order to be able to developer to use their own implemention for rendering restful types, like, for example a custom JSON implementation using no-standard go package for encode/decode -- [x] Move the iris/websocket package's source code inside iris/websocket.go one file, to be easier to use by users without import a new package +- [x] Refactor & extend view engine, separate the engines from the main code base, easier for the community to create new view engines[*](https://github.com/iris-contrib/template) +- [x] Refactor & extend sessions, split the different databases functionality to the iris-contrib[*](https://github.com/iris-contrib/sessiondb) +- [x] Refactor & extends the rest render engine in order to be able to developer to use their own implemention for rendering restful types, like, for example a custom JSON implementation using no-standard go package for encode/decode[*](https://github.com/iris-contrib/response) +- [x] Move the iris/websocket package's source code inside iris/websocket.go one file, to be easier to use by users without import a new package[*](https://github.com/kataras/iris/blob/master/websocket.go) - [ ] configs package should be removed after all these, we will not need big configurations because of different packages splitted & moved to the iris-contrib, we will keep interfaces and all required things inside kataras/iris.go. - [ ] Implement all [opened community's feature requests](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aopen+label%3A%22feature+request%22) - [ ] Extend i18n middleware for easier and better internalization support diff --git a/iris.go b/iris.go index 248c20e4..88c9a043 100644 --- a/iris.go +++ b/iris.go @@ -148,6 +148,7 @@ type ( Go() error Close() error UseSessionDB(SessionDatabase) + UseResponse(ResponseEngine, ...string) func(string) UseTemplate(TemplateEngine) *TemplateEngineLocation UseGlobal(...Handler) UseGlobalFunc(...HandlerFunc) @@ -538,8 +539,17 @@ func (s *Framework) UseSessionDB(db SessionDatabase) { // 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 -func UseResponse(e ResponseEngine, forContentTypesOrKeys ...string) { - Default.UseResponse(e, forContentTypesOrKeys...) +// +// 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...) } // UseResponse accepts a ResponseEngine and the key or content type on which the developer wants to register this response engine @@ -555,8 +565,17 @@ func UseResponse(e ResponseEngine, forContentTypesOrKeys ...string) { // 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 -func (s *Framework) UseResponse(e ResponseEngine, forContentTypesOrKeys ...string) { - s.responses.add(e, forContentTypesOrKeys...) +// +// 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...) } // UseTemplate adds a template engine to the iris view system diff --git a/response.go b/response.go index 3d19dcbb..31d526c1 100644 --- a/response.go +++ b/response.go @@ -93,9 +93,9 @@ type ( 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 then the text/plain will be sent to the client + // 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 // it's not the full content type with charset + contentType string } ) @@ -104,13 +104,13 @@ var ( defaultResponseKeys = [...]string{contentText, contentXML, contentBinary, contentJSON, contentJSONP, contentMarkdown} ) -var errNoResponseEngineFound = errors.New("No response engine found") - // 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) { @@ -151,13 +151,13 @@ func (r *responseEngineMap) render(ctx *Context, obj interface{}, options ...map ctx.SetContentType(ctype) if gzipEnabled { - ctx.Response.Header.Add("Content-Encoding", "gzip") gzipWriter := ctx.framework.AcquireGzip(ctx.Response.BodyWriter()) defer ctx.framework.ReleaseGzip(gzipWriter) _, err := gzipWriter.Write(finalResult) if err != nil { return err } + ctx.Response.Header.Add("Content-Encoding", "gzip") } else { ctx.Response.SetBody(finalResult) } @@ -186,10 +186,17 @@ type responseEngines struct { } // add accepts a simple response engine with its content type or key, key should not contains a dot('.'). -func (r *responseEngines) add(engine ResponseEngine, forContentTypesOrKeys ...string) { +// 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 @@ -201,7 +208,7 @@ func (r *responseEngines) add(engine ResponseEngine, forContentTypesOrKeys ...st key = defaultCtypeAndKey } - engineMap := r.getBy(key) + engineMap = r.getBy(key) if engineMap == nil { ctype := defaultCtypeAndKey @@ -209,11 +216,25 @@ func (r *responseEngines) add(engine ResponseEngine, forContentTypesOrKeys ...st // 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 {