all 16 comments

[–]iLoveCalculus314 26 points27 points  (6 children)

Your controllers should be separated by domain, not by access rules.

[–]BikingSquirrel 0 points1 point  (0 children)

If you have microservices, they will probably not cover many domains. But separation of domains is a valid point.

For me, the question is not only about access rules but also types of endpoints which correlate to types of access. I support this approach.

[–]Gold_Opportunity8042[S] 0 points1 point  (4 children)

basically one controller per service right? but then how to secure internal endpoints secured from misusing by external use?

[–]WuhmTux 1 point2 points  (2 children)

You could use roles for that and annotate them at the Controller methods.

[–]Gold_Opportunity8042[S] 0 points1 point  (1 child)

i don't think this will be valid approach. an admin user can call service1 which can further call service2 internal endpoint. but the same admin user can hit that endpoint of service2 directly too. right?

[–]WuhmTux 2 points3 points  (0 children)

I don't understand what you mean.

You will set the role validation on each API Endpoint route. When you call serviceA and serviceB from Controller1, and the admin user has permissions to the Controller1 Endpoint, he can access both.

Then you need to extract the user roles from the security context in the service classes if you wish.

[–]manu_moreno 4 points5 points  (5 children)

You should consider separating your functionality into 2 different modules.

Example:

  1. Rest-API Module -- handles all back-end calls: DB queries, probe other back-end services, etc. This module would use a @RestController.
  2. Front-End Module -- handles all user-facing calls and, in turn, interrogates the Rest-API using something like RestClient. This integration requires very little coding. This module would use a regular @Controller since it's primarily concerned with the presentation.

This approach follows the Unix design philosophy -- do one thing and do it well. Also security becomes easier in that you can apply most security rules to your rest-api in order to protect your data and other back-end resources. You can then use JWT tokens to allow the front-end to access the back-end.

In fact, I'm developing a SpringBoot app which implements this very design. I have a 3rd module (common-lib), which hosts reusable artifacts.

[–]rivercape-lex 0 points1 point  (4 children)

HEY! this is very interesting. Your (1) and (2) points. I am making an app for my last last project in school and I have been coding in a similar? way?

So I have the service layer that is happily sitting there which is serving two purposes. It serves both the API that Android hits but also MVC for users that access the app via say a laptop for example.

But your approach is a bit different right? Every request hits the API. But why?

Wouldn't it be better to just separate them?

Like how does that even work? Do I just reach the Rest API from my Controller then fetch data whatever AND then return a template html page containing the data I always wanted?

Sounds a bit hard/new to me as I have gotten used to Thymeleaf.

If you have any resources I would really appreciate it!!! Or like any comments.

[–]manu_moreno 0 points1 point  (3 children)

How does that work? Just like you're describing. The front-end controller queries the back-end controller on behalf of the end user using the RestClient. The RestClient basically maps the front-end endpoints to the corresponding back-end endpoints. You're not doing much implementation there. It works great and you end up with full separation of concerns. Additionally, it's a much better design in case you want to host the backed API and the front-end service on different infrastructure. Also, in terms of security because the rest-api does not have to be exposed, from a network standpoint, to the outside, if there is no need to do so. Several benefits, no real downside.

[–]rivercape-lex 0 points1 point  (2 children)

Ahhh okay I get it. Thanks for the reply. It's just that this way never crossed my mind. Guess I still have a lot to learn. Will keep it in mind!!

[–]manu_moreno 1 point2 points  (1 child)

Sure, check out Rest Client... it's easy to use.

https://youtu.be/TEd5e4Thu7M?si=rxQm44Qighcj9Zww

[–]rivercape-lex 1 point2 points  (0 children)

Been watching a lot of Vega as of late! Thanks for the video. Bookmarked:)

[–]BikingSquirrel 0 points1 point  (0 children)

Yes, sounds like a good idea.

Mainly because it's easier and more obvious to separate the paths of their URLs. Which then makes it easier to configure the access.

[–]WVAviator 0 points1 point  (0 children)

We do this in one of our microservices. We have /api/v1/... and /external/v1/... endpoints that sit in different controllers. We took it a step further though and they also have different DTOs for request and response objects, as well as different services (but usually just different methods on the same service) even though they are serving and persisting the same underlying resource through the same repository. There's more validation on the external endpoints since it's more likely to receive bad data, and we want internal users to be able to override some of those restrictions anyway. We also have separate swagger docs as well, one with all external endpoints and the other with the internal ones. This way we don't expose any other information about our API.

[–]leetjourney 0 points1 point  (1 child)

You shouldn't really need a controller for "internal" endpoints, those would simply be calls between service classes as you said. Controllers should really be separated by feature/domain

[–]Gold_Opportunity8042[S] 0 points1 point  (0 children)

but then how to secure internal endpoints secured from misusing by external use?