Comments (21)
I was planning to use c.Render(code int, i interface{})
to select one of JSON, XML ... based on content negotiation and default to html. Somehow I not able to understand how interface would help here as I think these bind/render are just helper functions. If someone wants to use there own renderer or binder its just so simple to write one, although we should have most of them.
I also plan to do opposite in c.Bind, so you can directly bind from JSON, XML ... to boost speed by not looking into content-type.
from echo.
from echo.
@vishr I'm not sure auto content negotiation would be ideal.
I was sort of expecting Render to render based on the RendererFunc
(view engine). My above Render and RenderFunc could had been over-enginnered. RenderFunc would be more than enough.
c.Render(200, "person", &person{fname: "...", lname: ""})
RenderFunc can then read the template in view/person.html
and pass the person model. This would be the default Render.
Then anyone can go and override the RendererFunc
if they want to base on their needs.
import "github.com/unrolled/render"
r := render.New()
var e := echo.New()
e.RenderFunc = func(rw http.ResponseWriter, req *http.Request, statusCode int, name string, data interface{}) {
r.HTML(rw, statusCode, name, data)
}
e.Get("/", func(c *echo.Context) {
c.Render(200, "persons", &person{fname:"..", lname:".."})
})
from echo.
In the above example it looks like e.RenderFunc is global, wouldn't it be a problem if I want to mix and match different renders?
from echo.
e.RenderFunc
is per echo
instance - e
rather than global echo
.
This was sort of what I was thinking of.
e.RenderFunc = func(rw http.ResponseWriter, req *http.Request, statusCode int, name string, data interface{}) {
if strings.HasSuffix(name, ".md") {
r.Markdown(....)
} else {
r.HTML(....)
}
}
Here is how one could render.
e.Get("/", func (c *echo.Context) {
c.Render(200, "index", nil)
})
e.Get("/doc", func (e *echo.Context) {
c.Render(200, "doc.md", nil)
})
from echo.
RenderFunc will be be serving all kind of formats. Now I was thinking how do we identify JSON or XML in the RenderFunc.
from echo.
That is where the req *http.Request
parameter comes in. The RenderFunc
can look at the headers and do the negotiation. But I think this is a bad idea.
I was thinking that RenderFunc
should only render html style contents and not json, xml, protobuf. That should be a different api. Most likely NegotiateFunc
and c.Negotiate
The reason is the difference in api. Notice that render takes the name
while Negotiate doesn't. (Also I need to play more with the negotiate api to make it better)
c.Render(200, "doc.md", &model{})
c.Negotiate(200, &model{})
Some references:
gin-gonic/gin#59
gohttp/response#4
https://github.com/NancyFx/Nancy/wiki/Content-Negotiation
from echo.
Also if you want to mix Render
and Negotiate
I think NancyFx does it in an interesting way. This allows the devs to switch models based on the content negotiation. (Need to find an idiomatic way to do this in go)
Here is an example in c#.
Get["/"] = parameters => {
return Negotiate
.WithModel(new RatPack {FirstName = "Nancy "})
.WithMediaRangeModel("text/html", new RatPack {FirstName = "Nancy fancy pants"})
.WithView("negotiatedview")
.WithHeader("X-Custom", "SomeValue");
};
from echo.
Just thinking out loud: In c.Render(200, "doc.md", &model{})
or c.Render(200, "doc.html", &model{})
since we already know that its html or md, can't we just do c.Markdown()
or c.HTML()
without hitting the function?
from echo.
For c.HTML
I expect a html text something like <div>Prabir Shrestha</div>
.
c.HTML(200, `<div>Prabir Shrestha</div>`)
But for c.Render
I expect a template text something like <div>{{firstName}} {{lastName}}</div>
c.Render(200, `<div>{{firstName}} {{lastName}}</div>`, &Person{"Prabir", "Shrestha"})
And it is the responsibitliy of the RenderFunc
to convert the template and the model to html text that could be used by c.HTML()
.
Also I don't think having c.Markdown()
is good idea to put in the core fwk. Then next time someone comes up with a new spec they will want to put it in there. c.XFormat()
. I think echo
should provide a solid foundation to build on top off.
Let says someone decides to use handlebars instead of the default template and they already have a bunch of existing templates. That person would want to easily update the RenderFunc
to use a handlerbars for new one while using default templates for the existing ones. c.Render(200, "doc.hbs", nil)
or c.Render(200, "doc.html", nil)
. This gives the user flexibility. My above markdown example could had been a bad sample to begin with.
from echo.
So primarily this render function is for templates and html. Can you think of any other types? I think c.Render
implies any kind of data be it JSON, XML, HTML or any other type. Do you think we shoujld call it TemplateFunc
and c.Template
? Let me know your thoughts and we can discuss it further.
from echo.
Yes. It is only for templates and html.
Render is a pretty common terminology in the MVC/web world. So I think it suits better. c.Template
sounds awkward for me.
Samples for c.Render
- Expressjs uses
render
function. http://expressjs.com/4x/api.html#app.render - Ruby on Rails uses
render
http://guides.rubyonrails.org/layouts_and_rendering.html - Backbone http://backbonejs.org/#View-render
Samples for c.View
- HapiJS uses view. http://hapijs.com/tutorials/views
- NancyFx uses view. https://github.com/NancyFx/Nancy/wiki/View-engines#rendering-a-view-from-a-route-action
- ASP.NET mvc uses views. http://www.asp.net/mvc/overview/older-versions-1/views/asp-net-mvc-views-overview-cs
(Note: NancyFX and ASP.NET MVC returns the view from the function while HapiJS calls the view method.)
I would prefer either c.Render
or c.View
but not c.Template
because I would consider the .html, .hbs, .md as templates but the rendered template I would considered it as view. I would still prefer c.Render
over c.View
as it will read as render a view called index.html.
from echo.
Thanks for the detailed description and links. I will have a look at them and come up with an API to discuss further.
from echo.
@prabirshrestha This is what I have thought so far. What do you think?
type RenderFunc func(io.Writer, string, interface{}) error
// Default RenderFunc
Echo.renderFunc: func(w io.Writer, name string, data interface{}) (err error) {
// Implement golang template/html and write it to w.
return
}
// Or provide your own RenderFunc?
func (c *Context) Render(code int, name string, data interface{}) error {
c.Response.Header().Set(HeaderContentType, MIMEHTML+"; charset=utf-8")
c.Response.WriteHeader(code)
return c.echo.renderFunc(c.Response.ResponseWriter, name, data)
}
// API call
c.Render(200, "user.tmpl", &Users{"Joe"})
from echo.
Looks awesome.
Not related to this but would be awesome to have. Most likely a different issue. Since we now have a bunch of functions like HTML
, JSON
and render
returning error. It would be awesome to support func serveXYZ(w http.ResponseWriter, r *http.Request) error { ... }
in wraphH
.
Handler functions: We define our handlers with an error return value, and we use a simple wrapper function to make them implement http.Handler. This means we can centralize error handling instead of having to format error messages and pass them to the http.Error for each possible error. Our handler functions look like:
func serveXYZ(w http.ResponseWriter, r *http.Request) error { ... }
from echo.
RenderFunc
seems to be private in Echo
.
renderFunc RenderFunc
from echo.
There is a function to set custom RenderFunc now 12bd049
from echo.
@prabirshrestha I am planning to change RenderFunc to Renderer interface{} it's more idiomatic to Go.
type Renderer interface {
Render(io.Writer, string, interface{})
}
func (c *Context) Render(code int, name string, data interface{}) error {
c.Response.Header().Set(HeaderContentType, MIMEHTML+"; charset=utf-8")
c.Response.WriteHeader(code)
return c.echo.renderer.Render(c.Response.ResponseWriter, name, data)
}
// API call
c.Render(200, "user.tmpl", &Users{"Joe"})
from echo.
LGTM
from echo.
@vishr Seems like you removed the status code. Can we have it back? Useful when rendering errors.
func (c *Context) Render(name string, data interface{}) error {...}
Also if I pass status code 0 I think it shouldn't write the head. Same for other methods like JSON
that writes.
func (c *Context) Render(statusCode int, name string, data interface{}) error {
if c.echo.renderer == nil {
return ErrNoRenderer
}
if statusCode != 0 {
c.Response.Header().Set(HeaderContentType, MIMEHTML+"; charset=utf-8")
c.Response.WriteHeader(statusCode)
}
return c.echo.renderer.Render(c.Response, name, data)
}
from echo.
@prabirshrestha I have put it back - I completely missed on rendering errors. Verifying status code is nice but I then I think we should be doing it for all invalid codes - which is a lot of work, I believe, lets assume users are adults 😉
I looked into the URL you posted about handlers returning errors and I liked the idea. Now the default HandlerFunc returns error. I also added handlers which returns error to the list. 381fbae
from echo.
Related Issues (20)
- Not able to detect the route url without \ HOT 9
- CSRF TokenLookup HOT 1
- Add an AllowContentType middleware (based on chi)
- Bind() panics when the destination is a map with non-interface types HOT 1
- Add SSE function in Context.Response HOT 7
- Any software design issues HOT 1
- Request support for more routing path matching HOT 1
- Unable to use proxy middleware along with bodyDump middleware HOT 1
- `Host` header always blank HOT 6
- Does echo support i18n? [feature request] HOT 2
- Weirdness with wrapped handler and embed FS (static files) HOT 1
- Remove default charset from 'application/json' Content-Type header
- echo v4 websocket client closed, program exited HOT 3
- router not setting ContextKeyHeaderAllow for group, causing cors preflight to not work HOT 6
- Static file has wrong body returned when using a custom HTTP Error Handler and complex paths HOT 2
- QueryParams seem to override formValues HOT 3
- DefaultHTTPErrorHandler does not log HOT 3
- Support Casbin Authorization Middleware HOT 1
- Echo response object calls flush on unflushable objects HOT 7
- Feature request: support Yaml responses transparently. HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from echo.