Git Product home page Git Product logo

echo's Introduction

Sourcegraph GoDoc Go Report Card GitHub Workflow Status (with event) Codecov Forum Twitter License

Echo

High performance, extensible, minimalist Go web framework.

Help and questions: Github Discussions

Feature Overview

  • Optimized HTTP router which smartly prioritize routes
  • Build robust and scalable RESTful APIs
  • Group APIs
  • Extensible middleware framework
  • Define middleware at root, group or route level
  • Data binding for JSON, XML and form payload
  • Handy functions to send variety of HTTP responses
  • Centralized HTTP error handling
  • Template rendering with any template engine
  • Define your format for the logger
  • Highly customizable
  • Automatic TLS via Let’s Encrypt
  • HTTP/2 support

Sponsors


Click here for more information on sponsorship.

Benchmarks

Date: 2020/11/11
Source: https://github.com/vishr/web-framework-benchmark
Lower is better!

The benchmarks above were run on an Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz

Installation

// go get github.com/labstack/echo/{version}
go get github.com/labstack/echo/v4

Latest version of Echo supports last four Go major releases and might work with older versions.

Example

package main

import (
  "github.com/labstack/echo/v4"
  "github.com/labstack/echo/v4/middleware"
  "net/http"
)

func main() {
  // Echo instance
  e := echo.New()

  // Middleware
  e.Use(middleware.Logger())
  e.Use(middleware.Recover())

  // Routes
  e.GET("/", hello)

  // Start server
  e.Logger.Fatal(e.Start(":1323"))
}

// Handler
func hello(c echo.Context) error {
  return c.String(http.StatusOK, "Hello, World!")
}

Official middleware repositories

Following list of middleware is maintained by Echo team.

Repository Description
github.com/labstack/echo-jwt JWT middleware
github.com/labstack/echo-contrib casbin, gorilla/sessions, jaegertracing, prometheus, pprof, zipkin middlewares

Third-party middleware repositories

Be careful when adding 3rd party middleware. Echo teams does not have time or manpower to guarantee safety and quality of middlewares in this list.

Repository Description
deepmap/oapi-codegen Automatically generate RESTful API documentation with OpenAPI Client and Server Code Generator
github.com/swaggo/echo-swagger Automatically generate RESTful API documentation with Swagger 2.0.
github.com/ziflex/lecho Zerolog logging library wrapper for Echo logger interface.
github.com/brpaz/echozap Uber´s Zap logging library wrapper for Echo logger interface.
github.com/samber/slog-echo Go slog logging library wrapper for Echo logger interface.
github.com/darkweak/souin/plugins/echo HTTP cache system based on Souin to automatically get your endpoints cached. It supports some distributed and non-distributed storage systems depending your needs.
github.com/mikestefanello/pagoda Rapid, easy full-stack web development starter kit built with Echo.
github.com/go-woo/protoc-gen-echo ProtoBuf generate Echo server side code

Please send a PR to add your own library here.

Contribute

Use issues for everything

  • For a small change, just send a PR.
  • For bigger changes open an issue for discussion before sending a PR.
  • PR should have:
    • Test case
    • Documentation
    • Example (If it makes sense)
  • You can also contribute by:
    • Reporting issues
    • Suggesting new features or enhancements
    • Improve/fix documentation

Credits

License

MIT

echo's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

echo's Issues

runtime error: index out of range in router Find

Test code:

package main

import (
        "github.com/labstack/echo"
)

func main() {
        e := echo.New()
        gr := e.Group("/acct/:a")
        gr.Get("/hello", helloHandler)
        e.Run(":4444")
}

func helloHandler(c *echo.Context) {
        c.String(200, "Hello World!")
}

Failure demo:

$ go run main.go &
[1] 27082
$ curl -i http://localhost:4444/acct/abc
2015/04/28 21:22:57 http: panic serving [::1]:46035: runtime error: index out of range
goroutine 5 [running]:
net/http.func·011()
        /big/usr-local/go/src/net/http/server.go:1130 +0xbb
github.com/labstack/echo.(*router).Find(0xc20800a750, 0xc20801e440, 0x3, 0xc20801e444, 0x9, 0xc2080403c0, 0x0, 0x0)
        /home/src/github.com/labstack/echo/router.go:271 +0x43d
github.com/labstack/echo.(*Echo).ServeHTTP(0xc208066000, 0x7f50a9246010, 0xc2080441e0, 0xc208032410)
        /home/src/github.com/labstack/echo/echo.go:294 +0xd0
