Este post é uma continuação do  Kotlin para backend?. Cada parte desta série está em branchs diferentes no github. Na primeira parte criamos as classes controller e service, vamos terminar a implementação e adicionar o banco de dados agora, mas antes precisamos refator alguns pontos:

Data Transfer Object

A camada Controller é a nossa interface com o front-end e devemos utilizar objetos que tenham a função de  transferir os dados que precisamos, sejam estes dados de entrada ou de saída. Vamos renomear a classe Game para GameDTO e acrescentar o campo id:

data class GameDTO(
        val id: String,
        val title: String,
        val releaseDate: LocalDate
)

Vamos também criar uma classe para representar os dados de criação e atualização do Game. Esta classe não deve conter o ID pois esta não é uma informação que o front-end deve passar na criação, vamos deixar para o back-end a função de gerenciar estes ids.

data class CreateGameDTO (
        val title: String,
        val releaseDate: LocalDate
)

CRUD

Vamos agora criar as opeções básicas no Controller:

    @GetMapping
    fun getGames(): List<GameDTO> = gameService.getGames()

    @GetMapping("/{id}")
    fun findGameById(@PathVariable id: String): GameDTO = gameService.getGameById(id)

    @PostMapping
    fun createGame(@RequestBody createGameDTO: CreateGameDTO): GameDTO = gameService.createGame(createGameDTO)

    @PutMapping("/{id}")
    fun updateGame(@PathVariable id: String,
                    @RequestBody createGameDTO: CreateGameDTO): GameDTO = gameService.update(id, createGameDTO)

    @DeleteMapping("/{id}")
    fun deleteGame(@PathVariable id: String) = gameService.delete(id)

Estas operações ainda não existem na nossa camada de Service, então precisamos atualizar a interface GameService:

interface GameService {
    fun getGames(): List<GameDTO>
    fun getGameById(id: String): GameDTO
    fun createGame(createGameDTO: CreateGameDTO): GameDTO
    fun update(id: String, createGameDTO: CreateGameDTO): GameDTO
    fun delete(id: String)
}

Por último vamos implementar estes novos métodos na classe GameServiceImpl. Dica: No IntelliJ podemos clicar no nome da classe e utilizar o atalho alt+enter -> “Implement members”. 

Repository

Para usufruirmos de todos os benefícios da programação reativa, vamos utilizar o MongoDB como banco de dados pois já temos o driver reativo. Até o momento da publicação deste post temos driver reativo para Cassandra, Mongo, Redis e, ainda em fase experimental, para bancos SQL.

Adicionar a dependência no build.gradle.kts:

implementation("org.springframework.boot:spring-boot-starter-data-mongodb-reactive")

Para facilitar, vamos rodar o mongo local através utilizando docker:

$ docker run -p 27017:27017 --name mongolocal -d mongo:4.0

O mapeamento da entitade Game:

@Document
data class GameEntity(
        @Id 
        val id: String? = null,
        val title: String,
        val releaseDate: LocalDate
)

E a interface que extende ReactiveMongoRepository:

@Repository
interface GameRepository : ReactiveMongoRepository<GameEntity, String>

Um ponto interessante a se notar é que não precisamos abrir o escopo se a classe ou interface não tiver nada a ser declarado. 

Vamos criar uma classe para habilitar os repositórios do mongo.

package io.redspark.games.config

import com.mongodb.reactivestreams.client.MongoClient
import com.mongodb.reactivestreams.client.MongoClients
import org.springframework.context.annotation.Bean
import org.springframework.data.mongodb.config.AbstractReactiveMongoConfiguration
import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories

@EnableReactiveMongoRepositories
class MongoReactiveApplication : AbstractReactiveMongoConfiguration() {
    @Bean
    fun mongoClient(): MongoClient {
        return MongoClients.create()
    }

    override fun getDatabaseName(): String {
        return "gamereactive"
    }

    override fun reactiveMongoClient(): MongoClient {
        return mongoClient()
    }
}

e fazer a configuração do acessos ao banco:

spring:
  data:
    mongodb:
      host: 127.0.0.1
      port: 27017