Cats Tutorial
This tutorial demonstrates using Cats Effect within a Spring Boot application.
The application retrieves a message from an H2 database using doobie and returns it in an HTTP response.
Maven dependency
Add Cats Effect and doobie support alongside the Spring Boot starter:
<dependency>
<groupId>net.officefloor.scala</groupId>
<artifactId>officescala_cats</artifactId>
</dependency>
<dependency>
<groupId>org.tpolecat</groupId>
<artifactId>doobie-h2_${scala-series}</artifactId>
</dependency>
Application class
The application registers DefaultScalaModule for Jackson serialisation and creates a doobie Transactor as a Spring bean using the auto-configured H2 DataSource:
@SpringBootApplication
class Application {
@Bean
def scalaJacksonModule(): JacksonModule = DefaultScalaModule
@Bean
def transactor(dataSource: DataSource): Transactor[IO] =
Transactor.fromDataSource[IO](dataSource, ExecutionContext.global)
}
object Application extends App {
SpringApplication.run(classOf[Application], args: _*)
}
Cats with doobie
The MessageRepository issues a SQL query via doobie and returns it as a Cats IO:
object MessageRepository {
def findById(id: Int)(implicit xa: Transactor[IO]): IO[Message] =
sql"SELECT id, content FROM message WHERE id = $id".query[Message].unique.transact(xa)
}
Service logic
The service method receives the @RequestBody and the injected Transactor (from the Spring bean), runs the doobie query, and returns IO[CatsResponse]. OfficeFloor (via officescala_cats) detects the IO return type, runs it, and passes the result as the @Parameter to the send method:
def service(@RequestBody request: CatsRequest)(implicit xa: Transactor[IO]): IO[CatsResponse] =
for {
message <- MessageRepository.findById(request.id)
response = CatsResponse(message.content + " and Cats")
} yield response
def send(@Parameter message: CatsResponse, response: ObjectResponse[CatsResponse]): Unit =
response.send(message)
REST endpoint
The YAML chains the two methods:
service:
class: net.officefloor.tutorial.catshttpserver.ServiceLogic
method: service
next: send
send:
class: net.officefloor.tutorial.catshttpserver.ServiceLogic
method: send
Request and Response
case class CatsRequest(id: Int)
case class CatsResponse(message: String)
Database
Spring Boot auto-initialises the embedded H2 database from schema.sql and data.sql on the classpath:
DROP TABLE IF EXISTS message;
CREATE TABLE message (id INT PRIMARY KEY, content VARCHAR(50));
INSERT INTO message (id, content) VALUES (1, 'Hi via doobie');
Testing
@SpringBootTest
@AutoConfigureMockMvc
class CatsHttpServerTest {
@Autowired var mvc: MockMvc = _
@Autowired var mapper: ObjectMapper = _
@Autowired var transactor: Transactor[IO] = _
@Test
def repositoryTest(): Unit = {
implicit val runtime: IORuntime = IORuntime.global
implicit val xa: Transactor[IO] = transactor
val message = MessageRepository.findById(1).unsafeRunSync()
assertEquals("Hi via doobie", message.content)
}
@Test
def httpServerTest(): Unit = {
mvc.perform(post("/")
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(CatsRequest(1)))
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk)
.andExpect(content().json(mapper.writeValueAsString(CatsResponse("Hi via doobie and Cats"))))
}
}
Next
The next tutorial covers ZIO.