net/http.serverHandler.ServeHTTP(0xc208042060, 0x7f50a9246010, 0xc2080441e0, 0xc208032410)
        /big/usr-local/go/src/net/http/server.go:1703 +0x19a
net/http.(*conn).serve(0xc208044000)
        /big/usr-local/go/src/net/http/server.go:1204 +0xb57
created by net/http.(*Server).Serve
        /big/usr-local/go/src/net/http/server.go:1751 +0x35e
curl: (52) Empty reply from server
$ curl -i http://localhost:4444/acct/abc/
2015/04/28 21:23:05 http: panic serving [::1]:46036: runtime error: index out of range
goroutine 6 [running]:
net/http.func·011()
        /big/usr-local/go/src/net/http/server.go:1130 +0xbb
github.com/labstack/echo.(*router).Find(0xc20800a750, 0xc20801e520, 0x3, 0xc20801e524, 0xa, 0xc208040500, 0x0, 0x0)
        /home/src/github.com/labstack/echo/router.go:271 +0x43d
github.com/labstack/echo.(*Echo).ServeHTTP(0xc208066000, 0x7f50a9246010, 0xc208044320, 0xc2080325b0)
        /home/src/github.com/labstack/echo/echo.go:294 +0xd0
net/http.serverHandler.ServeHTTP(0xc208042060, 0x7f50a9246010, 0xc208044320, 0xc2080325b0)
        /big/usr-local/go/src/net/http/server.go:1703 +0x19a
net/http.(*conn).serve(0xc208044280)
        /big/usr-local/go/src/net/http/server.go:1204 +0xb57
created by net/http.(*Server).Serve
        /big/usr-local/go/src/net/http/server.go:1751 +0x35e
curl: (52) Empty reply from server

Reverse url

Needs a function that behaves as follows:

e.Get("/users/:id", getUser)
e.URL(getUser, "123")
// => "/users/123"

Mistake in Response section of guide

Serving favicon
echo.Favicon(file string) serves default favicon - GET /favicon.ico. For example, code below serves favicon from file public/favicon.ico.

e.Index("public/favicon.ico")
but need e.Favicon("public/favicon.ico")

support for context.Render

Would be awesome if there was a Render function in context similar to rendering JSON.

Having this RendererFunc interface would allow to use any renderer. Would also be good to have html/template as a default Render. This is similar to how http.Handler and http.HandlerFunc is implemented.

type Renderer interface {
    Render(w http.ResponseWriter, r *http.Request, status int, name string, data interface{})
}

type RendererFunc (w http.ResponseWriter, r *http.Request, status int, name string, data interface{})

func (f RendererFunc) Render(w http.ResponseWriter, r *http.Request, status int, name string, data interface{})

gin use ... interface{} for data. Also should we also pass *http.Request to Render so that it can support content negotiation? If we pass request as nil then we can tell the render to not use content negotiation. Not sure if this is too much of magic. I think content negotiation should be a separate topic.

Here is sample api that could be possible to use. Thoughts?

var e := echo.New()
e.Get("/", func (c *e.Context) {
    c.Render(http.StatusOK, "home", nil)
});

Static handler broken

e.Static() seems to have broken. With a very simple setup to serve an index page and script it no longer works and returns 'not found' for requests that should be served by the static handler. If the e.Index method is commented out then it works so some interaction with how the routes are built up or searched (?)

e.Index("public/index.html")
e.Static("/scripts", "public/scripts")

Decouple router from context usage

Hi,

I'd like to know if there's a way to have the router decoupled from the context.
My use case is that I'd like to use the routing part but without all the other context stuff as I have a custom context already built.
What do you think?

nested resources and named params problem

I have the nested resource routes,
below case will be failed:

    r.Add("GET", "/users/new", func(*Context) {}, nil)
    r.Add("GET", "/users/wen", func(*Context) {}, nil)
    r.Add("GET", "/users/:id", func(*Context) {}, nil)
    r.Add("GET", "/users/:userId/photos/:photoId/comments/:id", func(*Context) {}, nil)
    h, _, _ := r.Find(MethodGET, "/users/233/photos/377/comments/610")
    if h == nil {
        t.Fatal("handle not found")
    }

Tree

