I understand that it is probably better to pass objects into a service method, but is this still the case if the caller would first have to look up the object before calling the service? And if so, why?
Example
Let's say I have a RoleService, that adds a role to the given user. And let's say the RoleService is called via a web controller or possibly a REST API. The web controller takes the userId and roleId as input from the web request.
Would I be better off using this service method?
public void addRoleToUser(long userId, long roleId) {
User user = userRepository.find(userId);
Role role = userRepository.find(roleId);
user.addRole(role);
}
Or this one? The web controller would obviously need to retrieve both objects before calling the service in this case.
public void addRoleToUser(User user, Role role) {
user.addRole(role);
userRepository.save(user);
}
Whether called via a web controller or a REST API, the incoming request would only be giving the 2 ID's, so you have to do the find() calls somewhere.
You certainly cannot trust the caller to have up-to-date information about the two objects, and it's a waste to transmit the full objects if you're only going to use the ID's anyway.
It is common to have the service API also be the database transaction boundary (service class or method annotated with #Transactional), so it is best to have the service method do the find() and addRole() calls, so they all execute in a single database transaction.
Related
I have a question regarding the transactional boundaries in REST-Controllers using Java/Jakarta EE and JAX-RS.
Given the following controller, when a user is created in the #POST method, first the user is created using a dedicated service. Afterwards, the user´s permissions are stored using a different service.
Both services wrap incoming calls in a container managed transaction.
#Path("/users")
public class UserController {
#Inject
private UserService userService;
#Inject
private PermissionService permissionService;
#POST
public UserDto createUser(UserDto userDto) {
User user = mapToUser(userDto);
User createdUser = userService.create(user);
Permissions perms = mapToPermissions(userDto);
permissionService.createPermissions(createdUser.getId());
return mapToUserDto(createdUser);
}
}
From my point of view, there exists a transactional boundary around userService.create() and a second one around permissionService.createPermissions(). Can you confirm that this is true?
Secondly, if the previous statement is true, and the applications shuts down mid processing, the users permissions might not be persisted. Is this appraoch considered bad practise and should both operations be performed in a single transaction (or in the REST-paradigm under different ressources / endpoints)?
You are correct, there are two transactions, so the first could succeed while the second fails.
A common practice is using a Service Façade pattern. A coarse grained service that sets the transactions boundaries, and call the services to achieve the result.
I've already read lots of topics about it, but still haven't found the better approach.
I have a User. One User may have many Posts. Users and Posts are different microservices. I'm using Spring Boot.
When the front-end call my Posts microservice sending a POST request to /posts/user/1, I need to check if the given userId (1) exists on my Users database. If no, throw an exception telling the front-end that the user doesn't exist. If yes, then insert the given request body as a Post.
The question is: how should I check this information at my backend? We don't want to let this responsibility with the front-end, since javascript is client-side and a malicious user could bypass this check.
Options:
REST communication between the microservices. (Posts microservice call Users microservice asking if the given id exists on his side)
Give Posts microservice access to Users microservice's database
I understand that communication between them will create coupling, but I'm not sure if giving Posts access to Users database is the best option.
Feel free to suggest any options.
You have an option to do interprocess communication between Post and User microservices through RESTful approach.
In case if you just want to check the existence of the resource and don't want any body in response then you should perfer using HEAD http method. Therefore your API endpoint hosted at User microservice will look like -
HEAD user/{userId}
Call this API from Post microservice.
Return 200 / OK if user exist
Return 404 / Not Found if user does not exist
Click here and here to get more details on HEAD method usage and use cases.
For this very particular use case, if you have a security layer, you can(should) make use of user access token, to ensure, that request is processed for the right user, which can be done by validating the token and relying on the fact that if user has token he exist. (As its just not about if user exist)
For any logic other than that, say you want to check if he is allowed to post or other such restrictions it is required to make a call to the user service.
Talking about giving access to the database, it will be against one basic guideline of microservices. Doing so will form a tight coupling between you and user. Its ok to call user service in this case which can decide how to serve this request.
User service on its part should provide ways to answer your queries within the SLA by caching or other mechanisms.
One more thing that you can explore is BFF (Backend for Frontend)
You rightly said you should not expose backend services to frontend or add any logic there, but often frontend pages may not be comfortable in accepting that content on same page is answered via n different back end services and there might be some logic to stitch such queries and thats where you can make use of BFF.
Backend server (in my case node) which take of things like these requiring frontend to make just one call(or less calls) for a given page and at the same time hiding your backend services within.
You're right, you must do a validation at the back end since, I suppose, it's a REST service and requests can be send not only from the UI.
Suppose you have a service implementation:
#Service
class UsersServiceImpl implements UsersService {
private final Users users;
public UsersServiceImpl(Users users) {
this.users = users;
}
#Override
public void addPost(long userId, Post post) {
User user = users.get(userId);
if (user == null) {
throw new UserNonExistent(userId);
}
user.addPost(post);
}
}
where Users is an interface representing a users database and UserNonExistent is a RuntimeException. Then in your controller you can do the following:
#RestController
class UsersController {
private final UsersService usersService;
public UsersController(UsersService usersService) {
this.usersService = usersService;
}
#PostMapping("/posts/user/{userId}")
public void addPostToUser(#PathVariable String userId, #RequestBody Post post) {
usersService.addPost(userId, post);
}
#ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "User does not exist")
#ExceptionHandler({UsersService.UserNonExistent.class})
public void handleUserNonExistentException() {
// Nothing to do
}
}
If the supplied user ID is invalid handleUserNonExistentException() method will be invoked and it will return a BAD REQUEST HTTP status code.
I read about jersey framework for rest service on this page http://howtodoinjava.com/jersey/jersey-restful-client-api-authentication-example/|
And I don't understand one thing.
For instance, when we have
#Path("/users")
public class JerseyService
{
#RolesAllowed("USER")
public String doLogin(#QueryParam("username") String uname,
#QueryParam("password") String result)
It means that user with role user can modify (by this method) ALL the users? Not only himself in the database? I am writing android app and I can imagine situation where someone is using for instance Advanced REST client. He logs on the service and modifying queries in appropriate way and strongly mess my database. For instance write some points to other user or something similar. How can I shut out this situation?
Jersey (and similar Spring Security) operate on Resource Types and Roles.
So, if you permit Role "USER" to operate on resource "Users", you can't block specific user from editing other users with Jersey only.
What you can do is use SecurityContext to get current user, and block dangerous operations if his credentials are different from user being changed.
Here's a good example on SecurityContext:
https://simplapi.wordpress.com/2015/09/19/jersey-jax-rs-securitycontext-in-action/
We are using the Play! framework for HTTP sessions.
tenantId and ipAddress are columns that are common across multiple tables.
When the user is logged in, we are storing the tenantId in HttpContextSession
Whenever we require the ip address of the user we are using Http.Context.current().request().remoteAddress() to store the ip address.
We have huge set of queries written and now we want to save or query in a generic way for tenantId.
All the queries goes via GenericDao
Can we use the following in GenericDao to get tenant Id so that we can append in all queries?
Http.Context.session().get("tenantId");
what would be the best approach to save or retrieve these details?
Thanks.
You don't want your DAO to have to depend on presentation layer things like an HTTP session. I would recommend an abstraction to hide these details.
Create an interface called TenantIdProvider and inject it into your DAO. It would look something like this:
public interface TenantIdProvider
{
String getTenantId();
}
Then create an implementation called HttpSessionTenantIdProvider.
class HttpSessionTenantIdProvider implements TenantIdProvider
{
#Override
public String getTenantId()
{
return Http.Context.session().get("tenantId");
}
}
Now your GenericDAO can have a reference to TenantIdProvider and every query that needs the tenantId can get it through the TenantIdProvider and not have any dependency on the play framework or any other presentation layer that you use.
This really becomes important if you end up having scheduled jobs that run and send notifications or some other task, and they use this DAO. If this DAO depended on an HTTP session it would not be possible. Your job app could create a TenantIdProvider that just returned "system" or something like that.
Lets assume a simple Spring MVC Controller that receives the ID of a domain object. The Controller should call a service that should do something with that domain object.
Where do you "convert" the ID of the domain object into the domain object by loading it from the database? This should not be done by the Controller. So the service method interface has to use accept the ID of the domain object instead of the domain object itself. But the interface of the service would be nicer if it takes the domain object as a parameter.
What are your thoughts about this common use case? How do you solve this?
The controller should pass the id down into the service layer and then get back whatever is needed to render the rest of the HTTP response.
So -
Map<String,Object> doGet (#RequestParam("id") int id) {
return serviceLayer.getStuffByDomainObjectId(id);
}
Anything else is just going to be polluting the web layer, which shouldn't care at all about persistence. The entire purpose of the service layer is to get domain objects and tell them to perform their business logic. So, a database call should reside in the service layer as such -
public Map<String,Object> getStuffByDomainObjectId(int id) {
DomainObject domainObject = dao.getDomainObjectById(id);
domainObject.businessLogicMethod();
return domainObject.map();
}
in a project of mine I used the service layer:
class ProductService {
void removeById(long id);
}
I think this would depend on whether the service is remote or local. As a rule I try to pass IDs where possible to remote services but prefer objects for local ones.
The reasoning behind this is that it reduces network traffic by only sending what is absolutely necessary to remote services and prevents multiple calls to DAOs for local services (although with Hibernate caching this might be a mute point for local services).