2015-04-24 15:13:06 -07:00
|
|
|
# Guide
|
|
|
|
|
2015-04-28 18:53:57 -07:00
|
|
|
<!---
|
2015-04-25 12:46:27 -07:00
|
|
|
Some info about guide
|
|
|
|
-->
|
|
|
|
|
2015-04-24 15:13:06 -07:00
|
|
|
---
|
|
|
|
|
|
|
|
## Installation
|
|
|
|
|
2015-04-25 12:46:27 -07:00
|
|
|
Echo has been developed and tested using Go `1.4.x`
|
|
|
|
|
2015-04-25 22:32:20 -07:00
|
|
|
Install the latest version of Echo via `go get`
|
2015-04-25 12:46:27 -07:00
|
|
|
|
|
|
|
```sh
|
|
|
|
$ go get github.com/labstack/echo
|
|
|
|
```
|
|
|
|
|
|
|
|
To upgrade
|
2015-04-24 15:13:06 -07:00
|
|
|
|
2015-04-25 12:46:27 -07:00
|
|
|
```sh
|
|
|
|
$ go get -u github.com/labstack/echo
|
|
|
|
```
|
2015-04-24 15:13:06 -07:00
|
|
|
|
2015-05-06 18:49:40 -07:00
|
|
|
Echo follows [semantic versioning](http://semver.org) managed through GitHub releases.
|
2015-07-08 13:51:08 -07:00
|
|
|
Specific version of Echo can be installed using a [package manager](https://github.com/avelino/awesome-go#package-management).
|
2015-04-24 15:13:06 -07:00
|
|
|
|
2015-04-28 18:53:57 -07:00
|
|
|
## Customization
|
2015-04-25 12:46:27 -07:00
|
|
|
|
2015-04-28 18:53:57 -07:00
|
|
|
### HTTP error handler
|
|
|
|
|
2015-05-19 18:54:31 -07:00
|
|
|
`Echo.SetHTTPErrorHandler(h HTTPErrorHandler)`
|
2015-04-28 18:53:57 -07:00
|
|
|
|
2015-05-19 18:54:31 -07:00
|
|
|
Registers a custom `Echo.HTTPErrorHandler`.
|
2015-05-06 15:51:52 -07:00
|
|
|
|
2015-05-20 15:59:36 -07:00
|
|
|
Default handler rules
|
2015-05-06 15:51:52 -07:00
|
|
|
|
2015-05-20 15:59:36 -07:00
|
|
|
- If error is of type `Echo.HTTPError` it sends HTTP response with status code `HTTPError.Code`
|
|
|
|
and message `HTTPError.Message`.
|
|
|
|
- Else it sends `500 - Internal Server Error`.
|
|
|
|
- If debug mode is enabled, it uses `error.Error()` as status message.
|
2015-05-19 18:54:31 -07:00
|
|
|
|
|
|
|
### Debug
|
|
|
|
|
2015-05-20 15:59:36 -07:00
|
|
|
`Echo.SetDebug(on bool)`
|
2015-05-19 18:54:31 -07:00
|
|
|
|
|
|
|
Enables debug mode.
|
2015-04-24 15:13:06 -07:00
|
|
|
|
2015-07-17 23:00:19 -07:00
|
|
|
### Enable/Disable colored log
|
2015-07-16 23:03:45 -07:00
|
|
|
|
2015-07-17 23:00:19 -07:00
|
|
|
`Echo.ColoredLog(on bool)`
|
2015-07-16 23:03:45 -07:00
|
|
|
|
2015-04-24 15:13:06 -07:00
|
|
|
## Routing
|
|
|
|
|
2015-04-28 18:53:57 -07:00
|
|
|
Echo's router is [fast, optimized](https://github.com/labstack/echo#benchmark) and
|
2015-07-08 13:51:08 -07:00
|
|
|
flexible. It's based on [radix tree](http://en.wikipedia.org/wiki/Radix_tree) data
|
|
|
|
structure which makes route lookup really fast. Router leverages [sync pool](https://golang.org/pkg/sync/#Pool)
|
|
|
|
to reuse memory and achieve zero dynamic memory allocation with no GC overhead.
|
2015-04-28 18:53:57 -07:00
|
|
|
|
2015-05-10 19:24:35 -07:00
|
|
|
Routes can be registered by specifying HTTP method, path and a handler. For example,
|
|
|
|
code below registers a route for method `GET`, path `/hello` and a handler which sends
|
2015-05-06 15:51:52 -07:00
|
|
|
`Hello!` HTTP response.
|
2015-04-28 18:53:57 -07:00
|
|
|
|
|
|
|
```go
|
2015-07-19 10:32:30 -07:00
|
|
|
e.Get("/hello", func(c *echo.Context) error {
|
2015-05-05 22:06:02 -07:00
|
|
|
return c.String(http.StatusOK, "Hello!")
|
2015-04-28 18:53:57 -07:00
|
|
|
})
|
|
|
|
```
|
|
|
|
|
2015-07-08 13:51:08 -07:00
|
|
|
Echo's default handler is `func(*echo.Context) error` where `echo.Context` primarily
|
|
|
|
holds HTTP request and response objects. Echo also has a support for other types
|
|
|
|
of handlers.
|
2015-04-28 18:53:57 -07:00
|
|
|
|
2015-04-28 23:09:30 -07:00
|
|
|
### Match-any
|
2015-04-28 18:53:57 -07:00
|
|
|
|
|
|
|
Matches zero or more characters in the path. For example, pattern `/users/*` will
|
2015-07-08 13:51:08 -07:00
|
|
|
match:
|
2015-04-28 18:53:57 -07:00
|
|
|
|
|
|
|
- `/users/`
|
|
|
|
- `/users/1`
|
|
|
|
- `/users/1/files/1`
|
|
|
|
- `/users/anything...`
|
|
|
|
|
|
|
|
### Path matching order
|
2015-04-25 12:46:27 -07:00
|
|
|
|
2015-04-28 18:53:57 -07:00
|
|
|
- Static
|
|
|
|
- Param
|
|
|
|
- Match any
|
|
|
|
|
2015-04-28 23:09:30 -07:00
|
|
|
#### Example
|
|
|
|
|
|
|
|
```go
|
2015-05-20 15:59:36 -07:00
|
|
|
e.Get("/users/:id", func(c *echo.Context) error {
|
2015-05-05 22:06:02 -07:00
|
|
|
return c.String(http.StatusOK, "/users/:id")
|
2015-04-28 23:09:30 -07:00
|
|
|
})
|
|
|
|
|
2015-05-20 15:59:36 -07:00
|
|
|
e.Get("/users/new", func(c *echo.Context) error {
|
2015-05-05 22:06:02 -07:00
|
|
|
return c.String(http.StatusOK, "/users/new")
|
2015-04-28 23:09:30 -07:00
|
|
|
})
|
|
|
|
|
2015-05-20 15:59:36 -07:00
|
|
|
e.Get("/users/1/files/*", func(c *echo.Context) error {
|
2015-05-05 22:06:02 -07:00
|
|
|
return c.String(http.StatusOK, "/users/1/files/*")
|
2015-04-28 23:09:30 -07:00
|
|
|
})
|
|
|
|
```
|
|
|
|
|
2015-07-08 13:51:08 -07:00
|
|
|
Above routes would resolve in the following order:
|
2015-04-28 23:09:30 -07:00
|
|
|
|
|
|
|
- `/users/new`
|
|
|
|
- `/users/:id`
|
|
|
|
- `/users/1/files/*`
|
|
|
|
|
2015-07-08 13:51:08 -07:00
|
|
|
> Routes can be written in any order.
|
2015-04-28 23:09:30 -07:00
|
|
|
|
2015-06-14 17:15:45 -07:00
|
|
|
### Group
|
|
|
|
|
|
|
|
`Echo.Group(prefix string, m ...Middleware) *Group`
|
|
|
|
|
|
|
|
Routes with common prefix can be grouped to define a new sub-router with optional
|
|
|
|
middleware. If middleware is passed to the function, it overrides parent middleware
|
|
|
|
- helpful if you want a completely new middleware stack for the group. To add middleware
|
|
|
|
later you can use `Group.Use(m ...Middleware)`. Groups can also be nested.
|
|
|
|
|
|
|
|
In the code below, we create an admin group which requires basic HTTP authentication
|
|
|
|
for routes `/admin/*`.
|
|
|
|
|
|
|
|
```go
|
|
|
|
echo.Group("/admin")
|
|
|
|
e.Use(mw.BasicAuth(func(usr, pwd string) bool {
|
|
|
|
if usr == "joe" && pwd == "secret" {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}))
|
|
|
|
```
|
2015-04-28 18:53:57 -07:00
|
|
|
|
|
|
|
### URI building
|
|
|
|
|
2015-05-21 15:24:08 -07:00
|
|
|
`Echo.URI` can be used generate URI for any handler with specified path parameters.
|
2015-04-28 18:53:57 -07:00
|
|
|
It's helpful to centralize all your URI patterns which ease in refactoring your
|
|
|
|
application.
|
|
|
|
|
2015-07-19 10:32:30 -07:00
|
|
|
`e.URI(h, 1)` will generate `/users/1` for the route registered below
|
2015-04-28 18:53:57 -07:00
|
|
|
|
|
|
|
```go
|
|
|
|
// Handler
|
2015-07-19 10:32:30 -07:00
|
|
|
h := func(c *echo.Context) error {
|
2015-05-05 22:06:02 -07:00
|
|
|
return c.String(http.StatusOK, "OK")
|
2015-04-28 18:53:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Route
|
|
|
|
e.Get("/users/:id", h)
|
|
|
|
```
|
|
|
|
|
2015-05-15 12:29:14 -07:00
|
|
|
## Middleware
|
2015-05-14 16:29:26 -07:00
|
|
|
|
2015-07-08 13:51:08 -07:00
|
|
|
Middleware is a function which is chained in the HTTP request-response cycle. Middleware
|
2015-06-07 19:57:49 -07:00
|
|
|
has access to the request and response objects which it utilizes to perform a specific
|
2015-07-08 13:51:08 -07:00
|
|
|
action, for example, logging every request.
|
2015-06-07 19:57:49 -07:00
|
|
|
|
|
|
|
### Logger
|
|
|
|
|
|
|
|
Logs each HTTP request with method, path, status, response time and bytes served.
|
|
|
|
|
|
|
|
*Example*
|
|
|
|
|
|
|
|
```go
|
|
|
|
e.Use(Logger())
|
|
|
|
|
|
|
|
// Output: `2015/06/07 18:16:16 GET / 200 13.238µs 14`
|
|
|
|
```
|
|
|
|
|
|
|
|
### BasicAuth
|
|
|
|
|
|
|
|
BasicAuth middleware provides an HTTP basic authentication.
|
|
|
|
|
|
|
|
- For valid credentials it calls the next handler in the chain.
|
|
|
|
- For invalid Authorization header it sends "404 - Bad Request" response.
|
|
|
|
- For invalid credentials, it sends "401 - Unauthorized" response.
|
|
|
|
|
|
|
|
*Example*
|
|
|
|
|
|
|
|
```go
|
2015-07-19 10:32:30 -07:00
|
|
|
e.Group("/admin")
|
2015-06-07 19:57:49 -07:00
|
|
|
e.Use(mw.BasicAuth(func(usr, pwd string) bool {
|
|
|
|
if usr == "joe" && pwd == "secret" {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}))
|
|
|
|
```
|
|
|
|
|
|
|
|
### Gzip
|
|
|
|
|
|
|
|
Gzip middleware compresses HTTP response using gzip compression scheme.
|
|
|
|
|
|
|
|
*Example*
|
|
|
|
|
|
|
|
```go
|
|
|
|
e.Use(mw.Gzip())
|
|
|
|
```
|
|
|
|
|
|
|
|
### Recover
|
|
|
|
|
|
|
|
Recover middleware recovers from panics anywhere in the chain and handles the control
|
|
|
|
to the centralized [HTTPErrorHandler](#error-handling).
|
|
|
|
|
|
|
|
*Example*
|
|
|
|
|
|
|
|
```go
|
|
|
|
e.Use(mw.Recover())
|
|
|
|
```
|
|
|
|
|
|
|
|
### StripTrailingSlash
|
|
|
|
|
|
|
|
StripTrailingSlash middleware removes the trailing slash from request path.
|
|
|
|
|
|
|
|
*Example*
|
|
|
|
|
|
|
|
```go
|
|
|
|
e.Use(mw.StripTrailingSlash())
|
|
|
|
```
|
|
|
|
|
|
|
|
### RedirectToSlash
|
|
|
|
RedirectToSlash middleware redirects requests without trailing slash path to trailing
|
|
|
|
slash path.
|
|
|
|
|
|
|
|
*Options*
|
|
|
|
```go
|
|
|
|
RedirectToSlashOptions struct {
|
|
|
|
Code int
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
*Example*
|
|
|
|
|
|
|
|
```go
|
|
|
|
e.Use(mw.RedirectToSlash())
|
|
|
|
```
|
|
|
|
|
2015-06-09 09:16:52 -07:00
|
|
|
> StripTrailingSlash and RedirectToSlash middleware should not be used together.
|
2015-06-07 19:57:49 -07:00
|
|
|
|
|
|
|
[Examples](https://github.com/labstack/echo/tree/master/examples/middleware)
|
2015-04-28 18:53:57 -07:00
|
|
|
|
2015-07-08 13:51:08 -07:00
|
|
|
## Request
|
|
|
|
|
|
|
|
### Path parameter
|
|
|
|
|
2015-07-19 10:32:30 -07:00
|
|
|
Path parameter can be retrieved either by name `Context.Param(name string) string`
|
|
|
|
or by index `Context.P(i int) string`. Getting parameter by index gives a slightly
|
2015-07-08 13:51:08 -07:00
|
|
|
better performance.
|
|
|
|
|
|
|
|
*Example*
|
|
|
|
|
|
|
|
```go
|
2015-07-19 10:32:30 -07:00
|
|
|
e.Get("/users/:name", func(c *echo.Context) error {
|
2015-07-08 13:51:08 -07:00
|
|
|
// By name
|
|
|
|
name := c.Param("name")
|
|
|
|
|
|
|
|
// By index
|
|
|
|
name := c.P(0)
|
|
|
|
|
|
|
|
return c.String(http.StatusOK, name)
|
|
|
|
})
|
|
|
|
```
|
|
|
|
|
|
|
|
```sh
|
|
|
|
$ curl http://localhost:1323/users/joe
|
|
|
|
```
|
|
|
|
|
|
|
|
### Query parameter
|
|
|
|
|
2015-07-19 10:32:30 -07:00
|
|
|
Query parameter can be retrieved by name using `Context.Query(name string)`.
|
2015-07-08 13:51:08 -07:00
|
|
|
|
|
|
|
*Example*
|
|
|
|
|
|
|
|
```go
|
2015-07-19 10:32:30 -07:00
|
|
|
e.Get("/users", func(c *echo.Context) error {
|
2015-07-08 13:51:08 -07:00
|
|
|
name := c.Query("name")
|
|
|
|
return c.String(http.StatusOK, name)
|
|
|
|
})
|
|
|
|
```
|
|
|
|
|
|
|
|
```sh
|
|
|
|
$ curl -G -d "name=joe" http://localhost:1323/users
|
|
|
|
```
|
|
|
|
|
|
|
|
### Form parameter
|
|
|
|
|
2015-07-19 10:32:30 -07:00
|
|
|
Form parameter can be retrieved by name using `Context.Form(name string)`.
|
2015-07-08 13:51:08 -07:00
|
|
|
|
|
|
|
*Example*
|
|
|
|
|
|
|
|
```go
|
2015-07-19 10:32:30 -07:00
|
|
|
e.Post("/users", func(c *echo.Context) error {
|
2015-07-08 13:51:08 -07:00
|
|
|
name := c.Form("name")
|
|
|
|
return c.String(http.StatusOK, name)
|
|
|
|
})
|
|
|
|
```
|
|
|
|
|
|
|
|
```sh
|
|
|
|
$ curl -d "name=joe" http://localhost:1323/users
|
|
|
|
```
|
|
|
|
|
2015-04-28 23:09:30 -07:00
|
|
|
## Response
|
|
|
|
|
2015-07-16 23:03:45 -07:00
|
|
|
### Template
|
|
|
|
|
|
|
|
```go
|
|
|
|
Context.Render(code int, name string, data interface{}) error
|
|
|
|
```
|
|
|
|
Renders a template with data and sends a text/html response with status code. Templates
|
|
|
|
can be registered using `Echo.SetRenderer()`, allowing us to use any templating engine.
|
|
|
|
Below is an example using Go `html/template`
|
|
|
|
|
|
|
|
Implement `echo.Render`
|
|
|
|
|
|
|
|
```go
|
|
|
|
Template struct {
|
|
|
|
templates *template.Template
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *Template) Render(w io.Writer, name string, data interface{}) error {
|
|
|
|
return t.templates.ExecuteTemplate(w, name, data)
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Pre-compile templates
|
|
|
|
|
|
|
|
```go
|
|
|
|
t := &Template{
|
|
|
|
templates: template.Must(template.ParseGlob("public/views/*.html")),
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Register templates
|
|
|
|
|
|
|
|
```go
|
|
|
|
e := echo.New()
|
|
|
|
e.SetRenderer(t)
|
|
|
|
e.Get("/hello", Hello)
|
|
|
|
```
|
|
|
|
|
|
|
|
Template `public/views/hello.html`
|
|
|
|
|
|
|
|
```html
|
|
|
|
{{define "hello"}}Hello, {{.}}!{{end}}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
Handler
|
|
|
|
|
|
|
|
```go
|
|
|
|
func Hello(c *echo.Context) error {
|
|
|
|
return c.Render(http.StatusOK, "hello", "World")
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2015-04-28 23:09:30 -07:00
|
|
|
### JSON
|
2015-04-25 12:46:27 -07:00
|
|
|
|
2015-05-04 14:00:07 -07:00
|
|
|
```go
|
2015-07-16 23:03:45 -07:00
|
|
|
Context.JSON(code int, v interface{}) error
|
2015-05-04 14:00:07 -07:00
|
|
|
```
|
|
|
|
|
2015-05-06 15:51:52 -07:00
|
|
|
Sends a JSON HTTP response with status code.
|
2015-04-28 23:09:30 -07:00
|
|
|
|
2015-07-16 23:03:45 -07:00
|
|
|
### XML
|
2015-04-28 23:09:30 -07:00
|
|
|
|
2015-05-04 14:00:07 -07:00
|
|
|
```go
|
2015-07-16 23:03:45 -07:00
|
|
|
Context.XML(code int, v interface{}) error
|
2015-05-04 14:00:07 -07:00
|
|
|
```
|
|
|
|
|
2015-07-16 23:03:45 -07:00
|
|
|
Sends an XML HTTP response with status code.
|
2015-04-28 23:09:30 -07:00
|
|
|
|
|
|
|
### HTML
|
|
|
|
|
2015-05-04 14:00:07 -07:00
|
|
|
```go
|
2015-07-16 23:03:45 -07:00
|
|
|
Context.HTML(code int, html string) error
|
2015-05-04 14:00:07 -07:00
|
|
|
```
|
|
|
|
|
2015-05-06 15:51:52 -07:00
|
|
|
Sends an HTML HTTP response with status code.
|
2015-04-25 12:46:27 -07:00
|
|
|
|
2015-07-16 23:03:45 -07:00
|
|
|
### String
|
|
|
|
|
|
|
|
```go
|
|
|
|
Context.String(code int, s string) error
|
|
|
|
```
|
|
|
|
|
|
|
|
Sends a text/plain HTTP response with status code.
|
|
|
|
|
2015-04-28 18:53:57 -07:00
|
|
|
### Static files
|
|
|
|
|
2015-05-21 15:24:08 -07:00
|
|
|
`Echo.Static(path, root string)` serves static files. For example, code below serves
|
2015-05-13 23:07:03 -07:00
|
|
|
files from directory `public/scripts` for any request path starting with `/scripts/`.
|
2015-04-28 18:53:57 -07:00
|
|
|
|
|
|
|
```go
|
2015-05-13 15:49:09 -07:00
|
|
|
e.Static("/scripts/", "public/scripts")
|
2015-04-28 18:53:57 -07:00
|
|
|
```
|
|
|
|
|
|
|
|
### Serving a file
|
|
|
|
|
2015-05-21 15:24:08 -07:00
|
|
|
`Echo.ServeFile(path, file string)` serves a file. For example, code below serves
|
2015-05-13 23:07:03 -07:00
|
|
|
file `welcome.html` for request path `/welcome`.
|
2015-04-28 18:53:57 -07:00
|
|
|
|
|
|
|
```go
|
|
|
|
e.ServeFile("/welcome", "welcome.html")
|
|
|
|
```
|
|
|
|
|
|
|
|
### Serving an index file
|
|
|
|
|
2015-05-21 15:24:08 -07:00
|
|
|
`Echo.Index(file string)` serves root index page - `GET /`. For example, code below
|
2015-05-13 23:07:03 -07:00
|
|
|
serves root index page from file `public/index.html`.
|
2015-04-28 18:53:57 -07:00
|
|
|
|
|
|
|
```go
|
2015-05-13 23:07:03 -07:00
|
|
|
e.Index("public/index.html")
|
2015-04-28 18:53:57 -07:00
|
|
|
```
|
|
|
|
|
2015-05-21 15:24:08 -07:00
|
|
|
### Serving favicon
|
2015-05-13 15:49:09 -07:00
|
|
|
|
2015-05-21 15:24:08 -07:00
|
|
|
`Echo.Favicon(file string)` serves default favicon - `GET /favicon.ico`. For example,
|
2015-05-13 23:07:03 -07:00
|
|
|
code below serves favicon from file `public/favicon.ico`.
|
2015-05-13 15:49:09 -07:00
|
|
|
|
|
|
|
```go
|
2015-05-14 08:23:14 -07:00
|
|
|
e.Favicon("public/favicon.ico")
|
2015-05-13 15:49:09 -07:00
|
|
|
```
|
|
|
|
|
2015-05-06 15:51:52 -07:00
|
|
|
## Error Handling
|
|
|
|
|
2015-05-20 15:59:36 -07:00
|
|
|
Echo advocates centralized HTTP error handling by returning `error` from middleware
|
|
|
|
and handlers.
|
2015-05-06 15:51:52 -07:00
|
|
|
|
2015-05-06 18:47:26 -07:00
|
|
|
It allows you to
|
2015-05-06 18:42:45 -07:00
|
|
|
|
|
|
|
- Debug by writing stack trace to the HTTP response.
|
|
|
|
- Customize HTTP responses.
|
2015-05-06 15:51:52 -07:00
|
|
|
- Recover from panics inside middleware or handlers.
|
|
|
|
|
2015-05-21 15:24:08 -07:00
|
|
|
For example, when basic auth middleware finds invalid credentials it returns
|
2015-05-20 15:59:36 -07:00
|
|
|
`401 - Unauthorized` error, aborting the current HTTP request.
|
2015-05-06 15:51:52 -07:00
|
|
|
|
|
|
|
```go
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net/http"
|
|
|
|
|
|
|
|
"github.com/labstack/echo"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
e := echo.New()
|
2015-05-20 15:59:36 -07:00
|
|
|
e.Use(func(c *echo.Context) error {
|
2015-05-06 15:51:52 -07:00
|
|
|
// Extract the credentials from HTTP request header and perform a security
|
|
|
|
// check
|
|
|
|
|
|
|
|
// For invalid credentials
|
2015-05-20 15:59:36 -07:00
|
|
|
return echo.NewHTTPError(http.StatusUnauthorized)
|
2015-05-06 15:51:52 -07:00
|
|
|
})
|
|
|
|
e.Get("/welcome", welcome)
|
2015-05-10 08:22:49 -07:00
|
|
|
e.Run(":1323")
|
2015-05-06 15:51:52 -07:00
|
|
|
}
|
|
|
|
|
2015-05-20 15:59:36 -07:00
|
|
|
func welcome(c *echo.Context) error {
|
2015-05-06 15:51:52 -07:00
|
|
|
return c.String(http.StatusOK, "Welcome!")
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2015-05-06 16:11:21 -07:00
|
|
|
See how [HTTPErrorHandler](#customization) handles it.
|
2015-04-28 23:09:30 -07:00
|
|
|
|