Rest Command Side
In this step, we are going to generate a command side restful microservice from scratch. The model-config for this service can be found at model-config repo.
Let’s first checkout model-config repo from GitHub.
git clone [email protected]:networknt/model-config.git
The swagger specification for the todo-list command side service can be found at ~/networknt/model-config/rest/todo-command. In the same folder, there is config.json which is used to control how light-codegen going to generate the code.
In order to generate the rest-command service, let’s first clone the light-codegen project and build it.
cd ~/networknt
git clone [email protected]:networknt/light-codegen.git
cd light-codegen
mvn clean install
Generate rest-command service with the following command line. Assume we are still in the light-codegen folder.
java -jar codegen-cli/target/codegen-cli.jar -f swagger -o ../light-example-4j/eventuate/todo-list/rest-command -m ../model-config/rest/todo_command/1.0.0/swagger.json -c ../model-config/rest/todo_command/1.0.0/config.json
Now add this rest-command into pom.xml and build it with maven.
<modules>
<module>common</module>
<module>command</module>
<module>query</module>
<module>rest-command</module>
</modules>
mvn clean install
The four modules should be built successfully.
Now let’s update rest-command module to wire in the logic.
First, we need to update dependencies for this project by adding the following.
<dependency>
<groupId>com.networknt</groupId>
<artifactId>todo-common</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>com.networknt</groupId>
<artifactId>todo-command</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>com.networknt</groupId>
<artifactId>eventuate-common</artifactId>
<version>${version.light-eventuate-4j}</version>
</dependency>
<dependency>
<groupId>com.networknt</groupId>
<artifactId>eventuate-jdbc</artifactId>
<version>${version.light-eventuate-4j}</version>
</dependency>
<dependency>
<groupId>com.networknt</groupId>
<artifactId>eventuate-client</artifactId>
<version>${version.light-eventuate-4j}</version>
</dependency>
<dependency>
<groupId>com.networknt</groupId>
<artifactId>test-jdbc</artifactId>
<version>${version.light-eventuate-4j}</version>
</dependency>
And change the three handlers to the following.
package com.networknt.todolist.restcommand.handler;
import com.networknt.body.BodyHandler;
import com.networknt.config.Config;
import com.networknt.eventuate.common.AggregateRepository;
import com.networknt.eventuate.common.EventuateAggregateStore;
import com.networknt.eventuate.todolist.TodoCommandService;
import com.networknt.eventuate.todolist.TodoCommandServiceImpl;
import com.networknt.eventuate.todolist.common.model.TodoInfo;
import com.networknt.eventuate.todolist.domain.TodoAggregate;
import com.networknt.eventuate.todolist.domain.TodoBulkDeleteAggregate;
import com.networknt.service.SingletonServiceFactory;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.HttpString;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
public class TodosIdDeleteHandler implements HttpHandler {
private EventuateAggregateStore eventStore = (EventuateAggregateStore) SingletonServiceFactory.getBean(EventuateAggregateStore.class);
private AggregateRepository todoRepository = new AggregateRepository(TodoAggregate.class, eventStore);
private AggregateRepository bulkDeleteAggregateRepository = new AggregateRepository(TodoBulkDeleteAggregate.class, eventStore);
private TodoCommandService service = new TodoCommandServiceImpl(todoRepository, bulkDeleteAggregateRepository);
public void handleRequest(HttpServerExchange exchange) throws Exception {
// delete a new object
String id = exchange.getQueryParameters().get("id").getFirst();
TodoInfo todo = (TodoInfo)exchange.getAttachment(BodyHandler.REQUEST_BODY);
CompletableFuture<TodoInfo> result = service.remove(id).thenApply((e) -> {
TodoInfo m = e.getAggregate().getTodo();
return m;
});
exchange.getResponseHeaders().add(new HttpString("Content-Type"), "application/json");
exchange.getResponseSender().send(Config.getInstance().getMapper().writeValueAsString(result));
}
}
package com.networknt.todolist.restcommand.handler;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.networknt.body.BodyHandler;
import com.networknt.config.Config;
import com.networknt.eventuate.common.AggregateRepository;
import com.networknt.eventuate.common.EventuateAggregateStore;
import com.networknt.eventuate.todolist.TodoCommandService;
import com.networknt.eventuate.todolist.TodoCommandServiceImpl;
import com.networknt.eventuate.todolist.common.model.TodoInfo;
import com.networknt.eventuate.todolist.domain.TodoAggregate;
import com.networknt.eventuate.todolist.domain.TodoBulkDeleteAggregate;
import com.networknt.service.SingletonServiceFactory;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.HttpString;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
public class TodosPostHandler implements HttpHandler {
private EventuateAggregateStore eventStore = (EventuateAggregateStore) SingletonServiceFactory.getBean(EventuateAggregateStore.class);
private AggregateRepository todoRepository = new AggregateRepository(TodoAggregate.class, eventStore);
private AggregateRepository bulkDeleteAggregateRepository = new AggregateRepository(TodoBulkDeleteAggregate.class, eventStore);
private TodoCommandService service = new TodoCommandServiceImpl(todoRepository, bulkDeleteAggregateRepository);
public void handleRequest(HttpServerExchange exchange) throws Exception {
System.out.println("command side:");
ObjectMapper mapper = new ObjectMapper();
// add a new object
Map s = (Map)exchange.getAttachment(BodyHandler.REQUEST_BODY);
String json = mapper.writeValueAsString(s);
TodoInfo todo = mapper.readValue(json, TodoInfo.class);
//TodoInfo todo2 = JSonMapper.fromJson(exchange.getAttachment(BodyHandler.REQUEST_BODY), TodoInfo.class);
CompletableFuture<TodoInfo> result = service.add(todo).thenApply((e) -> {
TodoInfo m = e.getAggregate().getTodo();
return m;
});
exchange.getResponseHeaders().add(new HttpString("Content-Type"), "application/json");
exchange.getResponseSender().send(Config.getInstance().getMapper().writeValueAsString(result));
}
}
package com.networknt.todolist.restcommand.handler;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.networknt.body.BodyHandler;
import com.networknt.config.Config;
import com.networknt.eventuate.common.AggregateRepository;
import com.networknt.eventuate.common.EventuateAggregateStore;
import com.networknt.eventuate.common.impl.sync.AggregateCrud;
import com.networknt.eventuate.todolist.TodoCommandService;
import com.networknt.eventuate.todolist.TodoCommandServiceImpl;
import com.networknt.eventuate.todolist.common.model.TodoInfo;
import com.networknt.eventuate.todolist.domain.TodoAggregate;
import com.networknt.eventuate.todolist.domain.TodoBulkDeleteAggregate;
import com.networknt.service.SingletonServiceFactory;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.HttpString;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
public class TodosPutHandler implements HttpHandler {
private AggregateCrud aggregateCrud = (AggregateCrud) SingletonServiceFactory.getBean(AggregateCrud.class);
private EventuateAggregateStore eventStore = (EventuateAggregateStore)SingletonServiceFactory.getBean(EventuateAggregateStore.class);
// private TodoCommandService service = (TodoCommandService)SingletonServiceFactory.getBean(TodoCommandService.class);
private AggregateRepository todoRepository = new AggregateRepository(TodoAggregate.class, eventStore);
private AggregateRepository bulkDeleteAggregateRepository = new AggregateRepository(TodoBulkDeleteAggregate.class, eventStore);
private TodoCommandService service = new TodoCommandServiceImpl(todoRepository, bulkDeleteAggregateRepository);
public void handleRequest(HttpServerExchange exchange) throws Exception {
ObjectMapper mapper = new ObjectMapper(); // update a new object
String id = exchange.getQueryParameters().get("id").getFirst();
Map s = (Map)exchange.getAttachment(BodyHandler.REQUEST_BODY);
String json = mapper.writeValueAsString(s);
TodoInfo todo = mapper.readValue(json, TodoInfo.class);
CompletableFuture<TodoInfo> result = service.update(id, todo).thenApply((e) -> {
TodoInfo m = e.getAggregate().getTodo();
return m;
});
exchange.getResponseHeaders().add(new HttpString("Content-Type"), "application/json");
exchange.getResponseSender().send(Config.getInstance().getMapper().writeValueAsString(result));
}
}
Since we are going to create some eventuate class instances from interfaces, let’s create a service.yml under resources/config folder.
singletons:
- javax.sql.DataSource:
- com.zaxxer.hikari.HikariDataSource:
DriverClassName: com.mysql.jdbc.Driver
jdbcUrl: jdbc:mysql://localhost:3306/eventuate?useSSL=false
username: mysqluser
password: mysqlpw
- com.networknt.eventuate.common.impl.sync.AggregateCrud:
- com.networknt.eventuate.client.EventuateLocalDBAggregateCrud
- com.networknt.eventuate.common.impl.sync.AggregateEvents:
- com.networknt.eventuate.client.EventuateLocalAggregatesEvents
- com.networknt.eventuate.common.impl.AggregateCrud:
- com.networknt.eventuate.common.impl.adapters.SyncToAsyncAggregateCrudAdapter
- com.networknt.eventuate.common.impl.AggregateEvents:
- com.networknt.eventuate.common.impl.adapters.SyncToAsyncAggregateEventsAdapter
- com.networknt.eventuate.common.SnapshotManager:
- com.networknt.eventuate.common.SnapshotManagerImpl
- com.networknt.eventuate.common.MissingApplyEventMethodStrategy:
- com.networknt.eventuate.common.DefaultMissingApplyEventMethodStrategy
- com.networknt.eventuate.common.EventuateAggregateStore:
- com.networknt.eventuate.common.impl.EventuateAggregateStoreImpl
- com.networknt.eventuate.common.sync.EventuateAggregateStore:
- com.networknt.eventuate.common.impl.sync.EventuateAggregateStoreImpl
- com.networknt.eventuate.todolist.domain.TodoAggregate:
- com.networknt.eventuate.todolist.domain.TodoAggregate
- com.networknt.eventuate.todolist.domain.TodoBulkDeleteAggregate:
- com.networknt.eventuate.todolist.domain.TodoBulkDeleteAggregate
Now let’s verify that all modules can be built.
mvn clean install
If all modules are built successfully, we can move to the next step to complete the query side Restful service.