Creating User Service

We will now start implementing our first service, User Service. In the beginning, we will only implement a method that returns a User object for a given token string. If a user can't be found in the repository, the method will return UserNotFoundException, which should be caught by the AWS Lambda function and translated into the decline policy.

We can start implementing our User Service in the way we already know. Let's add our new module's name to the settings.gradle file using a simple echo command:

    $ echo "include 'services-user'" >> settings.gradle

Create the required folder using the following command:

    $ mkdir -p services-user/src/main/java/com/serverlessbook/services/user 

It is a good time to create a User object for our project now. The User class will have the ID, email, and username properties, and it will be a POJO. We can create the User object under a new package named domain:

    $ mkdir -p services-user/src/main/java/com/
serverlessbook/services/user/domain

And we can implement the class as follows:

package com.serverlessbook.services.user.domain; 
public class User { 
 
  private int id;  
  private String username; 
  private String email; 
  public int getId() { 
    return id; 
  } 
 
  public User withId(int id) { 
    this.id = id; 
    return this; 
  } 
 
  public String getUsername() { 
    return username; 
  } 
 
  public User withUsername(String username) { 
    this.username = username; 
    return this; 
  } 
 
  public String getEmail() { 
    return email; 
  } 
         
  public User withEmail(String email) { 
    this.email = email; 
    return this; 
  } 
} 

We can now create the interface for UserService. Note that UserService will be just an interface and other consuming services-in our case, our AWS Lambda function-will be aware of the interface only. However, the Dependency Injection framework will be injecting a concrete implementation of the interface. In this way, you can switch a different implementation of the same service interface, and you can even mock the interface to produce a fake service for unit testing purposes. Preferring interface abstraction over concrete implementations is called Dependency Inversion Principle and stands for "D" of SOLID principles.

Then, we can create the UserService class in our new module:

package com.serverlessbook.services.user; 
import com.serverlessbook.services.user.domain.User; 
public interface UserService { 
  User getUserByToken(String token) throws UserNotFoundException; 
} 

We must also implement a basic exception class for users not found, and it can also go to the same package:

package com.serverlessbook.services.user; 
public class UserNotFoundException extends Exception { 
  private static final long serialVersionUID = -3235669501483817417L; 
} 

Now we can create the implementation of UserService. In the beginning, our concrete method will throw UserNotFoundException:

package com.serverlessbook.services.user; 
import com.serverlessbook.services.user.domain.User; 
public class UserServiceImpl implements UserService { 
   @Override 
   public User getUserByToken(String token) throws UserNotFoundException { 
      throw new UserNotFoundException(); 
   } 
} 

We keep it simple for now because without the data layer, it does not make any sense to write more business logic. However, at this stage, we are ready to consume this service in our AWS Lambda and see it in action.