Description

I have an api group, and I want it to have a different 404 handler than the main group. I want to do something like this:

r.Group("/a").NoRoute(func(ctx *gin.Context) {
    // manage no route for /a
})
r.Group("/b").NoRoute(func(ctx *gin.Context) {
    // manage no route for /b
})

But it is not possible with current RouterGroup

I don't want use workaround explained here #2999, since I want to compose handler func with ctx.Next(), ctx.Abort() and other complex things.

Comment From: JimChenWYU

Base on the current structure of gin, I dont think gin can solve your problem.

Just group by prefix

Gin Different 404 handler for different group

All routes will be registered to engine.Handlers

Gin Different 404 handler for different group Gin Different 404 handler for different group

So only provides the global 404 handler

Gin Different 404 handler for different group

Comment From: jerome-laforge

Thanks for this confirmation @JimChenWYU

Comment From: jerome-laforge

I won't use gin.NoRoute(), instead of I will use this workaround:

func noRoute(r *gin.Engine, basePath string, hfs ...gin.HandlerFunc) {
    r.Any(basePath+"/:path", hfs...)
}
...
noRoute(r, "/a", func(ctx *gin.Context) {
    // manage no route for /a/*
})
noRoute(r, "/b", func(ctx *gin.Context) {
    // manage no route for /b/*
})

Thx again @JimChenWYU for your support

Comment From: jerome-laforge

Another workaround that is more robust but also more weird, it is use 2 gin.Engine for each group (the global mergeEngine & the specific engineOnlyForA or engineOnlyForB)

mergeEngine := gin.New()

// manage all routes + noroutes for /a/*
{
    engineOnlyForA := gin.New()
    engineOnlyForA.GET("/a/bc", func(c *gin.Context) {
        // do stuff for /a/bc
    })
    engineOnlyForA.GET("/a/de", func(c *gin.Context) {
        // do stuff for /a/de
    })
    engineOnlyForA.NoRoute(func(c *gin.Context) {
        // no route for /a/*
    })

    mergeEngine.Any("/a/*path", gin.WrapH(engineOnlyForA))
}

// manage all routes + noroutes for /b/* 
{
    engineOnlyForB := gin.New()
    engineOnlyForB.GET("/b/cd", func(c *gin.Context) {
        // do stuff for /b/cd
    })
    engineOnlyForB.GET("/b/ef", func(c *gin.Context) {
        // do stuff for /b/ef
    })
    engineOnlyForB.NoRoute(func(c *gin.Context) {
        // no route for /b/*
    })

    mergeEngine.Any("/b/*path", gin.WrapH(engineOnlyForB))
}