add content type and response text to the Controller 💯

Former-commit-id: 99cde0a445027b10839155501a7918732a783af3
This commit is contained in:
hiveminded 2017-09-02 14:32:14 +03:00
parent fe94840929
commit d7ec0d4416
6 changed files with 107 additions and 73 deletions

View File

@ -16,9 +16,9 @@ func main() {
app.Use(logger.New())
// Method: GET
// Resource: http://localhost:8080/
// Resource: http://localhost:8080
app.Handle("GET", "/", func(ctx iris.Context) {
ctx.HTML("<b>Welcome!</b>")
ctx.HTML("<h1>Welcome</h1>")
})
// same as app.Handle("GET", "/ping", [...])
@ -31,7 +31,7 @@ func main() {
// Method: GET
// Resource: http://localhost:8080/hello
app.Get("/hello", func(ctx iris.Context) {
ctx.JSON(iris.Map{"message": "Hello iris web framework."})
ctx.JSON(iris.Map{"message": "Hello Iris!"})
})
// http://localhost:8080

View File

@ -35,9 +35,7 @@ func main() {
app.Use(recover.New())
app.Use(logger.New())
app.Controller("/", new(IndexController))
app.Controller("/ping", new(PingController))
app.Controller("/hello", new(HelloController))
app.Controller("/", new(ExampleController))
// http://localhost:8080
// http://localhost:8080/ping
@ -45,63 +43,50 @@ func main() {
app.Run(iris.Addr(":8080"))
}
// IndexController serves the "/".
type IndexController struct {
// ExampleController serves the "/", "/ping" and "/hello".
type ExampleController struct {
// if you build with go1.8 you have to use the mvc package, `mvc.Controller` instead.
iris.Controller
}
// Get serves
// Method: GET
// Resource: http://localhost:8080/
func (c *IndexController) Get() {
c.Ctx.HTML("<b>Welcome!</b>")
// Resource: http://localhost:8080
func (c *ExampleController) Get() {
c.ContentType = "text/html"
c.Text = "<h1>Welcome!</h1>"
}
// PingController serves the "/ping".
type PingController struct {
iris.Controller
}
// Get serves
// GetPing serves
// Method: GET
// Resource: http://localhost:8080/ping
func (c *PingController) Get() {
c.Ctx.WriteString("pong")
func (c *ExampleController) GetPing() {
c.Text = "pong"
}
// HelloController serves the "/hello".
type HelloController struct {
iris.Controller
}
type myJSONData struct {
Message string `json:"message"`
}
// Get serves
// GetHello serves
// Method: GET
// Resource: http://localhost:8080/hello
func (c *HelloController) Get() {
c.Ctx.JSON(myJSONData{"Hello iris web framework."})
func (c *ExampleController) GetHello() {
c.Ctx.JSON(iris.Map{"message": "Hello Iris!"})
}
/* Can use more than one, the factory will make sure
that the correct http methods are being registered for each route
for this controller, uncomment these if you want:
func (c *HelloController) Post() {}
func (c *HelloController) Put() {}
func (c *HelloController) Delete() {}
func (c *HelloController) Connect() {}
func (c *HelloController) Head() {}
func (c *HelloController) Patch() {}
func (c *HelloController) Options() {}
func (c *HelloController) Trace() {}
func (c *ExampleController) Post() {}
func (c *ExampleController) Put() {}
func (c *ExampleController) Delete() {}
func (c *ExampleController) Connect() {}
func (c *ExampleController) Head() {}
func (c *ExampleController) Patch() {}
func (c *ExampleController) Options() {}
func (c *ExampleController) Trace() {}
*/
/*
func (c *HelloController) All() {}
func (c *ExampleController) All() {}
// OR
func (c *HelloController) Any() {}
func (c *ExampleController) Any() {}
*/

View File

@ -1366,12 +1366,21 @@ func (ctx *context) FormFile(key string) (multipart.File, *multipart.FileHeader,
func (ctx *context) Redirect(urlToRedirect string, statusHeader ...int) {
ctx.StopExecution()
httpStatus := http.StatusFound // a 'temporary-redirect-like' which works better than for our purpose
if len(statusHeader) > 0 && statusHeader[0] > 0 {
httpStatus = statusHeader[0]
// get the previous status code given by the end-developer.
status := ctx.GetStatusCode()
if len(statusHeader) > 0 {
// check if status code is passed via receivers.
if s := statusHeader[0]; s > 0 {
status = s
}
}
if status == 0 {
// if status remains zero then default it.
// a 'temporary-redirect-like' which works better than for our purpose
status = http.StatusFound
}
http.Redirect(ctx.writer, ctx.request, urlToRedirect, httpStatus)
http.Redirect(ctx.writer, ctx.request, urlToRedirect, status)
}
// +------------------------------------------------------------+

View File

@ -169,7 +169,7 @@ func testTheRoutes(t *testing.T, tests []testRoute, debug bool) {
if method == "" {
method = tt.method
}
ex := e.Request(tt.method, req.path)
ex := e.Request(method, req.path)
if req.subdomain != "" {
ex.WithURL("http://" + req.subdomain + ".localhost:8080")
}

30
doc.go
View File

@ -163,10 +163,10 @@ Example code:
Listening and gracefully shutdown
You can listen to a server using any type of net.Listener or http.Server instance.
You can start the server(s) listening to any type of `net.Listener` or even `http.Server` instance.
The method for initialization of the server should be passed at the end, via `Run` function.
Below you'll read some usage examples:
Below you'll see some useful examples:
// Listening on tcp with network address 0.0.0.0:8080
@ -190,13 +190,22 @@ Below you'll read some usage examples:
// Automatic TLS
app.Run(iris.AutoTLS("localhost:443"))
app.Run(iris.AutoTLS(":443", "example.com", "admin@example.com"))
// UNIX socket
l, err := netutil.UNIX("/tmpl/srv.sock", 0666)
if errOs := os.Remove(socketFile); errOs != nil && !os.IsNotExist(errOs) {
app.Logger().Fatal(errOs)
}
l, err := net.Listen("unix", socketFile)
if err != nil {
panic(err)
app.Logger().Fatal(err)
}
if err = os.Chmod(socketFile, mode); err != nil {
app.Logger().Fatal(err)
}
app.Run(iris.Listener(l))
@ -454,7 +463,7 @@ Example code:
app.Any("/", handler)
func handler(ctx iris.Context){
ctx.Writef("Hello from method: %s and path: %s", ctx.Method(), ctx.Path())
ctx.Writef("Hello from method: %s and path: %s", ctx.Method(), ctx.Path())
}
@ -471,15 +480,12 @@ A group can have a nested group too.
Example code:
users:= app.Party("/users", myAuthHandler)
users := app.Party("/users", myAuthMiddlewareHandler)
// http://myhost.com/users/42/profile
users.Get("/{userid:int}/profile", userProfileHandler)
users.Get("/{id:int}/profile", userProfileHandler)
// http://myhost.com/users/messages/1
users.Get("/inbox/{messageid:int}", userMessageHandler)
app.Run(iris.Addr("myhost.com:80"))
users.Get("/inbox/{id:int}", userMessageHandler)
Custom HTTP Errors

View File

@ -63,17 +63,18 @@ import (
// Look `core/router/APIBuilder#Controller` method too.
type Controller struct {
// Name contains the current controller's full name.
//
// doesn't change on different paths.
Name string
// currentRoute is the current request context's route.
currentRoute context.RouteReadOnly
// contains the `Name` as different words, all lowercase,
// without the "Controller" suffix if exists.
// we need this as field because the activator
// we will not try to parse these if not needed
// it's up to the end-developer to call `RelPath()` or `RelTmpl()`
// which will result to fill them.
//
// doesn't change on different paths.
nameAsWords []string
// relPath the "as assume" relative request path.
@ -81,10 +82,12 @@ type Controller struct {
// If UserController and request path is "/user/messages" then it's "/messages"
// if UserPostController and request path is "/user/post" then it's "/"
// if UserProfile and request path is "/user/profile/likes" then it's "/likes"
//
// doesn't change on different paths.
relPath string
// request path and its parameters, read-write.
// Path is the current request path.
// Path is the current request path, if changed then it redirects.
Path string
// Params are the request path's parameters, i.e
// for route like "/user/{id}" and request to "/user/42"
@ -101,13 +104,19 @@ type Controller struct {
// If UserController then it's "user/"
// if UserPostController then it's "user/post/"
// if UserProfile then it's "user/profile/".
//
// doesn't change on different paths.
relTmpl string
// view read and write,
// can be already set-ed by previous handlers as well.
Layout string
Tmpl string
Data map[string]interface{}
ContentType string
Text string // or Text
// give access to the request context itself.
Ctx context.Context
}
@ -127,10 +136,7 @@ func (c *Controller) getNameWords() []string {
// Route returns the current request controller's context read-only access route.
func (c *Controller) Route() context.RouteReadOnly {
if c.currentRoute == nil {
c.currentRoute = c.Ctx.GetCurrentRoute()
}
return c.currentRoute
return c.Ctx.GetCurrentRoute()
}
const slashStr = "/"
@ -208,6 +214,13 @@ func (c *Controller) RelTmpl() string {
return c.relTmpl
}
// Write writes to the client via the context's ResponseWriter.
// Controller completes the `io.Writer` interface for the shake of ease.
func (c *Controller) Write(contents []byte) (int, error) {
c.tryWriteHeaders()
return c.Ctx.ResponseWriter().Write(contents)
}
// BeginRequest starts the main controller
// it initialize the Ctx and other fields.
//
@ -221,12 +234,26 @@ func (c *Controller) BeginRequest(ctx context.Context) {
c.Status = ctx.GetStatusCode()
// share values
c.Values = ctx.Values()
// view
// view data for templates, remember
// each controller is a new instance, so
// checking for nil and then init those type of fields
// have no meaning.
c.Data = make(map[string]interface{}, 0)
// context itself
c.Ctx = ctx
}
func (c *Controller) tryWriteHeaders() {
if status := c.Status; status > 0 && status != c.Ctx.GetStatusCode() {
c.Ctx.StatusCode(status)
}
if contentType := c.ContentType; contentType != "" {
c.Ctx.ContentType(contentType)
}
}
// EndRequest is the final method which will be executed
// before response sent.
//
@ -236,25 +263,32 @@ func (c *Controller) BeginRequest(ctx context.Context) {
// It's called internally.
// End-Developer can ovveride it but still should be called at the end.
func (c *Controller) EndRequest(ctx context.Context) {
if path := c.Path; path != "" && path != ctx.Path() {
// then redirect
ctx.Redirect(path)
if ctx.ResponseWriter().Written() > 0 {
return
}
if status := c.Status; status > 0 && status != ctx.GetStatusCode() {
ctx.StatusCode(status)
if path := c.Path; path != "" && path != ctx.Path() {
// then redirect and exit.
ctx.Redirect(path, c.Status)
return
}
c.tryWriteHeaders()
if response := c.Text; response != "" {
ctx.WriteString(response)
return // exit here
}
if view := c.Tmpl; view != "" {
if layout := c.Layout; layout != "" {
ctx.ViewLayout(layout)
}
if data := c.Data; data != nil {
if data := c.Data; len(data) > 0 {
for k, v := range data {
ctx.ViewData(k, v)
}
}
ctx.View(view)
}
}