└── /users/ has=0, h=<nil>, echo=0, edges=3
    ├── new has=0, h=0x6e8a0, echo=0, edges=0
    ├── wen has=0, h=0x6e8b0, echo=0, edges=0
    └── : has=0, h=<nil>, echo=0, edges=2
        ├── id has=0, h=0x6e8c0, echo=0, edges=0
        └── userId has=0, h=<nil>, echo=0, edges=1
            └── /photos/ has=1, h=<nil>, echo=0, edges=1
                └── :photoId has=0, h=<nil>, echo=0, edges=1
                    └── /comments/ has=1, h=<nil>, echo=0, edges=1
                        └── :id has=0, h=0x6e8d0, echo=0, edges=0

Middleware chain no longer traversed if no route found

73fa05f (https://github.com/labstack/echo/blob/master/echo.go#L323) makes ServeHTTP skip all middlewares if no matching route is found.
This breaks among other things logging of 404 requests with logger middleware, also other middlewares we use like CORS/preflight for options requests do no longer work as we have no matching Options routes. Is this intended (and future) behavior to skip all the middlewares if no matching route is found or is it a bug?

Installation giving error

go version go1.1.2 linux/386

Install by go get github.com/labstack/echo will give below error

# github.com/labstack/echo
/root/go/src/github.com/labstack/echo/context.go:17: invalid recursive type Echo
/root/go/src/github.com/labstack/echo/echo.go:30: undefined: sync.Pool
/root/go/src/github.com/labstack/echo/router.go:305: r.echo.pool undefined (type *Echo has no field or method pool)
/root/go/src/github.com/labstack/echo/router.go:306: cannot assign <T> to _ (type blank) in multiple assignment
/root/go/src/github.com/labstack/echo/router.go:311: r.echo.notFoundHandler undefined (type *Echo has no field or method notFoundHandler)
/root/go/src/github.com/labstack/echo/router.go:313: r.echo.pool undefined (type *Echo has no field or method pool)

Am I missed something?

Echo response that implements http.Hijack

I could just copy that issue: go-martini/martini#45

It's almost the same problem. I am new to go and working on my first small project. I am now almost done and wanted to add websockets.

But I ran into this error websocket: response does not implement http.Hijacker.
I guess I could just rewrite some parts and use Martini or some other framework, but I really started to like Echo.

What do you think? Would it be possible to implement http.Hijack or would this be against the concept of Echo?

As in the Martini issue I would like to say: "please excuse me if this is just nonesense".

Run middleware from middleware chain and context access

Hi guys,

I being use Echo a while and there are two things to discuss with you, I guess it would be a nice have.

  1. If I 'Use' a middleware of mine, is it possible to Run that Middleware for a given route ?
    I mean:
    ...
    echo.Use(middlewareA)
    echo.Use(middlewareB)
    ...
    echo.Get("/home"), func(c *echo.Context) {
    echo.Execute(middlewareA)
    })

echo.Get("/root"), func(c *echo.Context) {
echo.Execute(middlewareB)
})

2 ) It would be cool, when using Echo and external middlewares like negroni, to access Echo Context easily through Echo instance. Since Echo allows wrapping Handlers, we can't use Echo context when needed inside of one of that foreign handlers like:

echo.Get("/user",negroni.New(
    negroni.HandlerFunc(...),
    negroni.HandlerFunc(...),
    ...

))

I hope I'm not saying stupid things totally other way from the project purpose.

Many thanks

Per-route middlewares

This should be an enhancement. It is useful for a few of us out here that a router + middleware would allow per-route middlewares. Say you have a small admin panel and you want to use the http-auth middleware in just that route, but you don't want to apply it to all the other routes declared, currently, looks like it's not possible without something like alice.

Several routers already have the option to mix with certain middleware chainers such as alice or negroni, but they always loose any kind of functionality related to the router, though. For example, you can create an alice chain to a certain handler in httprouter but then, how do you retrieve any named parameter from the url? By passing the handler to alice, you lose the ability to retrieve them in the handler.

Parent middleware is not being applied to sub-groups

Middleware that gets added to a parent route is not being applied to any of the groups created off that route.

Here is a reproducible example:

package main

import (
    "github.com/labstack/echo"
    "github.com/labstack/echo/middleware"
)

func main() {
    e := echo.New()

    e.Use(middleware.Logger)

    g := e.Group("/group")
    g.Get("/search", func(e *echo.Context) {
        e.String(200, "Hello, World!")
    })

    e.Run(":3000")
}

