From Microservices to Service Blocks using Spring Cloud Function and AWS Lambda

The Commands

Next, let’s fetch the commands that are available for the Account resource. To do this, we’ll send an HTTP GET request to the location href listed on the hypermedia link named commands.

Example 8. HTTP GET request to /v1/accounts/1/commands

1
2
3
4
5
6
7
8
9
10
{
 "_links": {
 "activate": {
 "href": "http://localhost:8080/v1/accounts/1/commands/activate"
 },
 "suspend": {
 "href": "http://localhost:8080/v1/accounts/1/commands/suspend"
 }
 }
}

|**|By attaching the commands to an account resource as a hypermedia link, all consumers will be able to easily lookup the commands that can be executed on the resource.|

After traversing to commands, we are provided back another set of links that we can continue to follow. We see that we can either activate or suspend this account. First, let’s try executing the activate command. To do this, we make an HTTP GET request to the href associated with the command.

Example 9. HTTP GET request to /v1/accounts/1/commands/activate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
 "createdAt": 1491459939554,
 "lastModified": 1491473977565,
 "firstName": "Taylor",
 "lastName": "Swift",
 "email": "tswift@cloud.com",
 "status": "ACCOUNT_ACTIVATED",
 "_links": {
 "commands": {
 "href": "http://localhost:8080/v1/accounts/1/commands"
 },
 "events": {
 "href": "http://localhost:8080/v1/accounts/1/events"
 }
 },
 "accountId": 1
}

In the example above, we see the command returned back the account resource with a new value for the status property. After executing the command, the account’s status transitioned from ACCOUNT_CREATED to ACCOUNT_ACTIVATED. Let’s try sending the same activate command twice in a row and see what happens.

Example 10. 2nd HTTP GET request to /v1/accounts/1/commands/activate

1
2
3
4
5
6
7
8
{
 "timestamp": 1491474077084,
 "status": 400,
 "error": "Bad Request",
 "exception": "java.lang.RuntimeException",
 "message": "Account already activated",
 "path": "/v1/accounts/1/commands/activate"
}

As expected, we’ve received an error. This is because the account we created had already been activated. Which means that we cannot issue the same command twice in a row. Now, what’s interesting about this response is that the validation logic is not coming from within the core Spring Boot application. Instead, we have two stateless functions that are deployed to AWS Lambda. These two functions will act as an event handlers — mutating state based on the current context and command of an account.

Now, let’s try the only other command that is listed on the account resource: suspend.

Example 11. HTTP GET to /v1/accounts/1/suspend

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
 "createdAt": 1491459939554,
 "lastModified": 1491474306296,
 "firstName": "Taylor",
 "lastName": "Swift",
 "email": "tswift@cloud.com",
 "status": "ACCOUNT_SUSPENDED",
 "_links": {
 "commands": {
 "href": "http://localhost:8080/v1/accounts/1/commands"
 },
 "events": {
 "href": "http://localhost:8080/v1/accounts/1/events"
 }
 },
 "accountId": 1
}

Now we see that the account response successfully transitioned from ACCOUNT_ACTIVATED to ACCOUNT_SUSPENDED, without error. This is a fairly trivial example, where we have two different states that can be transitioned to and from without being applied twice in a row. |**|Imagine the complexity of a domain aggregate with many different states and rules between transitions. Things can get complicated quickly. To simplify the system design, we can start out by modeling these state transitions as a directed graph, called a state machine.|