Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create separate route groups with different middleware in Goji (Golang)?

Tags:

go

goji

I am using Goji (https://github.com/zenazn/goji) and would like to define groups of routes that have their own middleware. For example, all paths under /company should use an LDAP authentication and have a middleware defined to do this. All paths under /external use a different type of authentication so they have a different middleware definition. But this is a single application served on the same port, so I don't want to create separate web services altogether -- just the paths (and some specific routes) may use different middleware.

All the examples I've seen with Goji are using a single set of middleware for all routes, so I am not sure how to accomplish this in a clean way. Additionally it would be nice if I could specify a base path for all routes within a route group, similar to how I've seen in some other routing frameworks.

Am I missing this functionality in the Goji library (or net/http by extension) that allows me to group routes together and have each group use its own middleware stack?

What I would like to achieve is something like this (psedocode):

// Use an LDAP authenticator for:
// GET /company/employees
// and
// POST /company/records
companyGroup = &RouteGroup{"basePath": "/company"}
companyGroup.Use(LDAPAuthenticator)
companyGroup.Add(goji.Get("/employees", Employees.ListAll))
companyGroup.Add(goji.Post("/records", Records.Create))

// Use a special external user authenticator for: GET /external/products
externalGroup = &RouteGroup{"basePath": "/external"}
externalGroup.Use(ExternalUserAuthenticator)
externalGroup.Add(goji.Get("/products", Products.ListAll))
like image 372
william Avatar asked Dec 06 '22 00:12

william


2 Answers

You should be able to solve your problem with something like this:

// Use an LDAP authenticator 
companyGroup := web.New()
companyGroup.Use(LDAPAuthenticator)
companyGroup.Get("/company/employees", Employees.ListAll)
companyGroup.Post("/company/records", Records.Create)
goji.Handle("/company/*", companyGroup)

// Use a special external user authenticator for: GET /external/products
externalGroup := web.New()
externalGroup.Use(ExternalUserAuthenticator)
externalGroup.Get("/external/products", Products.ListAll)
goji.Handle("/external/*", externalGroup)

You need to give each group its own web. Just keep in mind you need to specify the full path within the group members.

like image 87
guregu Avatar answered Apr 26 '23 00:04

guregu


Greg R's response sums it up nicely (and is the correct answer), but I'll show you an approach that lets you 'avoid' (cheat!) having to specify the full route.

Part of why Goji's router is fast is that it compiles everything on start-up, so routes need to know their full path - but we can provide that at a higher level by writing functions that take a "prefix" and return a router.

package main

import (
    "github.com/zenazn/goji/graceful"
    "github.com/zenazn/goji/web"
    "net/http"
)

func GetCompanyRoutes(prefix string) http.Handler {
    comp := web.New()
    comp.Use(SomeMiddleware)
    comp.Get(prefix+"/products", Products.ListAll)
    comp.Get(prefix+"/product/:id", Products.JustOne)
    comp.Get(prefix+"/product/delete", Products.Delete)

    return comp
}

// ... and a GetExternalRoutes with the same pattern

func main() {
    r := web.New()

    r.Get("/", IndexHandler)
    r.Handle("/company/*", GetCompanyRoutes("/company"))
    r.Handle("/external/*", GetExternalRoutes("/external"))

    graceful.Serve("localhost:8000", r)
}

Since this is all compiled at startup, there's no concern about the string concatenation impacting routing performance.

I use a similar pattern as my handlers reside in a separate package - my package main just calls r.Handle("/admin/*", handlers.GetAdminRoutes("/admin"). If I wanted to change the URL structure at a later date, I can just change it to r.Handle("/newadminlocation/*", handlers.GetAdminRoutes("/newadminlocation") instead.

like image 44
elithrar Avatar answered Apr 26 '23 01:04

elithrar