What is Lagom framework | Basic Structure in Scala | Demo project in Scala

Knoldus Blog Audio
Reading Time: 4 minutes

What is Lagom framework

Lagom is a free and open-source framework for developing reactive microservice-based Java or Scala applications. Lagom builds on proven technologies such as Akka and Play, which are already in use in wide applications.

Rather than assembling services, this integrated production environment enables you to focus on business issues. A single command creates the project, enables microservices and Lagom infrastructure, and then enables components. When the build detects source code changes, it performs a hot reload.

For more basic introduction of the Lagom watch this video.

Basic Structure of Lagom in Scala

The basic structure of the lagom for scala is very simple and is described in a few steps below.

  1. Add the latest plugin of Lagom to the plugins.sbt file then reloads the project by which all the variables will enable which we are going to use in the build.sbt.
  2. Define two modules in the build.sbt file one for the -api(to describe the descriptor and routes) and another one -impl for the implementation of the -api module descriptor. Again reloads the project so the modules can be created.
  3. In -api module, create a trait, write the descriptor for your service, and declare all corresponding methods to every particular route.
  4. Now In -impl module make a class that extends the api’s trait and defines the body of the overridden methods. By doing this we simply write the implementation of the routes.
  5. Again in -impl module makes a Loader class in which we do the wiring of the Service and its implementation.
  6. In -impl module under the resource, folder makes an application.conf file and put the path of the Loader file for the play configuration


Note: There should be a dependency between the modules like the -impl should depend on the -api module.

By following the above steps the basic structure of the Lagom is ready and it looks like this:

LagomDemoProject
    ->build.sbt
    ->project
        ->build.properties
        ->plugins.sbt
    ->HelloService-api
        ->src
            ->main
                ->scala
                    ->com.knoldus.hello.api
                        ->HelloService.scala
    ->HelloService-impl
        ->src
            ->main
                ->resources
                    ->application.conf
                ->scala
                    ->com.knoldus.hello.impl
                        ->HelloServiceImpl.scala
                        ->HelloServiceLoader.scala

Running Demo project of Lagom in Scala

The basic structure of the Lagom project is already defined above so let’s define the body of every file.

plugins.sbt :-

// The Lagom plugin
addSbtPlugin("com.lightbend.lagom" % "lagom-sbt-plugin" % "1.6.5")

build.sbt :-


name := "LagomBasicDemo"

version := "0.1"

scalaVersion := "2.13.6"

val macwire = "com.softwaremill.macwire" %% "macros" % "2.3.3" % "provided"
val scalaTest = "org.scalatest" %% "scalatest" % "3.1.1" % Test

lazy val `LagomService1` = (project in file("."))
  .aggregate(`HelloService-api`, `HelloService-impl` )

lazy val `HelloService-api` = (project in file("HelloService-api"))
  .settings(
    ThisBuild / lagomKafkaEnabled := false,
    ThisBuild / lagomCassandraEnabled := false,
    libraryDependencies ++= Seq(
      lagomScaladslApi
    )
  )

lazy val `HelloService-impl` = (project in file("HelloService-impl"))
  .enablePlugins(LagomScala)
  .settings(

    ThisBuild / lagomKafkaEnabled := false,
    ThisBuild / lagomCassandraEnabled := false,
    libraryDependencies ++= Seq(
      lagomScaladslPersistenceJdbc,
      lagomScaladslKafkaBroker,
      lagomScaladslAkkaDiscovery,
      lagomScaladslTestKit,
      macwire,
      scalaTest
    )
  )
  .settings(lagomForkedTestSettings)
  .dependsOn(`HelloService-api`)

Note: Kafka and Cassandra are disabled in this project because there are no uses of them.

HelloService.scala :-

import com.lightbend.lagom.scaladsl.api.transport.Method.GET
import com.lightbend.lagom.scaladsl.api.{Descriptor, Service, ServiceCall}


trait HelloService extends Service{

  def sayHello() : ServiceCall[String,String]

  override def descriptor: Descriptor = {
    import Service._
    named("HelloService")
      .withCalls(
        restCall(GET,"/api/hello", sayHello _)
      )
      .withAutoAcl(true)
  }
}

HelloServiceImpl.scala :-

import com.knoldus.hello.api.HelloService
import com.lightbend.lagom.scaladsl.api.ServiceCall

import scala.concurrent.{ExecutionContext, Future}

class HelloServiceImpl()(implicit ec: ExecutionContext)
  extends HelloService {
  override def sayHello(): ServiceCall[String, String] = ServiceCall{
    user =>
      Future.successful{
        s"Hello! $user from Lagom service"
      }
  }
}

HelloServiceLoader.scala

import com.knoldus.hello.api.HelloService
import com.lightbend.lagom.scaladsl.akka.discovery.AkkaDiscoveryComponents
import com.lightbend.lagom.scaladsl.api.{Descriptor, ServiceLocator}
import com.lightbend.lagom.scaladsl.server._
import com.softwaremill.macwire._
import play.api.libs.ws.ahc.AhcWSComponents



class HelloServiceLoader extends LagomApplicationLoader {

  override def load(context: LagomApplicationContext): LagomApplication = {
    new HelloServiceApplication(context) with AkkaDiscoveryComponents
  }
  override def loadDevMode(context: LagomApplicationContext): LagomApplication = {
    new HelloServiceApplication(context)  {
      override def serviceLocator: ServiceLocator = ServiceLocator.NoServiceLocator
    }
  }
  override def describeService: Option[Descriptor] = Some(readDescriptor[HelloService])

}

abstract class HelloServiceApplication(context: LagomApplicationContext)
  extends LagomApplication(context)
  with AhcWSComponents {
  override lazy val lagomServer: LagomServer = serverFor[HelloService](wire[HelloServiceImpl])
}

application.conf :-

play.application.loader = com.knoldus.hello.impl.HelloServiceLoader

These are the content of every file.

The above project is also available here as a Github repository where you can simply clone and run it using the mentioned instruction in the readme file.

How to check Output

To check the output of the project first you have to run the project which can be done by a single command:-

sbt runAll

The above command will run the project and the output will be generated at the allocated port mentioned in the logs for example:

So the output will be generated at localhost:55527/api/hello where /api/hello is path mentioned in the directive in HelloService.scala

To check this output I use Postman software.

In the Postman I select the GET method for the request and add the above URL in the field, For Body I select the raw radio button and then choose text from the drop down menu. Now add the data and hit the Send button the output will shown as below:

As you can see in the above image the status code is 200 OK and the output is “Hello! Yash Gupta from Lagom service” which is correct.

For more details please see the Lagom framework documentation.

Leave a Reply