Matheus
Matheus

Reputation: 3370

Data validation across different microservices

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:

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.

Upvotes: 15

Views: 7219

Answers (3)

Anunay
Anunay

Reputation: 1893

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.

Upvotes: 4

Boris
Boris

Reputation: 24453

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.

Upvotes: -2

Amolpskamble
Amolpskamble

Reputation: 978

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.

Upvotes: 8

Related Questions