1
0
mirror of https://github.com/kataras/iris.git synced 2026-01-09 21:15:56 +00:00

Update to 4.0.0-alpha.3 - Response Engines, 'inject' the context.JSON/JSONP/Text/Data/Markdown/Render, Read HISTORY.md

## 4.0.0-alpha.2 -> 4.0.0-alpha.3

**New**

A **Response Engine** gives you the freedom to create/change the
render/response writer for

- `context.JSON`
- `context.JSONP`
- `context.XML`
- `context.Text`
- `context.Markdown`
- `context.Data`
- `context.Render("my_custom_type",mystructOrData{},
iris.RenderOptions{"gzip":false,"charset":"UTF-8"})`
- `context.MarkdownString`
- `iris.ResponseString(...)`

**Fix**
- https://github.com/kataras/iris/issues/294

**Small changes**

- `iris.Config.Charset`, before alpha.3 was `iris.Config.Rest.Charset` &
`iris.Config.Render.Template.Charset`, but you can override it at
runtime by passinth a map `iris.RenderOptions` on the `context.Render`
call .
- `iris.Config.IsDevelopment` , before alpha.1 was
`iris.Config.Render.Template.IsDevelopment`

**Websockets changes**

No need to import the `github.com/kataras/iris/websocket` to use the
`Connection` iteral, the websocket moved inside `kataras/iris` , now all
exported variables' names have the prefix of `Websocket`, so the old
`websocket.Connection` is now `iris.WebsocketConnection`.