If you were to run that code and the curl http://localhost:3000/group/search you will see that the logging middleware was never triggered.

To get the desire effect one has to change the application to explicitly add the desired middleware to the group as well as the parent:

package main

import (
    "github.com/labstack/echo"
    "github.com/labstack/echo/middleware"
)

func main() {
    e := echo.New()

    e.Use(middleware.Logger)

    g := e.Group("/group")
    g.Use(middleware.Logger)

    g.Get("/search", func(e *echo.Context) {
        e.String(200, "Hello, World!")
    })

    e.Run(":3000")
}

c.Request.Header.Get("Referer") — not works on latest Echo release

This codes works on previous Echo release, but not works on the latest Echo release:

package main

import (
    "github.com/labstack/echo"
    "github.com/snowplow/referer-parser/go"
    "net/http"
)

func main() {
    e := echo.New()

    e.Get("/users", func(c *echo.Context) error {
        refererURL := c.Request.Header.Get("Referer")
        r := refererparser.Parse(refererURL)
        return c.String(http.StatusOK, "The search term is: "+r.SearchTerm)
    })

    e.Run(":4444")
}

Running above codes will give error:

c.Request.Header undefined (type func() *http.Request has no field or method Header)

I failed to find any solution elsewhere.

Help testing middleware

echo currently makes it hard/impossible to initialize a context outside of an actual HTTP request handling (the "response" field is private for example). This makes testing echo middleware tricky as one cannot just mock a context. It would be good if echo exposed a way to create arbitrary contexts. To make things more concrete here is an example of what I'm trying to achieve:

// Create dummy echo.Context with request for tests
// Note: echo makes it impossible to initialize the context response :(
func dummyContext() *echo.Context {
    req, _ := http.NewRequest("POST", "http://example.com", strings.NewReader("foo"))
    ctx := echo.Context{Request: req}
    ctx.String(200, "ok") // BLOWS UP because "response" not initialized
    return &ctx
}

panic: echo => unknown middleware

This morning I pulled down the latest version of echo and when I try to use the new middleware I get the following panic:

panic: echo => unknown middleware

goroutine 1 [running]:
github.com/labstack/echo.wrapMiddleware(0x21e600, 0x364d38, 0x18040d0)
        /Users/markbates/Dropbox/development/gocode/src/github.com/labstack/echo/echo.go:399 +0x35c
github.com/labstack/echo.(*Echo).Use(0xc208054090, 0xc20801f768, 0x1, 0x1)
        /Users/markbates/Dropbox/development/gocode/src/github.com/labstack/echo/echo.go:215 +0xa7
main.main()
        /Users/markbates/Dropbox/Desktop/scraps/scrap.go:10 +0xbf

goroutine 2 [runnable]:
runtime.forcegchelper()
        /usr/local/go/src/runtime/proc.go:90
runtime.goexit()
        /usr/local/go/src/runtime/asm_amd64.s:2232 +0x1

goroutine 3 [runnable]:
runtime.bgsweep()
        /usr/local/go/src/runtime/mgc0.go:82
runtime.goexit()
        /usr/local/go/src/runtime/asm_amd64.s:2232 +0x1

goroutine 4 [runnable]:
runtime.runfinq()
        /usr/local/go/src/runtime/malloc.go:712
runtime.goexit()
        /usr/local/go/src/runtime/asm_amd64.s:2232 +0x1
exit status 2

shell returned 1 

Here is a simple, reproducible (for me at least), bit of code to demonstrate the issue.

package main

import (
    "github.com/labstack/echo"
    "github.com/labstack/echo/middleware"
)

func main() {
    e := echo.New()
    e.Use(middleware.Recover)

    e.Run(":3000")
}

Parameters mixed up between routes

Looks like the parameters and getting mixed up when two routes share the same url, but not the same parameters.

[...]
e.Get("/list", test)
e.Get("/list/:limit", test)
[...]
func test(c *echo.Context) {
fmt.Println(c.Param("limit"))
}

/list -> prints nothing
/list/100 -> prints "100"
/list -> prints "100"

Looks like the limit parameter persists when it shouldn't.

CORS and concurrency

Hi guys,
I've been using echo for a while and its awesome. Congratz. 👍

My bundle has a front-end application that requests data from an API with echo. When the load of requests is too high, sometimes I receive a HTTP 502 error due a >> No 'Access-Control-Allow-Origin' header is present on the requested resource. <<
I use rs/cors middleware as found in the docs.

