It is now time to create our second real Lambda function: User Registration Lambda. Create the required directory structure and add the lambda-userregistration module to the settings.gradle file so that Gradle accepts it as a module:
$ mkdir -p lambda-userregistration/src/main/java/
com/serverlessbook/lambda/userregistration $ echo "include 'lambda-userregistration " >> settings.gradle
We have to create a build.gradle file for this module and dependencies for the user service and Guice, which is pretty much the same as the authorizer Lambda. Let's create the file first:
$ touch lambda-userregistration/build.gradle
Then, let's paste this block:
dependencies {
compile group: 'com.google.inject', name: 'guice', version: guiceVersion compile project(':services-user') }
Now we can create the handler class:
public class Handler extends LambdaHandler<Handler.RegistrationInput,
Handler.RegistrationOutput> { public static class RegistrationInput {
@JsonProperty("username")
private String username;
@JsonProperty("email")
private String email;
public String getUsername() {
return username;
}
public String getEmail() {
return email;
}
}
public static class RegistrationOutput {
private final String resourceUrl;
public RegistrationOutput(User user) {
resourceUrl = "/user/" + user.getId();
}
@JsonGetter("resourceUrl")
public String getResourceUrl() {
return resourceUrl;
}
}
@Override public RegistrationOutput handleRequest(RegistrationInput input,
Context context) {
return null;
}
}
For the sake of simplicity, this time, we used static inner classes for input and output instead of creating different files for these classes. For input, we will accept a JSON with email and username properties, and for output, we will return only the resource URL of the generated user.
We should add the dependency injection part to the handler as well, just like the the authorizer Lambda:
public class Handler extends LambdaHandler<Handler.RegistrationInput,
Handler.RegistrationOutput> { ..... private static final Injector INJECTOR = Guice.createInjector(new
DependencyInjectionModule()); private UserService userService; @Inject public void setUserService(UserService userService) { this.userService = userService; } public Handler() { INJECTOR.injectMembers(this); Objects.requireNonNull(userService); }
... }
We should create DependencyInjectionModule for this new Lambda again, with almost the same content as the authorizer Lambda. Let's create the file:
$ touch lambda-userregistration/src/main/java/com/serverlessbook/
lambda/userregistration/DependencyInjectionModule.java
Then let's use the following code:
package com.serverlessbook.lambda.userregistration; import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper; import com.google.inject.AbstractModule; import com.serverlessbook.repository.DynamoDBMapperWithCustomTableName; import com.serverlessbook.services.user.UserService; import com.serverlessbook.services.user.UserServiceImpl; import com.serverlessbook.services.user.repository.UserRepository; import com.serverlessbook.services.user.repository.UserRepositoryDynamoDB; public class DependencyInjectionModule extends AbstractModule { @Override protected void configure() { bind(UserService.class).to(UserServiceImpl.class); bind(UserRepository.class).to(UserRepositoryDynamoDB.class); bind(DynamoDBMapper.class).to(DynamoDBMapperWithCustomTableName.class); } }
Now we can implement our handle method in the Handler class:
@Override public RegistrationOutput handleRequest(RegistrationInput input, Context context) { User createdUser = userService.registerNewUser(input.username, input.email); return new RegistrationOutput(createdUser); }
Did you notice an issue here? Our compiler complains because registerNewUser is throwing an exception. However, we do not want to catch this exception as any uncaught exception will cause Lambda to fail, and consequently, we can handle this error to produce HTTP error code in API Gateway. As you may know, any checked exception deriving from Exception should be caught or reported in the method signature, as is also the case with our UserRegistrationException exceptions. But if an exception derived from RuntimeException does not have this limitation, then we can solve this issue by changing UserRegistrationException with the following style:
public abstract class UserRegistrationException extends RuntimeException { private static final long serialVersionUID = -7628860081079461234L; protected UserRegistrationException(String message) { super(message); } }