A Small Microservice Developed in Scala Using Hexagonal Architecture

Overview

Scala is a language that I have been using extensively in my work, but with the focus on Big Data using Spark for data processing.

Scala was in my playlist of languages that I wanted to delve into a bit more and not only experiment with in the area of Big Data using Spark, but to write a microservice using HTTP and REST.

The idea is to apply the concept of Hexagonal Architecture (ports and adapters). My microservice is called a Sparrow Account, and the source code is available in GitHub. I also did a similar experiment using the Clojure language that you can see on GitHub.

Let’s go to the requirements.

1. Microservice Requirements

Create a microservice that checks and creates a hypothetical bank account.

It must comprise an HTTP Server with two endpoints:

Requirements:

Proposed Solution

The architecture of the proposed solution follows the Hexagonal Architecture concept. The design is based on two books:

Below is an example diagram of a Hexagonal Architecture:

A Small Microservice Developed in Scala Using Hexagonal Architecture

Below is an diagram laying out the Organization Application Package:

A Small Microservice Developed in Scala Using Hexagonal Architecture

1.1 HTTP REST Server

To build a request and response HTTP REST Server, Finagle-Finch was used:

Here's the piece of code where the server is used: src/main/scala/sparrow/account/ServerApp.scala

def runServer(): Unit = {
  val app = Http
    .server
    .withLabel(serverConf.name)
    .withAdmissionControl.concurrencyLimit(
    maxConcurrentRequests = serverConf.maxConcurrentRequests,
    maxWaiters = serverConf.maxWaiters
  ).serve(s"${serverConf.host}:${serverConf.port}",
  (Routes.balanceAccount :+: Routes.fillAccount).toService)
  onExit {
    app.close()
  }
  Await.ready(app)
}

The end-points available on the server are:

Method EndPoint Example Parameter
POST /account {“uuid”:”1”, “amount”:100.50}
GET /balance not required

Here's the piece of code of the routes with the end-points: src/main/scala/sparrow/account/ServerApp.scala

final val fillAccount: Endpoint[Account] =
  post("account" :: jsonBody[AccountFillRequest]) {req: AccountFillRequest =>
    for {
      r <- accountService.fillAccount(req.uuid, req.amount)
    } yield r match {
      case Right(a) => Ok(a)
      case Left(m) => BadRequest(m)
    }
  }

There are two end-points: fillAccount that can create an account and deposit a value, as well as can withdraw using the negative value; and the  balanceAccount end-piont to see the balance available to the user.

1.2 Transactional Memory and Concurrency Control

When we are talking about microservices, we have to guarantee the atomicity of the code, so that no undue competition occurs. To control concurrency the ScalaSTM was used.

Here's the piece of code where atomicity is used: src/main/scala/sparrow/account/controller/AccountController.scala

override def fillAccount(uuid: String, amount: Double): Future[Either[AccountFillException, AccountTransaction]] = Future {
  if (accounts.get(uuid).isEmpty) createAccount(uuid, 0)

  accounts.get(uuid) match {
    case Some(transact) => {
      atomic {implicit tx =>
        transact() = AccountTransaction(transact().uuid, transact().amount + amount)

        displayOperationType(transact().uuid, transact().amount)

        if (amountIsNegative(transact().amount))
          transact() = AccountTransaction(transact().uuid, transact().amount - amount)

        Right(transact())
      }
    }
    case _ => Left(AccountFillException("Fill account not found."))
  }
}

1.3 Other Tools Used

Other tools used in the project are in the order below:

1.4 Building the Project

To build the project, you can follow the instructions in the GitHub repository located here:

Conclusion

We saw in this short article how easy and simple it is to create a microservice application using the Scala language. It could also have used other libraries such as the AKKA that I predict will soon make an article about it.

Thanks!

 

 

 

 

Top