The headers are well-formed as it is supposed to be.
Between client and Go API there is a cloudflare-nginx server.

What are you're guess about this ? Has Echo any kind of issue regarding concurrent requests ? Like that ones "Response headers were already written" ?

I can reproduce this error if I kill the API service. Response from server is the same. It seems a concurrency problem..

Thank you so much for your help. :)

Param returning empty string

I modified the example project a bit, adding this:

func nextUserId() string {
    var next = nextid;
    nextid += 1;
    return strconv.Itoa(next)
}

func createUser(c *echo.Context) {
    u := new(user)
    u.ID = nextUserId()
    u.Name = c.Param("name")

    if c.Bind(u) {
        users[u.ID] = *u
        c.JSON(http.StatusCreated, u)
    }
}

Except u.Name is for some reason always the empty string. What am I doing wrong? I've looked at the context.go source and it looks like it should work.

NotFoundHandler: panic: echo: unknown handler

The following code fails with panic: echo: unknown handler line 16: e.NotFoundHandler(index)

package main

import (
    "net/http"
    "github.com/labstack/echo"
)

func index(c *echo.Context) {
    c.HTML(http.StatusOK, "<html></html>")
}

func main() {
    e := echo.New()
    e.NotFoundHandler(index)
    e.Run(":1234")
}

I have an older version of echo (54d2f72) and with that the code above works just fine. Could this be a bug or am I missing something?

Example of template sets?

I've tried to load template sets based on documentation but still have no idea how.
Below is example using plain Go. I'm trying to make this using echo and output on browser.

server.go:

package main

import (
    "fmt"
    "os"
    "text/template"
)

type Person struct {
    Name, Age string
}

func main() {

    p := Person{Name: "Mary", Age: "35"} //define an instance with required field

    s1, _ := template.ParseFiles("t1.tmpl", "t2.tmpl") //create a set of template from many files.

    s1.ExecuteTemplate(os.Stdout, "basetemplate", p) //execute basetemplate
    fmt.Println()
    s1.Execute(os.Stdout, p)
}

t1.tmpl:

{{define "basetemplate"}}My name is {{.Name}} and {{template "insideit" .}}years old.{{end}}

t2.tmpl:

{{define "insideit"}}I'm {{.Age}} {{end}}

Output: My name is Mary and I'm 35 years old.

Stable API

Hi. Thank you for this project, it's great. I want to ask when do you plan to release stable api to use in production. Is there a lot things to do which can break backward compatibility?

context doesn't capture "Group" params

The request params that are part of the Group prefix are not captured correctly. Here's a test program:

package main

import (
        "fmt"

        "github.com/labstack/echo"
)

func main() {
        e := echo.New()
        gr := e.Group("/acct/:a")
        gr.Get("/hello", helloHandler)
        e.Run(":4444")
}

func helloHandler(c *echo.Context) {
        c.String(200, fmt.Sprintf("Hello World!\nacct: %s\n%#v\n", c.Param("acct"), *c))
}

and a simple test:

2$ go run main.go &
[1] 1485
tve@h:/home/src/github.com/rightscale/uca/bug2$ curl http://localhost:4444/acct/123/hello
Hello World!
acct:
echo.Context{Request:(*http.Request)(0xc2080325b0), Response:(*echo.response)(0xc20803ac90), pnames:[]string(nil), pvalues:[]string{"123", "", "", "", ""}, store:echo.store{}, echo:(*echo.Echo)(0xc208066080)}

You can see that the 'acct' param is empty, but in the context the value of the param was captured but not the name. Am I doing something wrong?

Catch route with regex

This will allow catching a bad route using regex for situations where route is bad written.
Main route: "/home"
Bad route: "/hhome"

If I could declare a route e.Get("/* ") or e.Get(" [a-zA-Z0-9]+ ") I could work over the response Header.

Many thanks

Add interface that unifies *echo.Router and *echo.Group

Since Groups were recently split from the main echo.Router class, it's difficult for my application to work on these two classes simultaneously: 1) root level router (defined as *echo.Router), or 2) a sub-group (defined as *echo.Group)

It should be simple to make an interface that covers the common parts of both APIs, then calling applications could just expect that to be passed in instead.

Does this make sense?

Middleware documentation/examples

