I have an API server written in Go that does some work for different tenants. I have many endpoints that should implements different code based on the tenant that call it, so, for example:
s.GET("/api/orders", a.getOrders)
will call the a.getOrders
handler that after its work will returns the same JSON structure for all the tenants but the implementation to get the data could be different (sometimes for a tenant I need to call another web service, for another one I need to query different DB tables etc...).
I'm thinking to create different packages for every tenant, so I'll have a common
(for the common implementations), tenanta
(for tenant A specific implementations), tenantb
, tenantc
and so on... Now, my question is: which is the best way to handle the "redirection"?
The first (and probably bad) thing I can think is to put a switch in my a.getOrders
handler and parse the tenantID
from the session or the url:
switch tenantID {
case "tenanta":
tenanta.getOrders()
case "tenantb":
tenantb.getOrders()
case "tenantc":
tenantc.getOrders()
default:
common.getOrders()
}
Obviously it could became long pretty fast (at the moment I'd have to handle 20+ tenants). Is there a better way to handle this situation?
Thank you
You can do a tenant interface something like
type tenant interface{
getOrders() Orders
}
Now you can declare any number of tenants that implement this interface
package main
import (
"fmt"
)
type tenant interface {
getOrders()
}
type TenantA struct {
}
func (t TenantA) getOrders() {
fmt.Println("Tenant A")
}
var tenantMap = map[string]tenant{
"T-A": TenantA{},
}
func main() {
fmt.Println("Hello")
teneantTest := "T-A"
curTeneant, ok := tenantMap[teneantTest]
if !ok {
fmt.Println("Not Found")
return
}
curTeneant.getOrders()
}
Now all your tenants follow same interface and this will be compile time testable if all tenants have minimum set of functions defined as well
This will also lead to cleaner abstraction