1
0
mirror of https://github.com/labstack/echo.git synced 2024-11-24 08:22:21 +02:00

more godoc

Signed-off-by: Vishal Rana <vr@labstack.com>
This commit is contained in:
Vishal Rana 2016-03-19 15:47:20 -07:00
parent d01e856db6
commit c4caeb8ffb
21 changed files with 372 additions and 189 deletions

View File

@ -22,40 +22,108 @@ import (
) )
type ( type (
// Context represents context for the current request. It holds request and // Context represents the context of the current HTTP request. It holds request and
// response objects, path parameters, data and registered handler. // response objects, path, path parameters, data and registered handler.
Context interface { Context interface {
netContext.Context netContext.Context
// NetContext returns `http://blog.golang.org/context.Context` interface.
NetContext() netContext.Context NetContext() netContext.Context
// SetNetContext sets `http://blog.golang.org/context.Context` interface.
SetNetContext(netContext.Context) SetNetContext(netContext.Context)
// Request returns `engine.Request` interface.
Request() engine.Request Request() engine.Request
// Request returns `engine.Response` interface.
Response() engine.Response Response() engine.Response
// Path returns the registered path for the handler.
Path() string Path() string
// P returns path parameter by index.
P(int) string P(int) string
// Param returns path parameter by name.
Param(string) string Param(string) string
// ParamNames returns path parameter names.
ParamNames() []string ParamNames() []string
// Query returns query parameter by name.
Query(string) string Query(string) string
// Form returns form parameter by name.
Form(string) string Form(string) string
// Get retrieves data from the context.
Get(string) interface{} Get(string) interface{}
// Set saves data in the context.
Set(string, interface{}) Set(string, interface{})
// Bind binds the request body into provided type `i`. The default binder does
// it based on Content-Type header.
Bind(interface{}) error Bind(interface{}) error
// Render renders a template with data and sends a text/html response with status
// code. Templates can be registered using `Echo.SetRenderer()`.
Render(int, string, interface{}) error Render(int, string, interface{}) error
// HTML sends an HTTP response with status code.
HTML(int, string) error HTML(int, string) error
// String sends a string response with status code.
String(int, string) error String(int, string) error
// JSON sends a JSON response with status code.
JSON(int, interface{}) error JSON(int, interface{}) error
// JSONBlob sends a JSON blob response with status code.
JSONBlob(int, []byte) error JSONBlob(int, []byte) error
// JSONP sends a JSONP response with status code. It uses `callback` to construct
// the JSONP payload.
JSONP(int, string, interface{}) error JSONP(int, string, interface{}) error
// XML sends an XML response with status code.
XML(int, interface{}) error XML(int, interface{}) error
// XMLBlob sends a XML blob response with status code.
XMLBlob(int, []byte) error XMLBlob(int, []byte) error
// File sends a response with the content of the file.
File(string) error File(string) error
// Attachment sends a response from `io.Reader` as attachment, prompting client
// to save the file.
Attachment(io.Reader, string) error Attachment(io.Reader, string) error
// NoContent sends a response with no body and a status code.
NoContent(int) error NoContent(int) error
// Redirect redirects the request with status code.
Redirect(int, string) error Redirect(int, string) error
// Error invokes the registered HTTP error handler. Generally used by middleware.
Error(err error) Error(err error)
// Handler implements `Handler` interface.
Handle(Context) error Handle(Context) error
// Logger returns the `Logger` instance.
Logger() *log.Logger Logger() *log.Logger
// Echo returns the `Echo` instance.
Echo() *Echo Echo() *Echo
// Object returns the `context` instance.
Object() *context Object() *context
// Reset resets the context after request completes. It must be called along
// with `Echo#GetContext()` and `Echo#PutContext()`. See `Echo#ServeHTTP()`
Reset(engine.Request, engine.Response)
} }
context struct { context struct {
@ -118,22 +186,18 @@ func (c *context) Handle(ctx Context) error {
return c.handler.Handle(ctx) return c.handler.Handle(ctx)
} }
// Request returns *http.Request.
func (c *context) Request() engine.Request { func (c *context) Request() engine.Request {
return c.request return c.request
} }
// Response returns `engine.Response`.
func (c *context) Response() engine.Response { func (c *context) Response() engine.Response {
return c.response return c.response
} }
// Path returns the registered path for the handler.
func (c *context) Path() string { func (c *context) Path() string {
return c.path return c.path
} }
// P returns path parameter by index.
func (c *context) P(i int) (value string) { func (c *context) P(i int) (value string) {
l := len(c.pnames) l := len(c.pnames)
if i < l { if i < l {
@ -142,7 +206,6 @@ func (c *context) P(i int) (value string) {
return return
} }
// Param returns path parameter by name.
func (c *context) Param(name string) (value string) { func (c *context) Param(name string) (value string) {
l := len(c.pnames) l := len(c.pnames)
for i, n := range c.pnames { for i, n := range c.pnames {
@ -154,22 +217,18 @@ func (c *context) Param(name string) (value string) {
return return
} }
// ParamNames returns path parameter names.
func (c *context) ParamNames() []string { func (c *context) ParamNames() []string {
return c.pnames return c.pnames
} }
// Query returns query parameter by name.
func (c *context) Query(name string) string { func (c *context) Query(name string) string {
return c.request.URL().QueryValue(name) return c.request.URL().QueryValue(name)
} }
// Form returns form parameter by name.
func (c *context) Form(name string) string { func (c *context) Form(name string) string {
return c.request.FormValue(name) return c.request.FormValue(name)
} }
// Set saves data in the context.
func (c *context) Set(key string, val interface{}) { func (c *context) Set(key string, val interface{}) {
if c.store == nil { if c.store == nil {
c.store = make(store) c.store = make(store)
@ -177,19 +236,14 @@ func (c *context) Set(key string, val interface{}) {
c.store[key] = val c.store[key] = val
} }
// Get retrieves data from the context.
func (c *context) Get(key string) interface{} { func (c *context) Get(key string) interface{} {
return c.store[key] return c.store[key]
} }
// Bind binds the request body into provided type `i`. The default binder does
// it based on Content-Type header.
func (c *context) Bind(i interface{}) error { func (c *context) Bind(i interface{}) error {
return c.echo.binder.Bind(i, c) return c.echo.binder.Bind(i, c)
} }
// Render renders a template with data and sends a text/html response with status
// code. Templates can be registered using `Echo.SetRenderer()`.
func (c *context) Render(code int, name string, data interface{}) (err error) { func (c *context) Render(code int, name string, data interface{}) (err error) {
if c.echo.renderer == nil { if c.echo.renderer == nil {
return ErrRendererNotRegistered return ErrRendererNotRegistered
@ -204,7 +258,6 @@ func (c *context) Render(code int, name string, data interface{}) (err error) {
return return
} }
// HTML sends an HTTP response with status code.
func (c *context) HTML(code int, html string) (err error) { func (c *context) HTML(code int, html string) (err error) {
c.response.Header().Set(ContentType, TextHTMLCharsetUTF8) c.response.Header().Set(ContentType, TextHTMLCharsetUTF8)
c.response.WriteHeader(code) c.response.WriteHeader(code)
@ -212,7 +265,6 @@ func (c *context) HTML(code int, html string) (err error) {
return return
} }
// String sends a string response with status code.
func (c *context) String(code int, s string) (err error) { func (c *context) String(code int, s string) (err error) {
c.response.Header().Set(ContentType, TextPlainCharsetUTF8) c.response.Header().Set(ContentType, TextPlainCharsetUTF8)
c.response.WriteHeader(code) c.response.WriteHeader(code)
@ -220,7 +272,6 @@ func (c *context) String(code int, s string) (err error) {
return return
} }
// JSON sends a JSON response with status code.
func (c *context) JSON(code int, i interface{}) (err error) { func (c *context) JSON(code int, i interface{}) (err error) {
b, err := json.Marshal(i) b, err := json.Marshal(i)
if c.echo.Debug() { if c.echo.Debug() {
@ -232,7 +283,6 @@ func (c *context) JSON(code int, i interface{}) (err error) {
return c.JSONBlob(code, b) return c.JSONBlob(code, b)
} }
// JSONBlob sends a JSON blob response with status code.
func (c *context) JSONBlob(code int, b []byte) (err error) { func (c *context) JSONBlob(code int, b []byte) (err error) {
c.response.Header().Set(ContentType, ApplicationJSONCharsetUTF8) c.response.Header().Set(ContentType, ApplicationJSONCharsetUTF8)
c.response.WriteHeader(code) c.response.WriteHeader(code)
@ -240,8 +290,6 @@ func (c *context) JSONBlob(code int, b []byte) (err error) {
return return
} }
// JSONP sends a JSONP response with status code. It uses `callback` to construct
// the JSONP payload.
func (c *context) JSONP(code int, callback string, i interface{}) (err error) { func (c *context) JSONP(code int, callback string, i interface{}) (err error) {
b, err := json.Marshal(i) b, err := json.Marshal(i)
if err != nil { if err != nil {
@ -259,7 +307,6 @@ func (c *context) JSONP(code int, callback string, i interface{}) (err error) {
return return
} }
// XML sends an XML response with status code.
func (c *context) XML(code int, i interface{}) (err error) { func (c *context) XML(code int, i interface{}) (err error) {
b, err := xml.Marshal(i) b, err := xml.Marshal(i)
if c.echo.Debug() { if c.echo.Debug() {
@ -271,7 +318,6 @@ func (c *context) XML(code int, i interface{}) (err error) {
return c.XMLBlob(code, b) return c.XMLBlob(code, b)
} }
// XMLBlob sends a XML blob response with status code.
func (c *context) XMLBlob(code int, b []byte) (err error) { func (c *context) XMLBlob(code int, b []byte) (err error) {
c.response.Header().Set(ContentType, ApplicationXMLCharsetUTF8) c.response.Header().Set(ContentType, ApplicationXMLCharsetUTF8)
c.response.WriteHeader(code) c.response.WriteHeader(code)
@ -282,7 +328,6 @@ func (c *context) XMLBlob(code int, b []byte) (err error) {
return return
} }
// File sends a response with the content of the file.
func (c *context) File(file string) error { func (c *context) File(file string) error {
root, file := filepath.Split(file) root, file := filepath.Split(file)
fs := http.Dir(root) fs := http.Dir(root)
@ -305,8 +350,6 @@ func (c *context) File(file string) error {
return ServeContent(c.Request(), c.Response(), f, fi) return ServeContent(c.Request(), c.Response(), f, fi)
} }
// Attachment sends a response from `io.Reader` as attachment, prompting client
// to save the file.
func (c *context) Attachment(r io.Reader, name string) (err error) { func (c *context) Attachment(r io.Reader, name string) (err error) {
c.response.Header().Set(ContentType, detectContentType(name)) c.response.Header().Set(ContentType, detectContentType(name))
c.response.Header().Set(ContentDisposition, "attachment; filename="+name) c.response.Header().Set(ContentDisposition, "attachment; filename="+name)
@ -315,13 +358,11 @@ func (c *context) Attachment(r io.Reader, name string) (err error) {
return return
} }
// NoContent sends a response with no body and a status code.
func (c *context) NoContent(code int) error { func (c *context) NoContent(code int) error {
c.response.WriteHeader(code) c.response.WriteHeader(code)
return nil return nil
} }
// Redirect redirects the request with status code.
func (c *context) Redirect(code int, url string) error { func (c *context) Redirect(code int, url string) error {
if code < http.StatusMultipleChoices || code > http.StatusTemporaryRedirect { if code < http.StatusMultipleChoices || code > http.StatusTemporaryRedirect {
return ErrInvalidRedirectCode return ErrInvalidRedirectCode
@ -331,26 +372,24 @@ func (c *context) Redirect(code int, url string) error {
return nil return nil
} }
// Error invokes the registered HTTP error handler. Generally used by middleware.
func (c *context) Error(err error) { func (c *context) Error(err error) {
c.echo.httpErrorHandler(err, c) c.echo.httpErrorHandler(err, c)
} }
// Echo returns the `Echo` instance.
func (c *context) Echo() *Echo { func (c *context) Echo() *Echo {
return c.echo return c.echo
} }
// Logger returns the `Logger` instance.
func (c *context) Logger() *log.Logger { func (c *context) Logger() *log.Logger {
return c.echo.logger return c.echo.logger
} }
// Object returns the `context` object.
func (c *context) Object() *context { func (c *context) Object() *context {
return c return c
} }
// ServeContent sends a response from `io.Reader`. It automatically sets the `Content-Type`
// and `Last-Modified` headers.
func ServeContent(req engine.Request, res engine.Response, f http.File, fi os.FileInfo) error { func ServeContent(req engine.Request, res engine.Response, f http.File, fi os.FileInfo) error {
res.Header().Set(ContentType, detectContentType(fi.Name())) res.Header().Set(ContentType, detectContentType(fi.Name()))
res.Header().Set(LastModified, fi.ModTime().UTC().Format(http.TimeFormat)) res.Header().Set(LastModified, fi.ModTime().UTC().Format(http.TimeFormat))
@ -366,7 +405,7 @@ func detectContentType(name string) (t string) {
return return
} }
func (c *context) reset(req engine.Request, res engine.Response) { func (c *context) Reset(req engine.Request, res engine.Response) {
c.netContext = nil c.netContext = nil
c.request = req c.request = req
c.response = res c.response = res

View File

@ -191,8 +191,8 @@ func TestContext(t *testing.T) {
c.Error(errors.New("error")) c.Error(errors.New("error"))
assert.Equal(t, http.StatusInternalServerError, rec.Status()) assert.Equal(t, http.StatusInternalServerError, rec.Status())
// reset // Reset
c.Object().reset(req, test.NewResponseRecorder()) c.Object().Reset(req, test.NewResponseRecorder())
} }
func TestContextPath(t *testing.T) { func TestContextPath(t *testing.T) {

165
echo.go
View File

@ -1,3 +1,42 @@
/*
Package echo implements a fast and unfancy micro web framework for Go.
Example:
package main
import (
"net/http"
"github.com/labstack/echo"
"github.com/labstack/echo/engine/standard"
"github.com/labstack/echo/middleware"
)
// Handler
func hello() echo.HandlerFunc {
return func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!\n")
}
}
func main() {
// Echo instance
e := echo.New()
// Middleware
e.Use(middleware.Logger())
e.Use(middleware.Recover())
// Routes
e.Get("/", hello())
// Start server
e.Run(standard.New(":1323"))
}
Learn more at https://labstack.com/echo
*/
package echo package echo
import ( import (
@ -20,6 +59,7 @@ import (
) )
type ( type (
// Echo is the top-level framework instance.
Echo struct { Echo struct {
prefix string prefix string
middleware []Middleware middleware []Middleware
@ -36,33 +76,43 @@ type (
logger *log.Logger logger *log.Logger
} }
// Route contains a handler and information for matching against requests.
Route struct { Route struct {
Method string Method string
Path string Path string
Handler string Handler string
} }
// HTTPError represents an error that occured while handling a request.
HTTPError struct { HTTPError struct {
Code int Code int
Message string Message string
} }
// Middleware defines an interface for middleware via `Handle(Handler) Handler`
// function.
Middleware interface { Middleware interface {
Handle(Handler) Handler Handle(Handler) Handler
} }
// MiddlewareFunc is an adapter to allow the use of `func(Handler) Handler` as
// middleware.
MiddlewareFunc func(Handler) Handler MiddlewareFunc func(Handler) Handler
// Handler defines an interface to server HTTP requests via `Handle(Context)`
// function.
Handler interface { Handler interface {
Handle(Context) error Handle(Context) error
} }
// HandlerFunc is an adapter to allow the use of `func(Context)` as an HTTP
// handler.
HandlerFunc func(Context) error HandlerFunc func(Context) error
// HTTPErrorHandler is a centralized HTTP error handler. // HTTPErrorHandler is a centralized HTTP error handler.
HTTPErrorHandler func(error, Context) HTTPErrorHandler func(error, Context)
// Binder is the interface that wraps the Bind method. // Binder is the interface that wraps the Bind function.
Binder interface { Binder interface {
Bind(interface{}, Context) error Bind(interface{}, Context) error
} }
@ -70,41 +120,36 @@ type (
binder struct { binder struct {
} }
// Validator is the interface that wraps the Validate method. // Validator is the interface that wraps the Validate function.
Validator interface { Validator interface {
Validate() error Validate() error
} }
// Renderer is the interface that wraps the Render method. // Renderer is the interface that wraps the Render function.
Renderer interface { Renderer interface {
Render(io.Writer, string, interface{}, Context) error Render(io.Writer, string, interface{}, Context) error
} }
) )
//--------------
// HTTP methods
//--------------
const ( const (
// CONNECT HTTP method
CONNECT = "CONNECT" CONNECT = "CONNECT"
// DELETE HTTP method
DELETE = "DELETE" DELETE = "DELETE"
// GET HTTP method
GET = "GET" GET = "GET"
// HEAD HTTP method
HEAD = "HEAD" HEAD = "HEAD"
// OPTIONS HTTP method
OPTIONS = "OPTIONS" OPTIONS = "OPTIONS"
// PATCH HTTP method
PATCH = "PATCH" PATCH = "PATCH"
// POST HTTP method
POST = "POST" POST = "POST"
// PUT HTTP method
PUT = "PUT" PUT = "PUT"
// TRACE HTTP method
TRACE = "TRACE" TRACE = "TRACE"
)
//------------- //-------------
// Media types // Media types
//------------- //-------------
const (
ApplicationJSON = "application/json" ApplicationJSON = "application/json"
ApplicationJSONCharsetUTF8 = ApplicationJSON + "; " + CharsetUTF8 ApplicationJSONCharsetUTF8 = ApplicationJSON + "; " + CharsetUTF8
ApplicationJavaScript = "application/javascript" ApplicationJavaScript = "application/javascript"
@ -120,17 +165,19 @@ const (
TextPlainCharsetUTF8 = TextPlain + "; " + CharsetUTF8 TextPlainCharsetUTF8 = TextPlain + "; " + CharsetUTF8
MultipartForm = "multipart/form-data" MultipartForm = "multipart/form-data"
OctetStream = "application/octet-stream" OctetStream = "application/octet-stream"
)
//--------- //---------
// Charset // Charset
//--------- //---------
const (
CharsetUTF8 = "charset=utf-8" CharsetUTF8 = "charset=utf-8"
)
//--------- //---------
// Headers // Headers
//--------- //---------
const (
AcceptEncoding = "Accept-Encoding" AcceptEncoding = "Accept-Encoding"
Authorization = "Authorization" Authorization = "Authorization"
ContentDisposition = "Content-Disposition" ContentDisposition = "Content-Disposition"
@ -158,22 +205,24 @@ var (
PUT, PUT,
TRACE, TRACE,
} }
)
//-------- //--------
// Errors // Errors
//-------- //--------
var (
ErrUnsupportedMediaType = NewHTTPError(http.StatusUnsupportedMediaType) ErrUnsupportedMediaType = NewHTTPError(http.StatusUnsupportedMediaType)
ErrNotFound = NewHTTPError(http.StatusNotFound) ErrNotFound = NewHTTPError(http.StatusNotFound)
ErrUnauthorized = NewHTTPError(http.StatusUnauthorized) ErrUnauthorized = NewHTTPError(http.StatusUnauthorized)
ErrMethodNotAllowed = NewHTTPError(http.StatusMethodNotAllowed) ErrMethodNotAllowed = NewHTTPError(http.StatusMethodNotAllowed)
ErrRendererNotRegistered = errors.New("renderer not registered") ErrRendererNotRegistered = errors.New("renderer not registered")
ErrInvalidRedirectCode = errors.New("invalid redirect status code") ErrInvalidRedirectCode = errors.New("invalid redirect status code")
)
//---------------- //----------------
// Error handlers // Error handlers
//---------------- //----------------
var (
notFoundHandler = HandlerFunc(func(c Context) error { notFoundHandler = HandlerFunc(func(c Context) error {
return ErrNotFound return ErrNotFound
}) })
@ -206,12 +255,14 @@ func New() (e *Echo) {
return return
} }
func (m MiddlewareFunc) Handle(h Handler) Handler { // Handle chains middleware.
return m(h) func (f MiddlewareFunc) Handle(h Handler) Handler {
return f(h)
} }
func (h HandlerFunc) Handle(c Context) error { // Handle serves HTTP request.
return h(c) func (f HandlerFunc) Handle(c Context) error {
return f(c)
} }
// Router returns router. // Router returns router.
@ -261,12 +312,12 @@ func (e *Echo) SetHTTPErrorHandler(h HTTPErrorHandler) {
e.httpErrorHandler = h e.httpErrorHandler = h
} }
// SetBinder registers a custom binder. It's invoked by Context.Bind(). // SetBinder registers a custom binder. It's invoked by `Context#Bind()`.
func (e *Echo) SetBinder(b Binder) { func (e *Echo) SetBinder(b Binder) {
e.binder = b e.binder = b
} }
// SetRenderer registers an HTML template renderer. It's invoked by Context.Render(). // SetRenderer registers an HTML template renderer. It's invoked by `Context#Render()`.
func (e *Echo) SetRenderer(r Renderer) { func (e *Echo) SetRenderer(r Renderer) {
e.renderer = r e.renderer = r
} }
@ -301,59 +352,70 @@ func (e *Echo) chainMiddleware() {
} }
} }
// Connect adds a CONNECT route > handler to the router. // Connect registers a new CONNECT route for a path with matching handler in the
// router with optional route-level middleware.
func (e *Echo) Connect(path string, h Handler, m ...Middleware) { func (e *Echo) Connect(path string, h Handler, m ...Middleware) {
e.add(CONNECT, path, h, m...) e.add(CONNECT, path, h, m...)
} }
// Delete adds a DELETE route > handler to the router. // Delete registers a new DELETE route for a path with matching handler in the router
// with optional route-level middleware.
func (e *Echo) Delete(path string, h Handler, m ...Middleware) { func (e *Echo) Delete(path string, h Handler, m ...Middleware) {
e.add(DELETE, path, h, m...) e.add(DELETE, path, h, m...)
} }
// Get adds a GET route > handler to the router. // Get registers a new GET route for a path with matching handler in the router
// with optional route-level middleware.
func (e *Echo) Get(path string, h Handler, m ...Middleware) { func (e *Echo) Get(path string, h Handler, m ...Middleware) {
e.add(GET, path, h, m...) e.add(GET, path, h, m...)
} }
// Head adds a HEAD route > handler to the router. // Head registers a new HEAD route for a path with matching handler in the
// router with optional route-level middleware.
func (e *Echo) Head(path string, h Handler, m ...Middleware) { func (e *Echo) Head(path string, h Handler, m ...Middleware) {
e.add(HEAD, path, h, m...) e.add(HEAD, path, h, m...)
} }
// Options adds an OPTIONS route > handler to the router. // Options registers a new OPTIONS route for a path with matching handler in the
// router with optional route-level middleware.
func (e *Echo) Options(path string, h Handler, m ...Middleware) { func (e *Echo) Options(path string, h Handler, m ...Middleware) {
e.add(OPTIONS, path, h, m...) e.add(OPTIONS, path, h, m...)
} }
// Patch adds a PATCH route > handler to the router. // Patch registers a new PATCH route for a path with matching handler in the
// router with optional route-level middleware.
func (e *Echo) Patch(path string, h Handler, m ...Middleware) { func (e *Echo) Patch(path string, h Handler, m ...Middleware) {
e.add(PATCH, path, h, m...) e.add(PATCH, path, h, m...)
} }
// Post adds a POST route > handler to the router. // Post registers a new POST route for a path with matching handler in the
// router with optional route-level middleware.
func (e *Echo) Post(path string, h Handler, m ...Middleware) { func (e *Echo) Post(path string, h Handler, m ...Middleware) {
e.add(POST, path, h, m...) e.add(POST, path, h, m...)
} }
// Put adds a PUT route > handler to the router. // Put registers a new PUT route for a path with matching handler in the
// router with optional route-level middleware.
func (e *Echo) Put(path string, h Handler, m ...Middleware) { func (e *Echo) Put(path string, h Handler, m ...Middleware) {
e.add(PUT, path, h, m...) e.add(PUT, path, h, m...)
} }
// Trace adds a TRACE route > handler to the router. // Trace registers a new TRACE route for a path with matching handler in the
// router with optional route-level middleware.
func (e *Echo) Trace(path string, h Handler, m ...Middleware) { func (e *Echo) Trace(path string, h Handler, m ...Middleware) {
e.add(TRACE, path, h, m...) e.add(TRACE, path, h, m...)
} }
// Any adds a route > handler to the router for all HTTP methods. // Any registers a new route for all HTTP methods and path with matching handler
// in the router with optional route-level middleware.
func (e *Echo) Any(path string, handler Handler, middleware ...Middleware) { func (e *Echo) Any(path string, handler Handler, middleware ...Middleware) {
for _, m := range methods { for _, m := range methods {
e.add(m, path, handler, middleware...) e.add(m, path, handler, middleware...)
} }
} }
// Match adds a route > handler to the router for multiple HTTP methods provided. // Match registers a new route for multiple HTTP methods and path with matching
// handler in the router with optional route-level middleware.
func (e *Echo) Match(methods []string, path string, handler Handler, middleware ...Middleware) { func (e *Echo) Match(methods []string, path string, handler Handler, middleware ...Middleware) {
for _, m := range methods { for _, m := range methods {
e.add(m, path, handler, middleware...) e.add(m, path, handler, middleware...)
@ -392,7 +454,7 @@ func (e *Echo) add(method, path string, handler Handler, middleware ...Middlewar
e.router.routes = append(e.router.routes, r) e.router.routes = append(e.router.routes, r)
} }
// Group creates a new router group with prefix. // Group creates a new router group with prefix and optional group-level middleware.
func (e *Echo) Group(prefix string, m ...Middleware) (g *Group) { func (e *Echo) Group(prefix string, m ...Middleware) (g *Group) {
g = &Group{prefix: prefix, echo: e} g = &Group{prefix: prefix, echo: e}
g.Use(m...) g.Use(m...)
@ -448,7 +510,7 @@ func (e *Echo) PutContext(c Context) {
func (e *Echo) ServeHTTP(req engine.Request, res engine.Response) { func (e *Echo) ServeHTTP(req engine.Request, res engine.Response) {
c := e.pool.Get().(*context) c := e.pool.Get().(*context)
c.reset(req, res) c.Reset(req, res)
// Execute chain // Execute chain
if err := e.head.Handle(c); err != nil { if err := e.head.Handle(c); err != nil {
@ -465,6 +527,7 @@ func (e *Echo) Run(s engine.Server) error {
return s.Start() return s.Start()
} }
// NewHTTPError creates a new HTTPError instance.
func NewHTTPError(code int, msg ...string) *HTTPError { func NewHTTPError(code int, msg ...string) *HTTPError {
he := &HTTPError{Code: code, Message: http.StatusText(code)} he := &HTTPError{Code: code, Message: http.StatusText(code)}
if len(msg) > 0 { if len(msg) > 0 {

View File

@ -54,7 +54,7 @@ type (
// RemoteAddress returns the client's network address. // RemoteAddress returns the client's network address.
RemoteAddress() string RemoteAddress() string
// Method returns the request's HTTP method. // Method returns the request's HTTP function.
Method() string Method() string
// SetMethod sets the HTTP method of the request. // SetMethod sets the HTTP method of the request.
@ -136,7 +136,7 @@ type (
QueryString() string QueryString() string
} }
// Config defines engine configuration. // Config defines engine config.
Config struct { Config struct {
Address string // TCP address to listen on. Address string // TCP address to listen on.
Listener net.Listener // Custom `net.Listener`. If set, server accepts connections on it. Listener net.Listener // Custom `net.Listener`. If set, server accepts connections on it.
@ -152,7 +152,8 @@ type (
ServeHTTP(Request, Response) ServeHTTP(Request, Response)
} }
// HandlerFunc is an adapter to allow the use of `func(Request, Response)` as HTTP handlers. // HandlerFunc is an adapter to allow the use of `func(Request, Response)` as
// an HTTP handler.
HandlerFunc func(Request, Response) HandlerFunc func(Request, Response)
) )

View File

@ -16,27 +16,27 @@ type (
} }
) )
// Add implements `engine.Header#Add` method. // Add implements `engine.Header#Add` function.
func (h *RequestHeader) Add(key, val string) { func (h *RequestHeader) Add(key, val string) {
// h.RequestHeader.Add(key, val) // h.RequestHeader.Add(key, val)
} }
// Del implements `engine.Header#Del` method. // Del implements `engine.Header#Del` function.
func (h *RequestHeader) Del(key string) { func (h *RequestHeader) Del(key string) {
h.RequestHeader.Del(key) h.RequestHeader.Del(key)
} }
// Set implements `engine.Header#Set` method. // Set implements `engine.Header#Set` function.
func (h *RequestHeader) Set(key, val string) { func (h *RequestHeader) Set(key, val string) {
h.RequestHeader.Set(key, val) h.RequestHeader.Set(key, val)
} }
// Get implements `engine.Header#Get` method. // Get implements `engine.Header#Get` function.
func (h *RequestHeader) Get(key string) string { func (h *RequestHeader) Get(key string) string {
return string(h.Peek(key)) return string(h.Peek(key))
} }
// Keys implements `engine.Header#Keys` method. // Keys implements `engine.Header#Keys` function.
func (h *RequestHeader) Keys() (keys []string) { func (h *RequestHeader) Keys() (keys []string) {
keys = make([]string, h.Len()) keys = make([]string, h.Len())
i := 0 i := 0
@ -51,28 +51,28 @@ func (h *RequestHeader) reset(hdr *fasthttp.RequestHeader) {
h.RequestHeader = hdr h.RequestHeader = hdr
} }
// Add implements `engine.Header#Add` method. // Add implements `engine.Header#Add` function.
func (h *ResponseHeader) Add(key, val string) { func (h *ResponseHeader) Add(key, val string) {
// TODO: https://github.com/valyala/fasthttp/issues/69 // TODO: https://github.com/valyala/fasthttp/issues/69
// h.header.Add(key, val) // h.header.Add(key, val)
} }
// Del implements `engine.Header#Del` method. // Del implements `engine.Header#Del` function.
func (h *ResponseHeader) Del(key string) { func (h *ResponseHeader) Del(key string) {
h.ResponseHeader.Del(key) h.ResponseHeader.Del(key)
} }
// Get implements `engine.Header#Get` method. // Get implements `engine.Header#Get` function.
func (h *ResponseHeader) Get(key string) string { func (h *ResponseHeader) Get(key string) string {
return string(h.Peek(key)) return string(h.Peek(key))
} }
// Set implements `engine.Header#Set` method. // Set implements `engine.Header#Set` function.
func (h *ResponseHeader) Set(key, val string) { func (h *ResponseHeader) Set(key, val string) {
h.ResponseHeader.Set(key, val) h.ResponseHeader.Set(key, val)
} }
// Keys implements `engine.Header#Keys` method. // Keys implements `engine.Header#Keys` function.
func (h *ResponseHeader) Keys() (keys []string) { func (h *ResponseHeader) Keys() (keys []string) {
keys = make([]string, h.Len()) keys = make([]string, h.Len())
i := 0 i := 0

View File

@ -22,72 +22,72 @@ type (
} }
) )
// TLS implements `engine.Request#TLS` method. // TLS implements `engine.Request#TLS` function.
func (r *Request) TLS() bool { func (r *Request) TLS() bool {
return r.IsTLS() return r.IsTLS()
} }
// Scheme implements `engine.Request#Scheme` method. // Scheme implements `engine.Request#Scheme` function.
func (r *Request) Scheme() string { func (r *Request) Scheme() string {
return string(r.RequestCtx.URI().Scheme()) return string(r.RequestCtx.URI().Scheme())
} }
// Host implements `engine.Request#Host` method. // Host implements `engine.Request#Host` function.
func (r *Request) Host() string { func (r *Request) Host() string {
return string(r.RequestCtx.Host()) return string(r.RequestCtx.Host())
} }
// URL implements `engine.Request#URL` method. // URL implements `engine.Request#URL` function.
func (r *Request) URL() engine.URL { func (r *Request) URL() engine.URL {
return r.url return r.url
} }
// Header implements `engine.Request#Header` method. // Header implements `engine.Request#Header` function.
func (r *Request) Header() engine.Header { func (r *Request) Header() engine.Header {
return r.header return r.header
} }
// UserAgent implements `engine.Request#UserAgent` method. // UserAgent implements `engine.Request#UserAgent` function.
func (r *Request) UserAgent() string { func (r *Request) UserAgent() string {
return string(r.RequestCtx.UserAgent()) return string(r.RequestCtx.UserAgent())
} }
// RemoteAddress implements `engine.Request#RemoteAddress` method. // RemoteAddress implements `engine.Request#RemoteAddress` function.
func (r *Request) RemoteAddress() string { func (r *Request) RemoteAddress() string {
return r.RemoteAddr().String() return r.RemoteAddr().String()
} }
// Method implements `engine.Request#Method` method. // Method implements `engine.Request#Method` function.
func (r *Request) Method() string { func (r *Request) Method() string {
return string(r.RequestCtx.Method()) return string(r.RequestCtx.Method())
} }
// SetMethod implements `engine.Request#SetMethod` method. // SetMethod implements `engine.Request#SetMethod` function.
func (r *Request) SetMethod(method string) { func (r *Request) SetMethod(method string) {
r.Request.Header.SetMethod(method) r.Request.Header.SetMethod(method)
} }
// URI implements `engine.Request#URI` method. // URI implements `engine.Request#URI` function.
func (r *Request) URI() string { func (r *Request) URI() string {
return string(r.RequestURI()) return string(r.RequestURI())
} }
// Body implements `engine.Request#Body` method. // Body implements `engine.Request#Body` function.
func (r *Request) Body() io.Reader { func (r *Request) Body() io.Reader {
return bytes.NewBuffer(r.PostBody()) return bytes.NewBuffer(r.PostBody())
} }
// FormValue implements `engine.Request#FormValue` method. // FormValue implements `engine.Request#FormValue` function.
func (r *Request) FormValue(name string) string { func (r *Request) FormValue(name string) string {
return string(r.RequestCtx.FormValue(name)) return string(r.RequestCtx.FormValue(name))
} }
// FormFile implements `engine.Request#FormFile` method. // FormFile implements `engine.Request#FormFile` function.
func (r *Request) FormFile(name string) (*multipart.FileHeader, error) { func (r *Request) FormFile(name string) (*multipart.FileHeader, error) {
return r.RequestCtx.FormFile(name) return r.RequestCtx.FormFile(name)
} }
// MultipartForm implements `engine.Request#MultipartForm` method. // MultipartForm implements `engine.Request#MultipartForm` function.
func (r *Request) MultipartForm() (*multipart.Form, error) { func (r *Request) MultipartForm() (*multipart.Form, error) {
return r.RequestCtx.MultipartForm() return r.RequestCtx.MultipartForm()
} }

View File

@ -24,12 +24,12 @@ type (
} }
) )
// Header implements `engine.Response#Header` method. // Header implements `engine.Response#Header` function.
func (r *Response) Header() engine.Header { func (r *Response) Header() engine.Header {
return r.header return r.header
} }
// WriteHeader implements `engine.Response#WriteHeader` method. // WriteHeader implements `engine.Response#WriteHeader` function.
func (r *Response) WriteHeader(code int) { func (r *Response) WriteHeader(code int) {
if r.committed { if r.committed {
r.logger.Warn("response already committed") r.logger.Warn("response already committed")
@ -40,34 +40,34 @@ func (r *Response) WriteHeader(code int) {
r.committed = true r.committed = true
} }
// Write implements `engine.Response#Write` method. // Write implements `engine.Response#Write` function.
func (r *Response) Write(b []byte) (n int, err error) { func (r *Response) Write(b []byte) (n int, err error) {
n, err = r.writer.Write(b) n, err = r.writer.Write(b)
r.size += int64(n) r.size += int64(n)
return return
} }
// Status implements `engine.Response#Status` method. // Status implements `engine.Response#Status` function.
func (r *Response) Status() int { func (r *Response) Status() int {
return r.status return r.status
} }
// Size implements `engine.Response#Size` method. // Size implements `engine.Response#Size` function.
func (r *Response) Size() int64 { func (r *Response) Size() int64 {
return r.size return r.size
} }
// Committed implements `engine.Response#Committed` method. // Committed implements `engine.Response#Committed` function.
func (r *Response) Committed() bool { func (r *Response) Committed() bool {
return r.committed return r.committed
} }
// Writer implements `engine.Response#Writer` method. // Writer implements `engine.Response#Writer` function.
func (r *Response) Writer() io.Writer { func (r *Response) Writer() io.Writer {
return r.writer return r.writer
} }
// SetWriter implements `engine.Response#SetWriter` method. // SetWriter implements `engine.Response#SetWriter` function.
func (r *Response) SetWriter(w io.Writer) { func (r *Response) SetWriter(w io.Writer) {
r.writer = w r.writer = w
} }

View File

@ -87,17 +87,17 @@ func NewFromConfig(c engine.Config) (s *Server) {
return return
} }
// SetHandler implements `engine.Server#SetHandler` method. // SetHandler implements `engine.Server#SetHandler` function.
func (s *Server) SetHandler(h engine.Handler) { func (s *Server) SetHandler(h engine.Handler) {
s.handler = h s.handler = h
} }
// SetLogger implements `engine.Server#SetLogger` method. // SetLogger implements `engine.Server#SetLogger` function.
func (s *Server) SetLogger(l *log.Logger) { func (s *Server) SetLogger(l *log.Logger) {
s.logger = l s.logger = l
} }
// Start implements `engine.Server#Start` method. // Start implements `engine.Server#Start` function.
func (s *Server) Start() error { func (s *Server) Start() error {
if s.config.Listener == nil { if s.config.Listener == nil {
return s.startDefaultListener() return s.startDefaultListener()

View File

@ -11,22 +11,22 @@ type (
} }
) )
// Path implements `engine.URL#Path` method. // Path implements `engine.URL#Path` function.
func (u *URL) Path() string { func (u *URL) Path() string {
return string(u.URI.Path()) return string(u.URI.Path())
} }
// SetPath implements `engine.URL#SetPath` method. // SetPath implements `engine.URL#SetPath` function.
func (u *URL) SetPath(path string) { func (u *URL) SetPath(path string) {
u.URI.SetPath(path) u.URI.SetPath(path)
} }
// QueryValue implements `engine.URL#QueryValue` method. // QueryValue implements `engine.URL#QueryValue` function.
func (u *URL) QueryValue(name string) string { func (u *URL) QueryValue(name string) string {
return string(u.QueryArgs().Peek(name)) return string(u.QueryArgs().Peek(name))
} }
// QueryString implements `engine.URL#QueryString` method. // QueryString implements `engine.URL#QueryString` function.
func (u *URL) QueryString() string { func (u *URL) QueryString() string {
return string(u.URI.QueryString()) return string(u.URI.QueryString())
} }

View File

@ -9,27 +9,27 @@ type (
} }
) )
// Add implements `engine.Header#Add` method. // Add implements `engine.Header#Add` function.
func (h *Header) Add(key, val string) { func (h *Header) Add(key, val string) {
h.Header.Add(key, val) h.Header.Add(key, val)
} }
// Del implements `engine.Header#Del` method. // Del implements `engine.Header#Del` function.
func (h *Header) Del(key string) { func (h *Header) Del(key string) {
h.Header.Del(key) h.Header.Del(key)
} }
// Set implements `engine.Header#Set` method. // Set implements `engine.Header#Set` function.
func (h *Header) Set(key, val string) { func (h *Header) Set(key, val string) {
h.Header.Set(key, val) h.Header.Set(key, val)
} }
// Get implements `engine.Header#Get` method. // Get implements `engine.Header#Get` function.
func (h *Header) Get(key string) string { func (h *Header) Get(key string) string {
return h.Header.Get(key) return h.Header.Get(key)
} }
// Keys implements `engine.Header#Keys` method. // Keys implements `engine.Header#Keys` function.
func (h *Header) Keys() (keys []string) { func (h *Header) Keys() (keys []string) {
keys = make([]string, len(h.Header)) keys = make([]string, len(h.Header))
i := 0 i := 0

View File

@ -17,12 +17,12 @@ type (
} }
) )
// TLS implements `engine.Request#TLS` method. // TLS implements `engine.Request#TLS` function.
func (r *Request) TLS() bool { func (r *Request) TLS() bool {
return r.Request.TLS != nil return r.Request.TLS != nil
} }
// Scheme implements `engine.Request#Scheme` method. // Scheme implements `engine.Request#Scheme` function.
func (r *Request) Scheme() string { func (r *Request) Scheme() string {
if r.TLS() { if r.TLS() {
return "https" return "https"
@ -30,17 +30,17 @@ func (r *Request) Scheme() string {
return "http" return "http"
} }
// Host implements `engine.Request#Host` method. // Host implements `engine.Request#Host` function.
func (r *Request) Host() string { func (r *Request) Host() string {
return r.Request.Host return r.Request.Host
} }
// URL implements `engine.Request#URL` method. // URL implements `engine.Request#URL` function.
func (r *Request) URL() engine.URL { func (r *Request) URL() engine.URL {
return r.url return r.url
} }
// Header implements `engine.Request#URL` method. // Header implements `engine.Request#URL` function.
func (r *Request) Header() engine.Header { func (r *Request) Header() engine.Header {
return r.header return r.header
} }
@ -57,48 +57,48 @@ func (r *Request) Header() engine.Header {
// return r.request.ProtoMinor() // return r.request.ProtoMinor()
// } // }
// UserAgent implements `engine.Request#UserAgent` method. // UserAgent implements `engine.Request#UserAgent` function.
func (r *Request) UserAgent() string { func (r *Request) UserAgent() string {
return r.Request.UserAgent() return r.Request.UserAgent()
} }
// RemoteAddress implements `engine.Request#RemoteAddress` method. // RemoteAddress implements `engine.Request#RemoteAddress` function.
func (r *Request) RemoteAddress() string { func (r *Request) RemoteAddress() string {
return r.RemoteAddr return r.RemoteAddr
} }
// Method implements `engine.Request#Method` method. // Method implements `engine.Request#Method` function.
func (r *Request) Method() string { func (r *Request) Method() string {
return r.Request.Method return r.Request.Method
} }
// SetMethod implements `engine.Request#SetMethod` method. // SetMethod implements `engine.Request#SetMethod` function.
func (r *Request) SetMethod(method string) { func (r *Request) SetMethod(method string) {
r.Request.Method = method r.Request.Method = method
} }
// URI implements `engine.Request#URI` method. // URI implements `engine.Request#URI` function.
func (r *Request) URI() string { func (r *Request) URI() string {
return r.RequestURI return r.RequestURI
} }
// Body implements `engine.Request#Body` method. // Body implements `engine.Request#Body` function.
func (r *Request) Body() io.Reader { func (r *Request) Body() io.Reader {
return r.Request.Body return r.Request.Body
} }
// FormValue implements `engine.Request#FormValue` method. // FormValue implements `engine.Request#FormValue` function.
func (r *Request) FormValue(name string) string { func (r *Request) FormValue(name string) string {
return r.Request.FormValue(name) return r.Request.FormValue(name)
} }
// FormFile implements `engine.Request#FormFile` method. // FormFile implements `engine.Request#FormFile` function.
func (r *Request) FormFile(name string) (*multipart.FileHeader, error) { func (r *Request) FormFile(name string) (*multipart.FileHeader, error) {
_, fh, err := r.Request.FormFile(name) _, fh, err := r.Request.FormFile(name)
return fh, err return fh, err
} }
// MultipartForm implements `engine.Request#MultipartForm` method. // MultipartForm implements `engine.Request#MultipartForm` function.
func (r *Request) MultipartForm() (*multipart.Form, error) { func (r *Request) MultipartForm() (*multipart.Form, error) {
err := r.Request.ParseMultipartForm(32 << 20) // 32 MB err := r.Request.ParseMultipartForm(32 << 20) // 32 MB
return r.Request.MultipartForm, err return r.Request.MultipartForm, err

View File

@ -28,12 +28,12 @@ type (
} }
) )
// Header implements `engine.Response#Header` method. // Header implements `engine.Response#Header` function.
func (r *Response) Header() engine.Header { func (r *Response) Header() engine.Header {
return r.header return r.header
} }
// WriteHeader implements `engine.Response#WriteHeader` method. // WriteHeader implements `engine.Response#WriteHeader` function.
func (r *Response) WriteHeader(code int) { func (r *Response) WriteHeader(code int) {
if r.committed { if r.committed {
r.logger.Warn("response already committed") r.logger.Warn("response already committed")
@ -44,48 +44,48 @@ func (r *Response) WriteHeader(code int) {
r.committed = true r.committed = true
} }
// Write implements `engine.Response#Write` method. // Write implements `engine.Response#Write` function.
func (r *Response) Write(b []byte) (n int, err error) { func (r *Response) Write(b []byte) (n int, err error) {
n, err = r.writer.Write(b) n, err = r.writer.Write(b)
r.size += int64(n) r.size += int64(n)
return return
} }
// Status implements `engine.Response#Status` method. // Status implements `engine.Response#Status` function.
func (r *Response) Status() int { func (r *Response) Status() int {
return r.status return r.status
} }
// Size implements `engine.Response#Size` method. // Size implements `engine.Response#Size` function.
func (r *Response) Size() int64 { func (r *Response) Size() int64 {
return r.size return r.size
} }
// Committed implements `engine.Response#Committed` method. // Committed implements `engine.Response#Committed` function.
func (r *Response) Committed() bool { func (r *Response) Committed() bool {
return r.committed return r.committed
} }
// Writer implements `engine.Response#Writer` method. // Writer implements `engine.Response#Writer` function.
func (r *Response) Writer() io.Writer { func (r *Response) Writer() io.Writer {
return r.writer return r.writer
} }
// SetWriter implements `engine.Response#SetWriter` method. // SetWriter implements `engine.Response#SetWriter` function.
func (r *Response) SetWriter(w io.Writer) { func (r *Response) SetWriter(w io.Writer) {
r.writer = w r.writer = w
} }
// Flush implements the http.Flusher interface to allow an HTTP handler to flush // Flush implements the http.Flusher interface to allow an HTTP handler to flush
// buffered data to the client. // buffered data to the client.
// See [http.Flusher](https://golang.org/pkg/net/http/#Flusher) // See https://golang.org/pkg/net/http/#Flusher
func (r *Response) Flush() { func (r *Response) Flush() {
r.ResponseWriter.(http.Flusher).Flush() r.ResponseWriter.(http.Flusher).Flush()
} }
// Hijack implements the http.Hijacker interface to allow an HTTP handler to // Hijack implements the http.Hijacker interface to allow an HTTP handler to
// take over the connection. // take over the connection.
// See [http.Hijacker](https://golang.org/pkg/net/http/#Hijacker) // See https://golang.org/pkg/net/http/#Hijacker
func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) { func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
return r.ResponseWriter.(http.Hijacker).Hijack() return r.ResponseWriter.(http.Hijacker).Hijack()
} }
@ -94,7 +94,7 @@ func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
// when the underlying connection has gone away. // when the underlying connection has gone away.
// This mechanism can be used to cancel long operations on the server if the // This mechanism can be used to cancel long operations on the server if the
// client has disconnected before the response is ready. // client has disconnected before the response is ready.
// See [http.CloseNotifier](https://golang.org/pkg/net/http/#CloseNotifier) // See https://golang.org/pkg/net/http/#CloseNotifier
func (r *Response) CloseNotify() <-chan bool { func (r *Response) CloseNotify() <-chan bool {
return r.ResponseWriter.(http.CloseNotifier).CloseNotify() return r.ResponseWriter.(http.CloseNotifier).CloseNotify()
} }

View File

@ -80,17 +80,17 @@ func NewFromConfig(c engine.Config) (s *Server) {
return return
} }
// SetHandler implements `engine.Server#SetHandler` method. // SetHandler implements `engine.Server#SetHandler` function.
func (s *Server) SetHandler(h engine.Handler) { func (s *Server) SetHandler(h engine.Handler) {
s.handler = h s.handler = h
} }
// SetLogger implements `engine.Server#SetLogger` method. // SetLogger implements `engine.Server#SetLogger` function.
func (s *Server) SetLogger(l *log.Logger) { func (s *Server) SetLogger(l *log.Logger) {
s.logger = l s.logger = l
} }
// Start implements `engine.Server#Start` method. // Start implements `engine.Server#Start` function.
func (s *Server) Start() error { func (s *Server) Start() error {
if s.config.Listener == nil { if s.config.Listener == nil {
return s.startDefaultListener() return s.startDefaultListener()

View File

@ -10,17 +10,17 @@ type (
} }
) )
// Path implements `engine.URL#Path` method. // Path implements `engine.URL#Path` function.
func (u *URL) Path() string { func (u *URL) Path() string {
return u.URL.Path return u.URL.Path
} }
// SetPath implements `engine.URL#SetPath` method. // SetPath implements `engine.URL#SetPath` function.
func (u *URL) SetPath(path string) { func (u *URL) SetPath(path string) {
u.URL.Path = path u.URL.Path = path
} }
// QueryValue implements `engine.URL#QueryValue` method. // QueryValue implements `engine.URL#QueryValue` function.
func (u *URL) QueryValue(name string) string { func (u *URL) QueryValue(name string) string {
if u.query == nil { if u.query == nil {
u.query = u.Query() u.query = u.Query()
@ -28,7 +28,7 @@ func (u *URL) QueryValue(name string) string {
return u.query.Get(name) return u.query.Get(name)
} }
// QueryString implements `engine.URL#QueryString` method. // QueryString implements `engine.URL#QueryString` function.
func (u *URL) QueryString() string { func (u *URL) QueryString() string {
return u.URL.RawQuery return u.URL.RawQuery
} }

View File

@ -1,6 +1,9 @@
package echo package echo
type ( type (
// Group is a set of sub-routes for a specified route. It can be used for inner
// routes that share a common middlware or functionality that should be separate
// from the parent echo instance while still inheriting from it.
Group struct { Group struct {
prefix string prefix string
middleware []Middleware middleware []Middleware
@ -8,59 +11,71 @@ type (
} }
) )
// Use implements `Echo#Use()` for sub-routes within the Group.
func (g *Group) Use(m ...Middleware) { func (g *Group) Use(m ...Middleware) {
g.middleware = append(g.middleware, m...) g.middleware = append(g.middleware, m...)
} }
// Connect implements `Echo#Connect()` for sub-routes within the Group.
func (g *Group) Connect(path string, h Handler, m ...Middleware) { func (g *Group) Connect(path string, h Handler, m ...Middleware) {
g.add(CONNECT, path, h, m...) g.add(CONNECT, path, h, m...)
} }
// Delete implements `Echo#Delete()` for sub-routes within the Group.
func (g *Group) Delete(path string, h Handler, m ...Middleware) { func (g *Group) Delete(path string, h Handler, m ...Middleware) {
g.add(DELETE, path, h, m...) g.add(DELETE, path, h, m...)
} }
// Get implements `Echo#Get()` for sub-routes within the Group.
func (g *Group) Get(path string, h Handler, m ...Middleware) { func (g *Group) Get(path string, h Handler, m ...Middleware) {
g.add(GET, path, h, m...) g.add(GET, path, h, m...)
} }
// Head implements `Echo#Head()` for sub-routes within the Group.
func (g *Group) Head(path string, h Handler, m ...Middleware) { func (g *Group) Head(path string, h Handler, m ...Middleware) {
g.add(HEAD, path, h, m...) g.add(HEAD, path, h, m...)
} }
// Options implements `Echo#Options()` for sub-routes within the Group.
func (g *Group) Options(path string, h Handler, m ...Middleware) { func (g *Group) Options(path string, h Handler, m ...Middleware) {
g.add(OPTIONS, path, h, m...) g.add(OPTIONS, path, h, m...)
} }
// Patch implements `Echo#Patch()` for sub-routes within the Group.
func (g *Group) Patch(path string, h Handler, m ...Middleware) { func (g *Group) Patch(path string, h Handler, m ...Middleware) {
g.add(PATCH, path, h, m...) g.add(PATCH, path, h, m...)
} }
// Post implements `Echo#Post()` for sub-routes within the Group.
func (g *Group) Post(path string, h Handler, m ...Middleware) { func (g *Group) Post(path string, h Handler, m ...Middleware) {
g.add(POST, path, h, m...) g.add(POST, path, h, m...)
} }
// Put implements `Echo#Put()` for sub-routes within the Group.
func (g *Group) Put(path string, h Handler, m ...Middleware) { func (g *Group) Put(path string, h Handler, m ...Middleware) {
g.add(PUT, path, h, m...) g.add(PUT, path, h, m...)
} }
// Trace implements `Echo#Trace()` for sub-routes within the Group.
func (g *Group) Trace(path string, h Handler, m ...Middleware) { func (g *Group) Trace(path string, h Handler, m ...Middleware) {
g.add(TRACE, path, h, m...) g.add(TRACE, path, h, m...)
} }
// Any implements `Echo#Any()` for sub-routes within the Group.
func (g *Group) Any(path string, handler Handler, middleware ...Middleware) { func (g *Group) Any(path string, handler Handler, middleware ...Middleware) {
for _, m := range methods { for _, m := range methods {
g.add(m, path, handler, middleware...) g.add(m, path, handler, middleware...)
} }
} }
// Match implements `Echo#Match()` for sub-routes within the Group.
func (g *Group) Match(methods []string, path string, handler Handler, middleware ...Middleware) { func (g *Group) Match(methods []string, path string, handler Handler, middleware ...Middleware) {
for _, m := range methods { for _, m := range methods {
g.add(m, path, handler, middleware...) g.add(m, path, handler, middleware...)
} }
} }
// Group creates a new sub-group with prefix. // Group creates a new sub-group with prefix and optional sub-group-level middleware.
func (g *Group) Group(prefix string, m ...Middleware) *Group { func (g *Group) Group(prefix string, m ...Middleware) *Group {
m = append(g.middleware, m...) m = append(g.middleware, m...)
return g.echo.Group(g.prefix+prefix, m...) return g.echo.Group(g.prefix+prefix, m...)

View File

@ -7,10 +7,12 @@ import (
) )
type ( type (
// BasicAuthConfig defines config for HTTP basic auth middleware.
BasicAuthConfig struct { BasicAuthConfig struct {
AuthFunc BasicAuthFunc AuthFunc BasicAuthFunc
} }
// BasicAuthFunc defines a function to validate basic auth credentials.
BasicAuthFunc func(string, string) bool BasicAuthFunc func(string, string) bool
) )
@ -19,10 +21,11 @@ const (
) )
var ( var (
// DefaultBasicAuthConfig is the default basic auth middleware config.
DefaultBasicAuthConfig = BasicAuthConfig{} DefaultBasicAuthConfig = BasicAuthConfig{}
) )
// BasicAuth returns an HTTP basic authentication middleware. // BasicAuth returns an HTTP basic auth middleware.
// //
// For valid credentials it calls the next handler. // For valid credentials it calls the next handler.
// For invalid credentials, it sends "401 - Unauthorized" response. // For invalid credentials, it sends "401 - Unauthorized" response.
@ -32,6 +35,8 @@ func BasicAuth(f BasicAuthFunc) echo.MiddlewareFunc {
return BasicAuthFromConfig(c) return BasicAuthFromConfig(c)
} }
// BasicAuthFromConfig returns an HTTP basic auth middleware from config.
// See `BasicAuth()`.
func BasicAuthFromConfig(config BasicAuthConfig) echo.MiddlewareFunc { func BasicAuthFromConfig(config BasicAuthConfig) echo.MiddlewareFunc {
return func(next echo.Handler) echo.Handler { return func(next echo.Handler) echo.Handler {
return echo.HandlerFunc(func(c echo.Context) error { return echo.HandlerFunc(func(c echo.Context) error {

View File

@ -13,7 +13,9 @@ import (
) )
type ( type (
// GzipConfig defines config for gzip middleware.
GzipConfig struct { GzipConfig struct {
// Level is the gzip level.
Level int Level int
} }
@ -24,7 +26,8 @@ type (
) )
var ( var (
defaultGzipConfig = GzipConfig{ // DefaultGzipConfig is the default gzip middleware config.
DefaultGzipConfig = GzipConfig{
Level: gzip.DefaultCompression, Level: gzip.DefaultCompression,
} }
) )
@ -32,10 +35,11 @@ var (
// Gzip returns a middleware which compresses HTTP response using gzip compression // Gzip returns a middleware which compresses HTTP response using gzip compression
// scheme. // scheme.
func Gzip() echo.MiddlewareFunc { func Gzip() echo.MiddlewareFunc {
return GzipFromConfig(defaultGzipConfig) return GzipFromConfig(DefaultGzipConfig)
} }
// GzipFromConfig return `Gzip` middleware from config. // GzipFromConfig return gzip middleware from config.
// See `Gzip()`.
func GzipFromConfig(config GzipConfig) echo.MiddlewareFunc { func GzipFromConfig(config GzipConfig) echo.MiddlewareFunc {
pool := gzipPool(config) pool := gzipPool(config)
scheme := "gzip" scheme := "gzip"

View File

@ -15,26 +15,46 @@ import (
) )
type ( type (
// LoggerConfig defines config for logger middleware.
//
LoggerConfig struct { LoggerConfig struct {
// Format is the log format.
//
// Example "${remote_id} ${status}"
// Available tags:
// - time_rfc3339
// - remote_ip
// - method
// - path
// - status
// - response_time
// - response_size
Format string Format string
// Output is the writer where logs are written. Default is `os.Stdout`.
Output io.Writer Output io.Writer
template *fasttemplate.Template template *fasttemplate.Template
color *color.Color color *color.Color
} }
) )
var ( var (
// DefaultLoggerConfig is the default logger middleware config.
DefaultLoggerConfig = LoggerConfig{ DefaultLoggerConfig = LoggerConfig{
Format: "time=${time_rfc3339}, remote_ip=${remote_ip}, method=${method}, path=${path}, status=${status}, response_time=${response_time}, size=${size}\n", Format: "time=${time_rfc3339}, remote_ip=${remote_ip}, method=${method}, path=${path}, status=${status}, response_time=${response_time}, response_size=${response_size} bytes\n",
color: color.New(), color: color.New(),
Output: os.Stdout, Output: os.Stdout,
} }
) )
// Logger returns a middleware that logs HTTP requests.
func Logger() echo.MiddlewareFunc { func Logger() echo.MiddlewareFunc {
return LoggerFromConfig(DefaultLoggerConfig) return LoggerFromConfig(DefaultLoggerConfig)
} }
// LoggerFromConfig returns a logger middleware from config.
// See `Logger()`.
func LoggerFromConfig(config LoggerConfig) echo.MiddlewareFunc { func LoggerFromConfig(config LoggerConfig) echo.MiddlewareFunc {
config.template = fasttemplate.New(config.Format, "${", "}") config.template = fasttemplate.New(config.Format, "${", "}")
config.color = color.New() config.color = color.New()
@ -94,7 +114,7 @@ func LoggerFromConfig(config LoggerConfig) echo.MiddlewareFunc {
return w.Write([]byte(status)) return w.Write([]byte(status))
case "response_time": case "response_time":
return w.Write([]byte(took.String())) return w.Write([]byte(took.String()))
case "size": case "response_size":
return w.Write([]byte(size)) return w.Write([]byte(size))
default: default:
return w.Write([]byte(fmt.Sprintf("[unknown tag %s]", tag))) return w.Write([]byte(fmt.Sprintf("[unknown tag %s]", tag)))

View File

@ -9,14 +9,22 @@ import (
) )
type ( type (
// RecoverConfig defines config for recover middleware.
RecoverConfig struct { RecoverConfig struct {
// StackSize is the stack size to be printed.
StackSize int StackSize int
// StackAll is flag to format stack traces of all other goroutines into
// buffer after the trace for the current goroutine, or not. Default is true.
StackAll bool StackAll bool
// PrintStack is the flag to print stack or not. Default is true.
PrintStack bool PrintStack bool
} }
) )
var ( var (
// DefaultRecoverConfig is the default recover middleware config.
DefaultRecoverConfig = RecoverConfig{ DefaultRecoverConfig = RecoverConfig{
StackSize: 4 << 10, // 4 KB StackSize: 4 << 10, // 4 KB
StackAll: true, StackAll: true,
@ -24,12 +32,14 @@ var (
} }
) )
// Recover returns a middleware which recovers from panics anywhere in the chain
// and handles the control to the centralized HTTPErrorHandler.
func Recover() echo.MiddlewareFunc { func Recover() echo.MiddlewareFunc {
return RecoverFromConfig(DefaultRecoverConfig) return RecoverFromConfig(DefaultRecoverConfig)
} }
// Recover returns a middleware which recovers from panics anywhere in the chain // RecoverFromConfig returns a recover middleware from config.
// and handles the control to the centralized HTTPErrorHandler. // See `Recover()`.
func RecoverFromConfig(config RecoverConfig) echo.MiddlewareFunc { func RecoverFromConfig(config RecoverConfig) echo.MiddlewareFunc {
return func(next echo.Handler) echo.Handler { return func(next echo.Handler) echo.Handler {
return echo.HandlerFunc(func(c echo.Context) error { return echo.HandlerFunc(func(c echo.Context) error {

View File

@ -9,26 +9,38 @@ import (
) )
type ( type (
// StaticConfig defines config for static middleware.
StaticConfig struct { StaticConfig struct {
// Root is the directory from where the static content is served.
Root string `json:"root"` Root string `json:"root"`
// Index is the index file to be used while serving a directory.
// Default is `index.html`.
Index string `json:"index"` Index string `json:"index"`
// Browse is the flag to list directory or not. Default is false.
Browse bool `json:"browse"` Browse bool `json:"browse"`
} }
) )
var ( var (
// DefaultStaticConfig is the default static middleware config.
DefaultStaticConfig = StaticConfig{ DefaultStaticConfig = StaticConfig{
Index: "index.html", Index: "index.html",
Browse: false, Browse: false,
} }
) )
// Static returns a static middleware to deliever static content from the provided
// root directory.
func Static(root string) echo.MiddlewareFunc { func Static(root string) echo.MiddlewareFunc {
c := DefaultStaticConfig c := DefaultStaticConfig
c.Root = root c.Root = root
return StaticFromConfig(c) return StaticFromConfig(c)
} }
// StaticFromConfig returns a static middleware from config.
// See `Static()`.
func StaticFromConfig(config StaticConfig) echo.MiddlewareFunc { func StaticFromConfig(config StaticConfig) echo.MiddlewareFunc {
return func(next echo.Handler) echo.Handler { return func(next echo.Handler) echo.Handler {
return echo.HandlerFunc(func(c echo.Context) error { return echo.HandlerFunc(func(c echo.Context) error {

View File

@ -1,6 +1,8 @@
package echo package echo
type ( type (
// Router is the registry of all registered routes for an `Echo` instance for
// request matching and URL path parameter parsing.
Router struct { Router struct {
tree *node tree *node
routes []Route routes []Route
@ -37,6 +39,7 @@ const (
akind akind
) )
// NewRouter returns a new Router instance.
func NewRouter(e *Echo) *Router { func NewRouter(e *Echo) *Router {
return &Router{ return &Router{
tree: &node{ tree: &node{
@ -47,6 +50,7 @@ func NewRouter(e *Echo) *Router {
} }
} }
// Handle implements `echo.Middleware` which makes router a middleware.
func (r *Router) Handle(next Handler) Handler { func (r *Router) Handle(next Handler) Handler {
return HandlerFunc(func(c Context) error { return HandlerFunc(func(c Context) error {
method := c.Request().Method() method := c.Request().Method()
@ -56,10 +60,12 @@ func (r *Router) Handle(next Handler) Handler {
}) })
} }
// Priority is super secret.
func (r *Router) Priority() int { func (r *Router) Priority() int {
return 0 return 0
} }
// Add registers a new route for method and path with matching handler.
func (r *Router) Add(method, path string, h Handler, e *Echo) { func (r *Router) Add(method, path string, h Handler, e *Echo) {
ppath := path // Pristine path ppath := path // Pristine path
pnames := []string{} // Param names pnames := []string{} // Param names
@ -280,6 +286,14 @@ func (n *node) check405() HandlerFunc {
return notFoundHandler return notFoundHandler
} }
// Find lookup a handler registed for method and path. It also parses URL for path
// parameters and load them into context.
//
// For performance:
//
// - Get context from `Echo#GetContext()`
// - Reset it `Context#Reset()`
// - Return it `Echo#PutContext()`.
func (r *Router) Find(method, path string, context Context) { func (r *Router) Find(method, path string, context Context) {
ctx := context.Object() ctx := context.Object()
cn := r.tree // Current node as root cn := r.tree // Current node as root