Any documentation/advice on creating own middleware for Echo? There are things that I see to be different to other frameworks - no need to pass control to the next middleware in the chain for one?

I'm writing a simple basicauth middleware - it partially works but returns and flow passes to the route handler's function, so I get double output:- a 401 then the route's func handler response. How should I approach it to halt in the middleware and serve just the 401 Unauthorized?

Full disclosure: I'm fairly new to Go, so I'm still bit of a hacker and apologies if what I've asked seems basic or approached in the wrong way.

Router cannot find a handler

I'd try bolt as router, and encountered unexpected behavior to me.

Code:

r := New().Router
r.Add("GET", "/alice", func(c *Context) {})
r.Add("GET", "/:name", func(c *Context) {})
h, _, _ := r.Find("GET", "/bob")
if h == nil {
    fmt.Printf("handler not found\n")
    return
}

Output:

handler not found

Is this the intended behavior?

Allow log warning to be controlled for Response.committed

if r.committed {

I'm trying to stream a JSON response, which works just fine but I get warning messages logged.

For example:

func streamTest(c *echo.Context) *echo.HTTPError {
i := 0
    for {
        i++
        c.JSON(http.StatusOK, &SomeStruct{Name: fmt.Sprintf("John Doe #%d", cpt)})
        c.Response.Writer.(http.Flusher).Flush()
        // send every 3 seconds
        time.Sleep(time.Duration(3) * time.Second)
    }
}

If there was a way to set something to ignore warnings or disable logging or something that'd be great. Thanks!

Custom context supplied with a method

Hi,

I want to supply some application wide context to my echo handlers by making my handlers a method on AppContext. A struct containing some pointers to storage engines etc. As an example:

// FindOne returns a single thread in the API
func (a *AppContext) FindOne(c *echo.Context) error {
    id := c.P(0)
    thread, err := a.ThreadStorage.FindOne(id)
    if err != nil {
        return c.JSON(http.StatusNotFound, nil)
    }
    return c.JSON(http.StatusOK, thread)
}

Now, the strange thing is that if I place this method in my main.go, everything works fine. However, as soon as I place it in a separate file (same package) it gives me the error panic: echo: unknown handler as seen in echo.go.

Is this a completely wrong use case or should the method satisfy as a handler for Echo?

/users/new and /users/:id doesn't seem to work correctly

If I have this program. It does navigate to /user/new route but says not found for /users/:id route.

package main

import "github.com/labstack/echo"

func main() {
    app := echo.New()

    app.Get("/users/new", func(c *echo.Context) {
        c.String(200, "/users/new")
    })

    app.Get("/users/:id", func(c *echo.Context) {
        c.String(200, "/users/:id")
    })

    app.Run(":3000")
}

For express to work it needs to be in order but for hapijs it can be any order and it will automatically match with the stricter first.

why HTTPError as return from HandlerFunc?

Why did you make the breaking change to require HandlerFunc to return *HTTPError instead of error? Why not make HTTPError implement the Error() method and then it can be passed as error? This way a handler could either return a plain error or an HTTPError.

`*` doesn't match an empty string

I would expect * in a route to match any string, including the empty string. It doesn't, though:

package main

import (
    "fmt"

    "github.com/labstack/echo"
)

func okay(context *echo.Context) {
    context.String(200, "")
}

func main() {
    e := echo.New()
    e.Post("members*", okay)
    handler, ech := e.Router.Find("POST", "members", nil)
    fmt.Printf("%+v %+v\n", handler, ech)
}

Prints <nil>, <nil>.

Documentation Generation

I'm thinking of using echo for a large project and one of the requirements will be extensive documentation, it would be nice to automatically keep the code and docs in sync with something like:

e := echo.New()
...
//with cli flag, or even via another REST endpoint
if generate {
  //json.MarshalIndent internal echo structures (fn name, methods, urls, params, middleware, etc.)
  b := e.GenerateSpec()
  //display
  os.Stdout.Write(b)
  //or, send to documentation server
  http.Post("...", "application/json", &bytes.NewBuffer(b))
}

Then the user could convert the structures into:

Thoughts?

Router Match Rules

The router maps below:

r.Add('GET', '/users/:id', func(c *Context) {})
r.Add('GET', '/photos/:id', func(c *Context) {})
r.Add('GET', '/:c/:a', func(c *Context) {})

h, _ := r.Find('GET', '/controller/action')
// => h == nil

I think the /controller/action path should be matched, but not.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.