Kotlin é mais conhecida por ser a linguagem oficial para desenvolvimento de apps Android mas desde sua versão 1.0 (fevereiro de 2016) o framework Spring oferece suporte a esta linguagem que tem agradado a muitos desenvolvedores aqui na redspark.

Ter o suporte de um framework do tamanho do Spring foi muito importante para o crescimento do Kotlin para backend. Desenvolver uma API REST com Kotlin é uma forma de manter algumas vantagens do Java, como a robustez da JVM (Kotlin também roda em outras plataformas mas isso é assunto para outro post) e poder utilizar uma linguagem moderna e concisa.

Vamos criar nossa primeira aplicação REST utilizando Spring Webflux + Kotlin. Este post é o primeiro de uma série onde abordaremos a criação de uma API REST completa.

Configuração

Acesse https://start.spring.io/ para criar o projeto Spring e utilize as seguintes configurações:

Notem duas coisas interessantes aqui: Escolhemos Gradle no lugar de Maven e adicionamos o Spring Reactive Web além do Spring Web (aguardem um post exclusivo sobre Spring Reactive).

Maven é a ferramenta de build e gerenciamento de projeto mais conhecida e utilizada no mundo Java e teve seu lançamento em 2004, há quase 16 anos atrás, e para este projeto vamos utilizar o Gradle que usa Kotlin no lugar do XML (em versões antigas ou que não tenham a implementação do kotlin é utilizado Groovy). O Spring Reactive Web traz o Spring WebFlux que é construído em cima da especificação “non-blocking servers” reactive streams (https://www.reactive-streams.org/). Quem já estava trabalhando com JavaRx, Java Reactive Streams ou KotlinRx não deve ter grandes dificuldades ao utilizar o WebFlux, mas vamos explicando a medida que utilizarmos.  

Vamos clicar no “generate” e abrir o projeto na IDE, no caso estou utilizando o IntelliJ pois, assim como Kotlin, ele foi desenvolvido pelo pessoal da JetBrains e possuem uma integração excelente.

Main

Podemos observar que a classe GamesApplication está anotada com o @SpringBootApplication e não possue escopo (chave) aberto. A função main é uma função de escopo global e faz a chamada de runApplication que também é uma função de escopo global (“top level”).

@SpringBootApplication
class GamesApplication

fun main(args: Array<String>) {
  runApplication<GamesApplication>(*args)
}

Controller

Nesta aplicação vamos utilizar a arquitetura em camadas MVC. As anotações são as mesmas do Spring com Java:

@RestController
@RequestMapping("games")
class GameController {

   @GetMapping
   fun getGames(): List{
       val gameList = ArrayList()
       gameList.add("CS:GO")
       gameList.add("Candy Crush")
       gameList.add("Age of Empires")
       return gameList
   }

}

Olhando o método getGames podemos notar que o código está muito parecido com Java. É o que chamamos de “sotaque” Java. Este código funciona, se rodarmos o server e chamarmos http://localhost:8080/games (no browser ou no postman) teremos o retorno os 3 jogos.

Agora que está tudo funcionando, vamos refatorar o nosso código e escrever um código mais conciso. Primeiro podemos utilizar a função listOf() para inicializarmos nossa lista:

@GetMapping
fun getGames(): List{
   return listOf("CS:GO", "Candy Crush", "Age of Empires")
}

No Kotlin, quando temos uma função que tem como única instrução o retorno nós podemos fazer uma atribuição direta:

@GetMapping
fun getGames(): List = listOf("CS:GO", "Candy Crush", "Age of Empires")

Também é possível omitir o tipo de retorno (List) pois o Kotlin trabalha com inferência de tipos. É importante ter ciência que Kotlin, assim como o Java é uma linguagem fortemente tipada. De qualquer forma, aqui na redspark nós optamos por manter o retorno explícito pois acreditamos que isso melhora a leitura do código. Se rodarmos no server, teremos a mesma resposta.

Domain

Nós não queremos retornar uma String, no Kotlin continuamos no mundo da orientação a objeto. Nosso jogo terá título e data de lançamento:

class Game {

   lateinit var title: String
   lateinit var releaseDate: LocalDate

}

Algumas observações sobre esta classe. Agora as classes são public e final por definição. Se quisermos (e geralmente não vamos querer) fazer uma herança de uma classe, precisamos declará-la como “open”. Também não precisamos dos getters e setters de forma explícita (RIP Lombok), o Kotlin funciona com property access então, se necessário, podemos sobrescrever os getters e setters mas eles não precisam ser declarados.

Vamos refatorar esta classe para o tipo data class:

data class Game (

   val title: String,
   val releaseDate: LocalDate

)

Trocamos o escopo da classe por parênteses e o lateinit var (variável inicializada posteriormente) por val (constante). Este tipo de classe é utilizado para instanciar objetos que guardem dados e tem algumas vantagens como implementar os métodos equals(), hashCode(), toString() e copy().

 

 Service

 

Vamos implementar a camada de service, aqui é onde ficarão as regras de negócio da nossa aplicação. Como esta classe será instanciada e gerenciada pelo Spring vamos primeiro criar uma interface, assim podemos depender de uma abstração ao invés de uma classe concreta:

interface GameService {

   fun getGames(): List
  
}

Vamos criar a implementação desta classe (dica: Se estiver utilizando o IntelliJ, é só dar alt+enter na interface e pedir pra criar a implementação).

@Service
class GameServiceImpl : GameService {

   override fun getGames(): List {
       val csGo = Game("CS:GO", LocalDate.of(2012, 8, 21))
       val candyCrush = Game("Candy Crush", LocalDate.of(2012, 3, 12))
       val ageOfEmpires = Game("Age of Empires", LocalDate.of(1997, 9, 15))
       return listOf(csGo, candyCrush, ageOfEmpires)
   }

}

Por último vamos utilizar a injeção de dependência para instanciar nosso service no controller:

@RestController
@RequestMapping("games")
class GameController @Autowired constructor(
       private val gameService: GameService
){

   @GetMapping
   fun getGames(): List = gameService.getGames()

}

Conforme a recomendação do pessoal do Spring (http://olivergierke.de/2013/11/why-field-injection-is-evil/), vamos utilizar a injeção de dependência no construtor ao invés da propriedade.

Pronto, se chamarmos nosso endpoint teremos a seguinte resposta:

Por hora é isso pessoal. Aguardem nos próximos posts a implementação da camada de repository, security e mais dicas de Kotlin. O código fonte que criamos está disponível em https://github.com/fabiotadashi/redspark-kotlin-api.