diff --git a/context.go b/context.go index edaf7af7..4bf104c0 100644 --- a/context.go +++ b/context.go @@ -20,8 +20,9 @@ type ( ) // P returns path parameter by index. -func (c *Context) P(i int) (value string) { - if i <= len(c.pnames) { +func (c *Context) P(i uint8) (value string) { + l := uint8(len(c.pnames)) + if i <= l { value = c.pvalues[i] } return diff --git a/echo.go b/echo.go index f9e5258d..37be878d 100644 --- a/echo.go +++ b/echo.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "errors" + "fmt" "io" "log" "net/http" @@ -155,13 +156,14 @@ func (e *Echo) Group(pfx string, m ...Middleware) *Echo { return &g } -// MaxParam sets the maximum allowed path parameters. Default is 5, good enough -// for many users. +// MaxParam sets the maximum number of path parameters allowd for the application. +// Default value is 5, good enough for many use cases. func (e *Echo) MaxParam(n uint8) { e.maxParam = n } -// NotFoundHandler registers a custom NotFound handler. +// NotFoundHandler registers a custom NotFound handler used by router in case it +// doesn't find any registered handler for HTTP method and path. func (e *Echo) NotFoundHandler(h Handler) { e.notFoundHandler = wrapH(h) } @@ -235,7 +237,7 @@ func (e *Echo) Trace(path string, h Handler) { } // URI generates a URI from handler. -func (e *Echo) URI(h Handler, params ...string) string { +func (e *Echo) URI(h Handler, params ...interface{}) string { uri := new(bytes.Buffer) lp := len(params) n := 0 @@ -245,7 +247,7 @@ func (e *Echo) URI(h Handler, params ...string) string { if path[i] == ':' && n < lp { for ; i < l && path[i] != '/'; i++ { } - uri.WriteString(params[n]) + uri.WriteString(fmt.Sprintf("%v", params[n])) n++ } if i < l { @@ -257,7 +259,7 @@ func (e *Echo) URI(h Handler, params ...string) string { } // URL is an alias for URI -func (e *Echo) URL(h Handler, params ...string) string { +func (e *Echo) URL(h Handler, params ...interface{}) string { return e.URI(h, params...) } diff --git a/website/docs/guide.md b/website/docs/guide.md index bc9d517e..53510595 100644 --- a/website/docs/guide.md +++ b/website/docs/guide.md @@ -1,6 +1,6 @@ # Guide - @@ -25,22 +25,143 @@ $ go get -u github.com/labstack/echo Echo follows [Semantic Versioning](http://semver.org) managed through GitHub releases. Specific version of Echo can be installed using any [package manager](https://github.com/avelino/awesome-go#package-management). -## Configuration +## Customization -echo.MaxParam +### Max path parameters -echo.NotFoundHandler +`echo.MaxParam(n uint8)` -echo.HTTPErrorHandler +Sets the maximum number of path parameters allowed for the application. +Default value is **5**, [good enough](https://github.com/interagent/http-api-design#minimize-path-nesting) +for many use cases. Restricting path parameters allows us to use memory efficiently. + +### Not found handler + +`echo.NotFoundHandler(h Handler)` + +Registers a custom NotFound handler used by +router in case it doesn't find any registered handler for HTTP method and path. + +Default handler sends 404 "Not Found" response. + +### HTTP error handler + +`echo.HTTPErrorHandler(h HTTPErrorHandler)` + +Registers a centralized HTTP error handler. + +Default http error handler sends 500 "Internal Server Error" response. ## Routing -## Request +Echo's router is [fast, optimized](https://github.com/labstack/echo#benchmark) and +flexible. It's based on [redix tree](http://en.wikipedia.org/wiki/Radix_tree) +data structure which makes routing lookup really fast. It leverages +[sync pool](https://golang.org/pkg/sync/#Pool) to reuse memory and achieve +zero dynamic memory allocation with no garbage collection. -## Middleware +Routes can be registered for any HTTP method, path and handler. For example, code +below registers a route for method `GET`, path `/hello` and a handler which sends +`Hello!` response. -## Response +```go +echo.Get("/hello", func(*echo.Context) { + c.String(http.StatusOK, "Hello!") +}) +``` + + + +### Path parameters + +URL path parameters can be extracted either by name `echo.Context.Param(name string) string` or by +index `echo.Context.P(i uint8) string`. Getting parameter by index gives a slightly +better performance. + +```go +echo.Get("/users/:id", func(c *echo.Context) { + // By name + id := c.Param("id") + + // By index + id := c.P(0) + + c.String(http.StatusOK, id) +}) +``` + +### Match any + +Matches zero or more characters in the path. For example, pattern `/users/*` will +match + +- `/users/` +- `/users/1` +- `/users/1/files/1` +- `/users/anything...` + + + +### Path matching order + +- Static +- Param +- Match any + + + +### URI building + +`echo.URI` can be used generate URI for any handler with specified path parameters. +It's helpful to centralize all your URI patterns which ease in refactoring your +application. + +`echo.URI(h, 1)` will generate `/users/1` for the route registered below + +```go +// Handler +h := func(*echo.Context) { + c.String(http.StatusOK, "OK") +} + +// Route +e.Get("/users/:id", h) +``` + + + + + + ## Static Content -## Error Handling +### Static files + +`echo.Static(path, root string)` can be used to serve static files. For example, +code below serves all files from `public/scripts` directory for any path starting +with `/scripts/`. + +```go +e.Static("/scripts", "public/scripts") +``` + +### Serving a file + +`echo.ServeFile(path, file string)` can be used to serve a file. For example, code +below serves welcome.html for path `/welcome`. + +```go +e.ServeFile("/welcome", "welcome.html") +``` + +### Serving an index file + +`echo.Index(file string)` can be used to serve index file. For example, code below +serves index.html for path `/`. + +```go +e.Index("index.html") +``` + +