Description

I am building a multi tenant API where tenants are allowed to have a path in their base. For example: tenant1.base = tenant-1.com/ & tenant2.base = tenant-2.com/some-api/

I was hoping there was some way to add wildcards at the start of a route but this doesn't seem to be the case.

How can I implement my requirements ?

I was thinking of maybe running some code before the route is resolved to its handlers to internally reroute the request to a diff route, but I can't seem to find how to do this or if this is even possible.

I have tried using r.HandleContext() as such: (example code for testing)

server.Use(func(c *gin.Context) {
    if (c.Request.URL.Path != "/status") {
        c.Request.URL.Path = "/status"
        server.HandleContext(c);
    } else {
        c.Next();
    }
});

But this lead to 2 requests being handled and the response body being double of what it should be. Also, I do not want to start over the whole request flow, as in: the middleware that already ran should not be executed again.

My temporary ugly solution is: (this however doesn't work for me /openapi endpoint wich is served using r.StaticFile(...) and I expect I will run into some errors with some paths possibly matching multiple routes)

func registerRoute(server *gin.Engine, r string, handler gin.HandlerFunc) {
    server.GET(r, handler);
    server.GET("/:any" + r, handler);
    server.GET("/:any/:any" + r, handler);
    ...
}

Environment

  • go version: 1.20
  • gin version (or commit ref): 1.9.1
  • operating system: MacOS 13.4.1

Comment From: BelgianNoise

I managed to get HandleContext() to work by adding c.Abort(). Current code:

server.Use(func(c *gin.Context) {
    if (c.FullPath() == "") {
        multiTenantPaths := []string{
            "/status",
            "/openapi",
        };
        for _, path := range multiTenantPaths {
            match, e := regexp.MatchString(".+"+path, c.Request.URL.Path);
            if (match && e == nil) {
                c.Request.Header.Set("X-Original-Path", c.Request.URL.Path);
                c.Request.URL.Path = path;
                server.HandleContext(c);
                c.Abort();
            }
        }
    }
    c.Next();
});
server.Use(func(c *gin.Context) {
    originalPath := c.Request.Header.Get("X-Original-Path");
    if (originalPath != "") {
        c.Request.URL.Path = originalPath;
    }
    c.Next();
});

Seems to work okay for now. Still interested in a better solution tho.