NewService issues in go-res

My Premise: I’d really like to keep my services as small as possible, grouped by service name

I thought i would be able to create multiple services with the same name e.g. s := res.NewService("users"), where one service handles creating, listing and updating a user and another service handles things like grouping, accounts etc… with the goal of keeping them small and manageable rather than ever growing macro services.

When i tried to create a 2nd service with the same name I get errors about conflicting service names, is that expected?

e.g.
Service 1: user handles identity.create, identity.$id, identity.set
Service 2: user handles group.create, group.$id, group.set

what I’ve had to do is switch things around a bit, which while it does work, it doesn’t really feel right.
this is how i have had to do it, so far, but Im now realizing that this is going to result in the same problem…

Sevice 1: identity handles user.create, user.$id, user.set
Service 2: group handles user.create, user.$id, user.set <- these are creating groups for the users which don’t really communicate as well as they should

while this seems like a good solution it becomes problematic when I need another service for non user group stuff, like creating nested groups, managing group permissions etc…

another example.

lets say Im consuming another services API, facebook for example, if I call the service facebook then Im going to have to put every single service handler in that 1 service or get creative with the service names.

e.g. facebook-friends, facebook-groups, facebook-activities etc… which I guess is another solution but I can’t help but wonder why I can just have multiple services with the same service name that manage different handlers.

if I were just using nats native subscriptions that’s how I would do it, but something in go-res is tell me no (it looks like its coming from mux?). which is causing me to have weird service names like password which handles user authentication. I would much rather have 1 micro service called auth which handles user authentication and another service called auth which handles company authentication or SAML authentication.

Anyways I hope this doesn’t sound too negative, I didn’t intend it to be negative, I’m just trying to set patterns and figure out the best practice for doing it. how does the saying go,

“There are only two hard things in Computer Science: cache invalidation and naming things.”

I surely appreciate small services :grin: . So I approve of this effort!

And Resgate will not limit you in this, so I am not sure what conflict error you saw. There is no such check in the code base. This is fully OK code:

func main() {
	// Service 1, handling identity
	s1 := res.NewService("user")
	s1.Handle("identity.$id",
		IdentityHandler{},
	)
	go s1.ListenAndServe("nats://localhost:4222")

	// Service 2, handling group
	s2 := res.NewService("user")
	s2.Handle("group.$id",
		GroupHandler{},
	)
	s2.ListenAndServe("nats://localhost:4222")
}

What did your error say?
You will (and should) get an error if you try to add two handlers with identical resource patterns to the same service. But other than that, you should be free to go.

I see the question as positive :slight_smile: . Trying to solve things, and asking how to do it.

/Samuel

I knew i should have recorded the error, I’ll reproduce and report back soon

1 Like

ok I’ve been playing around with this and have some more details

e.g.

service 1: user.identity.create - works great

when service 2: user.group.list is registered it doesn’t receive messages until user.identity is turned off

to reproduce I created 2 completely separate services, each in their own docker containers and connected to the same resgate instance

the access handler of the 2nd service seems to receive messages so it appears to just be the methods which appear to not be found.

I’m getting a system.notFound in the browser

I am not entirely sure (without looking at the trace logs from resgate). But I have a guess.

When you use 2 services that shares namespace (user), you should explicitly set which resources they own (that they handle).

This is done with the func (*Service) SetOwnedResources method:

s := res.NewService("user")
s.SetOwnedResources(
	[]string{"user.identity", "user.identity.>"}, // Resources they handle (with wildcard)
	[]string{"user.identity", "user.identity.>"}, // Access they handle (with wildcard)
)

(Access requests can be handled by a completely different resource, if you wish to centralize access control).

By default, go-res will assume it owns all resources belonging to the service name (in your case `“user”, “user.>”)

Hope that helps :slight_smile:
/Samuel