Generally, no other changes on the 'frontend API', for response engines
examples and how you can register your own to add more features on
existing response engines or replace them, look
[here](https://github.com/iris-contrib/response).

**BAD SIDE**: E-Book is still pointing on the v3 release, but will be
updated soon.
This commit is contained in:
Gerasimos Maropoulos
2016-07-18 17:40:42 +03:00
parent 077984bd60
commit 675c0d510c
17 changed files with 1717 additions and 1358 deletions

162
iris.go
View File

@@ -45,13 +45,14 @@
//
// -----------------------------DOCUMENTATION----------------------------
// ----------------------------_______________---------------------------
// For middleware, templates, sessions, websockets, mails, subdomains,
// For middleware, template engines, response engines, sessions, websockets, mails, subdomains,
// dynamic subdomains, routes, party of subdomains & routes and much more
// visit https://www.gitbook.com/book/kataras/iris/details
package iris // import "github.com/kataras/iris"
import (
"fmt"
"io"
"net/http"
"os"
"path"
@@ -61,23 +62,29 @@ import (
"testing"
"time"
"github.com/klauspost/compress/gzip"
"sync"
"github.com/gavv/httpexpect"
"github.com/iris-contrib/errors"
"github.com/iris-contrib/logger"
"github.com/iris-contrib/rest"
"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/iris-contrib/template/html"
"github.com/kataras/iris/config"
"github.com/kataras/iris/context"
"github.com/kataras/iris/utils"
"github.com/kataras/iris/websocket"
"github.com/valyala/fasthttp"
)
const (
// Version of the iris
Version = "4.0.0-alpha.2"
Version = "4.0.0-alpha.3"
banner = ` _____ _
|_ _| (_)
@@ -93,7 +100,7 @@ var (
Config *config.Iris
Logger *logger.Logger
Plugins PluginContainer
Websocket websocket.Server
Websocket WebsocketServer
Servers *ServerList
// Available is a channel type of bool, fired to true when the server is opened and all plugins ran
// never fires false, if the .Close called then the channel is re-allocating.
@@ -151,6 +158,7 @@ type (
Path(string, ...interface{}) string
URL(string, ...interface{}) string
TemplateString(string, interface{}, ...map[string]interface{}) string
ResponseString(string, interface{}, ...map[string]interface{}) string
Tester(t *testing.T) *httpexpect.Expect
}
@@ -159,18 +167,18 @@ type (
// Implements the FrameworkAPI
Framework struct {
*muxAPI
rest *rest.Render
sessions *sessionsManager
templates *TemplateEngines
Config *config.Iris
gzipWriterPool sync.Pool // used for several methods, usually inside context
sessions *sessionsManager
responses *responseEngines
templates *templateEngines
// fields which are useful to the user/dev
// the last added server is the main server
Servers *ServerList
Config *config.Iris
// configuration by instance.Logger.Config
Logger *logger.Logger
Plugins PluginContainer
Websocket websocket.Server
Websocket WebsocketServer
Available chan bool
// this is setted once when .Tester(t) is called
testFramework *httpexpect.Expect
@@ -188,7 +196,14 @@ func New(cfg ...config.Iris) *Framework {
// we always use 's' no 'f' because 's' is easier for me to remember because of 'station'
// some things never change :)
s := &Framework{Config: &c, Available: make(chan bool)}
s := &Framework{
Config: &c,
gzipWriterPool: sync.Pool{New: func() interface{} {
return &gzip.Writer{}
}},
responses: &responseEngines{},
Available: make(chan bool),
}
{
///NOTE: set all with s.Config pointer
// set the Logger
@@ -196,17 +211,17 @@ func New(cfg ...config.Iris) *Framework {
// set the plugin container
s.Plugins = &pluginContainer{logger: s.Logger}
// set the templates
s.templates = &TemplateEngines{
Helpers: map[string]interface{}{
s.templates = &templateEngines{
helpers: map[string]interface{}{
"url": s.URL,
"urlpath": s.Path,
},
Engines: make([]*TemplateEngineWrapper, 0),
engines: make([]*templateEngineWrapper, 0),
}
//set the session manager
s.sessions = newSessionsManager(c.Sessions)
// set the websocket server
s.Websocket = websocket.NewServer(s.Config.Websocket)
s.Websocket = NewWebsocketServer(s.Config.Websocket)
// set the servemux, which will provide us the public API also, with its context pool
mux := newServeMux(sync.Pool{New: func() interface{} { return &Context{framework: s} }}, s.Logger)
mux.onLookup = s.Plugins.DoPreLookup
@@ -220,22 +235,46 @@ func New(cfg ...config.Iris) *Framework {
}
func (s *Framework) initialize() {
// set the rest
s.rest = rest.New(s.Config.Rest)
// 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 templates if enabled
if !s.Config.DisableTemplateEngines {
if err := s.templates.LoadAll(); err != nil {
s.Logger.Panic(err) // panic on templates loading before listening if we have an error.
}
// check and prepare the templates
if len(s.templates.Engines) == 0 { // no template engine is registered, let's use the default
if len(s.templates.engines) == 0 { // no template engine is registered, let's use the default
s.UseTemplate(html.New())
}
s.templates.Reload = s.Config.IsDevelopment
if err := s.templates.loadAll(); err != nil {
s.Logger.Panic(err) // panic on templates loading before listening if we have an error.
}
s.templates.reload = s.Config.IsDevelopment
}
// listen to websocket connections
websocket.RegisterServer(s, s.Websocket, s.Logger)
RegisterWebsocketServer(s, s.Websocket, s.Logger)
// prepare the mux & the server
s.mux.setCorrectPath(!s.Config.DisablePathCorrection)
@@ -486,6 +525,40 @@ func (s *Framework) UseSessionDB(db SessionDatabase) {
s.sessions.provider.registerDatabase(db)
}
// UseResponse accepts a ResponseEngine and the key or content type on which the developer wants to register this response engine
// 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
//
// 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
// 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
func UseResponse(e ResponseEngine, forContentTypesOrKeys ...string) {
Default.UseResponse(e, forContentTypesOrKeys...)
}
// UseResponse accepts a ResponseEngine and the key or content type on which the developer wants to register this response engine
// 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
//
// 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
// 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
func (s *Framework) UseResponse(e ResponseEngine, forContentTypesOrKeys ...string) {
s.responses.add(e, forContentTypesOrKeys...)
}
// UseTemplate adds a template engine to the iris view system
// it does not build/load them yet
func UseTemplate(e TemplateEngine) *TemplateEngineLocation {
@@ -495,7 +568,7 @@ func UseTemplate(e TemplateEngine) *TemplateEngineLocation {
// UseTemplate adds a template engine to the iris view system
// it does not build/load them yet
func (s *Framework) UseTemplate(e TemplateEngine) *TemplateEngineLocation {
return s.templates.Add(e)
return s.templates.add(e)
}
// UseGlobal registers Handler middleware to the beginning, prepends them instead of append
@@ -716,6 +789,25 @@ func (s *Framework) URL(routeName string, args ...interface{}) (url string) {
return
}
// AcquireGzip prepares a gzip writer and returns it
//
// Note that: each iris station has its own pool
// see ReleaseGzip
func (s *Framework) AcquireGzip(w io.Writer) *gzip.Writer {
gzipWriter := s.gzipWriterPool.Get().(*gzip.Writer)
gzipWriter.Reset(w)
return gzipWriter
}
// ReleaseGzip called when flush/close and put the gzip writer back to the pool
//
// Note that: each iris station has its own pool
// see AcquireGzip
func (s *Framework) ReleaseGzip(gzipWriter *gzip.Writer) {
gzipWriter.Close()
s.gzipWriterPool.Put(gzipWriter)
}
// TemplateString executes a template from the default template engine and returns its result as string, useful when you want it for sending rich e-mails
// returns empty string on error
func TemplateString(templateFile string, pageContext interface{}, options ...map[string]interface{}) string {
@@ -728,7 +820,25 @@ func (s *Framework) TemplateString(templateFile string, pageContext interface{},
if s.Config.DisableTemplateEngines {
return ""
}
res, err := s.templates.GetBy(templateFile).ExecuteToString(templateFile, pageContext, options...)
res, err := s.templates.getBy(templateFile).executeToString(templateFile, pageContext, options...)
if err != nil {
return ""
}
return res
}
// ResponseString returns the string of a response engine,
// 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...)
}
// ResponseString returns the string of a response engine,
// 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...)
if err != nil {
return ""
}