Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can add NoRoute(h HandlerFunc, m ...MiddlewareFunc) to Group and Echo? #856

Closed
mei-rune opened this issue Feb 19, 2017 · 10 comments
Closed

Comments

@mei-rune
Copy link

mei-rune commented Feb 19, 2017

Description

Can add NoRoute(h HandlerFunc, m ...MiddlewareFunc) to Group and Echo?
There are NoRoute() in https://github.com/gin-gonic/gin.

NoRoute() usage:

package mai

func main() {
	engine := echo.New()
	engine.Use(middleware.Logger())
	engine.Use(middleware.Recover())
       engine.NoRoute(http.DefaultServeMux)


       q := engine.Group("/query")
       q.GET("/hello", func(ctx echo.Context) error {
           ctx.String(http.StatusOK "hi!")
       })
       q.NoRoute(func(ctx echo.Context) error {
           ctx.String(http.StatusNotFound, "not found with prefix is /query")
       })
}
@vishr vishr self-assigned this Feb 19, 2017
@vishr vishr added the question label Feb 19, 2017
@vishr
Copy link
Member

vishr commented Feb 19, 2017

What is the function of NoRoute? If you are looking for handling route not found requests look at https://echo.labstack.com/guide/error-handling. Echo#DefaultErrorHandler captures all the errors and it can also be customized.

@mei-rune
Copy link
Author

mei-rune commented Feb 20, 2017

NoRoute() have more advantage than ErrorHandler!

  1. NoRoute() can add middleware handler, ErrorHandler can't.
  2. NoRoute() more user-friendly。

NoRoute() example as follow:

package mai

func main() {
	engine := echo.New()
	engine.Use(middleware.Logger())
	engine.Use(middleware.Recover())
       engine.NoRoute(http.DefaultServeMux)


       q := engine.Group("/query", authQuery) // authQueryis middleware handler,
       q.GET("/hello", func(ctx echo.Context) error {
           return ctx.String(http.StatusOK "hi!")
       })
       q.NoRoute(func(ctx echo.Context) error {
           return ctx.JSON(http.StatusOK, xxxx)
       }, auth) // auth is middleware


       cfg := engine.Group("/config", authConfig) // authConfig is middleware handler,
       cfg.GET("/hello", func(ctx echo.Context) error {
           return ctx.String(http.StatusOK "hi!")
       })
       cfg.NoRoute(func(ctx echo.Context) error {
           return  ctx.JSON(http.StatusOK, xxxx)
       })
}

ErrorHandler() example as follow:

package mai

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


       q := engine.Group("/query", auth) // auth is middleware handler,
       q.GET("/hello", func(ctx echo.Context) error {
           return ctx.String(http.StatusOK "hi!")
       })
       cfg := engine.Group("/config", auth) // auth is middleware handler,
       cfg.GET("/hello", func(ctx echo.Context) error {
           return ctx.String(http.StatusOK "hi!")
       })


       engine.ErrorHandler = func(e error, ctx Context) error {
          if e == echo.ErrNotFound {
               if strings.Contains(ctx.Request().URL.Path, "/query") {

                    //  hack! it isn't standard for run handler
                    authQuery(ctx, func(ctx Context) {
                        return ctx.JSON(http.StatusOK, queryxxxx)
                    } )
                 return nil
               } else if strings.Contains(ctx.Request().URL.Path, "/config") {

                    //  hack! it isn't standard for run handler
                    authConfig(ctx, func(ctx Context) {
                        return ctx.JSON(http.StatusOK, configxxxx)
                    } )
                   return nil
               }
              http.DefaultServeMux.ServeHttp(ctx.Response(), ctx.Request())
              return nil
          }
      }
}

@bxcodec
Copy link

bxcodec commented Aug 14, 2017

If you looking for example, you could see what gin does here http://godoc.org/github.com/gin-gonic/gin#Engine.NoRoute

It will return default 404 for un-registered routes 🙄

@stale
Copy link

stale bot commented Nov 30, 2018

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label Nov 30, 2018
@stale stale bot closed this as completed Dec 7, 2018
@mei-rune mei-rune mentioned this issue Mar 11, 2019
@whoiscarlo
Copy link

How come this was never added? I'm confused on how others use Angular with Echo when there are several resources file Angular ask at initialization. I tried doing this hack:

func Routes(e *echo.Echo) {
	e.GET("/", getWebApp)
	e.Any("/*", getWebApp)
}

func getWebApp(e echo.Context) error {
	// Get file name that is being requested
	_, file := path.Split(e.Request().RequestURI)
	fmt.Println("file", file)

	// Get file extension
	ext := filepath.Ext(file)
	fmt.Println("ext", ext)

	if file == "" || ext == "" {
		return e.File("../website/index.html")
	} else {
		newFile := path.Join("../website/", file)
		fmt.Println("newFile", newFile)

		// Response with a javascript heading if .js is being servered
		if ext == ".js" {
			e.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJavaScript)
		}

		return e.File(newFile)
	}
}

but then that capture all requests to any other paths (e.g something.com/this-path/) even if there is a e.group assigned.

@aldas
Copy link
Contributor

aldas commented Mar 20, 2022

If you want to use single page applications. Route all non "rest" requests to static assets - then Static middleware is something that you should use.

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

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

	e.Use(middleware.StaticWithConfig(middleware.StaticConfig{
		Root:  "./website",
		Index: "index.html",
		// Enable HTML5 mode by forwarding all not-found requests to root so that
		// SPA (single-page application) can handle the routing.
		HTML5: true, 
	}))

	api := e.Group("/api")
	api.GET("/pairs", func(c echo.Context) error {
		return c.JSON(http.StatusOK, map[string]string{"key": "value"})
	})

	if err := e.Start(":8080"); err != http.ErrServerClosed {
		log.Fatal(err)
	}
}

@aldas
Copy link
Contributor

aldas commented Mar 20, 2022

Note: there are plenty of different ways to replace 404. ErrorHandler is just one place

You can create Any route doing the same

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

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

	e.Any("/*", func(c echo.Context) error {
		return c.JSON(http.StatusNotFound, "NOT FOUND MESSAGE")
	})

	if err := e.Start(":8080"); err != http.ErrServerClosed {
		log.Fatal(err)
	}
}

You can even replace default 404 function as it is public

func main() {
	// or replace default NotFoundHandler
	echo.NotFoundHandler = func(c echo.Context) error {
		return c.JSON(http.StatusNotFound, "custom message")
	}

	e := echo.New()

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

	if err := e.Start(":8080"); err != http.ErrServerClosed {
		log.Fatal(err)
	}
}

@mei-rune
Copy link
Author

@aldas

       cfg := engine.Group("/config", authConfig) // authConfig is middleware handler
       ........
       cfg.NoRoute(func(ctx echo.Context) error {
           return  ctx.JSON(http.StatusOK, xxxx)
       })
       
       
       xxx := engine.Group("/xxxx", authConfig) // authConfig is middleware handler
       ........
       xxxx.NoRoute(func(ctx echo.Context) error {
           return  ctx.JSON(http.StatusOK, xxxx)
       })

@whoiscarlo
Copy link

@aldas Thank you for that solution

@mei-rune
Copy link
Author

#2217

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants