Introdução
O desenvolvimento de APIs REST tem se tornado uma necessidade primordial em aplicações modernas. Kotlin, com sua sintaxe concisa e recursos de interoperabilidade com Java, se torna uma escolha excelente para trabalhar em conjunto com o Spring Boot, um dos frameworks mais populares. Neste tutorial, iremos explorar como integrar Kotlin ao Spring Boot para construir uma API REST eficiente, aproveitando o melhor de ambas as linguagens. Vamos abordar desde a configuração inicial do projeto até a implementação de testes unitários. No final, você terá uma aplicação funcional que utiliza Kotlin como linguagem de programação e Spring Boot para gerenciar a lógica de backend. Este é um guia prático que atenderá tanto iniciantes quanto desenvolvedores mais experientes que desejam expandir suas habilidades.
Etapas
Configuração do Ambiente de Desenvolvimento
Para começar, precisamos ter o JDK e o Gradle instalados em sua máquina. Kotlin é totalmente compatível com a JVM, portanto, certifique-se de que as versões corretas estejam instaladas. Você pode verificar as versões usando os comandos abaixo. Para uma experiência de codificação ideal, recomenda-se também utilizar uma IDE como IntelliJ IDEA.
commands# Verificar versões instaladas
java -version
gradle -vCriação do Projeto Spring Boot com Kotlin
Utilize o Spring Initializr para criar um novo projeto. Escolha as opções: **Project**: Gradle Project, **Language**: Kotlin, **Spring Boot**: última versão estável, **Packaging**: Jar, **Java**: 11 ou superior. Adicione as dependências Spring Web e Spring Data JPA. Após configurar, faça o download e extraia o arquivo.
build.gradle.ktsplugins { id("org.springframework.boot") version "3.0.0" id("io.spring.dependency-management") version "1.0.11.RELEASE" kotlin("jvm") version "1.6.10" kotlin("plugin.spring") version "1.6.10" } repositories { mavenCentral() } dependencies { implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("com.h2database:h2") testImplementation("org.springframework.boot:spring-boot-starter-test") } tasks.withType<Test> { useJUnitPlatform() }
Configuração do Banco de Dados H2
No arquivo `src/main/resources/application.properties`, defina as propriedades do banco de dados H2 e habilite o console web para gerenciar os dados.
application.propertiesspring.h2.console.enabled=true spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password= spring.jpa.database-platform=org.hibernate.dialect.H2Dialect spring.jpa.hibernate.ddl-auto=update
Criação da Entidade `Produto`
Implemente a classe modelo `Produto` que representará os produtos da sua aplicação. Utilize anotações JPA para mapear a classe à tabela do banco de dados.
Produto.ktpackage com.example.apirestful.model import javax.persistence.* @Entity @Table(name = "produtos") data class Produto( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long? = null, @Column(nullable = false) var nome: String, @Column(nullable = false) var preco: Double )
Criação do Repositório `ProdutoRepository`
Crie uma interface `ProdutoRepository`, que estende `JpaRepository` para fornecer métodos CRUD.
ProdutoRepository.ktpackage com.example.apirestful.repository import com.example.apirestful.model.Produto import org.springframework.data.jpa.repository.JpaRepository import org.springframework.stereotype.Repository @Repository interface ProdutoRepository : JpaRepository<Produto, Long>
Implementação do Serviço `ProdutoService`
Desenvolva a classe `ProdutoService`, que gerencia a lógica de negócios e interage com o `ProdutoRepository`.
ProdutoService.ktpackage com.example.apirestful.service import com.example.apirestful.model.Produto import com.example.apirestful.repository.ProdutoRepository import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Service import java.util.Optional @Service class ProdutoService(@Autowired private val produtoRepository: ProdutoRepository) { fun findAll(): List<Produto> = produtoRepository.findAll() fun findById(id: Long): Optional<Produto> = produtoRepository.findById(id) fun save(produto: Produto): Produto = produtoRepository.save(produto) fun update(id: Long, produtoDetails: Produto): Produto { val produto = produtoRepository.findById(id).orElseThrow { RuntimeException("Produto não encontrado") } produto.nome = produtoDetails.nome produto.preco = produtoDetails.preco return produtoRepository.save(produto) } fun deleteById(id: Long) = produtoRepository.deleteById(id) }
Implementação do Controlador `ProdutoController`
Crie `ProdutoController` que exponha os endpoints da API REST para realizar operações CRUD.
ProdutoController.ktpackage com.example.apirestful.controller import com.example.apirestful.model.Produto import com.example.apirestful.service.ProdutoService import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* import java.util.List @RestController @RequestMapping("/api/produtos") class ProdutoController(@Autowired private val produtoService: ProdutoService) { @GetMapping fun getAllProdutos(): List<Produto> = produtoService.findAll() @GetMapping("/{id}") fun getProdutoById(@PathVariable id: Long): ResponseEntity<Produto> = produtoService.findById(id).map(ResponseEntity::ok).orElse(ResponseEntity.notFound().build()) @PostMapping fun createProduto(@RequestBody produto: Produto): Produto = produtoService.save(produto) @PutMapping("/{id}") fun updateProduto(@PathVariable id: Long, @RequestBody produtoDetails: Produto): ResponseEntity<Produto> = ResponseEntity.ok(produtoService.update(id, produtoDetails)) @DeleteMapping("/{id}") fun deleteProduto(@PathVariable id: Long): ResponseEntity<Void> { produtoService.deleteById(id) return ResponseEntity.noContent().build() } }
Implementação de Testes Unitários
Crie uma classe de testes `ProdutoServiceTest` para validar a lógica de negócios usando Mockito e JUnit.
ProdutoServiceTest.ktpackage com.example.apirestful.service import com.example.apirestful.model.Produto import com.example.apirestful.repository.ProdutoRepository import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.mockito.InjectMocks import org.mockito.Mock import org.mockito.MockitoAnnotations import java.util.Optional import org.mockito.Mockito.* class ProdutoServiceTest { @InjectMocks private lateinit var produtoService: ProdutoService @Mock private lateinit var produtoRepository: ProdutoRepository @BeforeEach fun init() { MockitoAnnotations.openMocks(this) } @Test fun testFindAll() { val produto1 = Produto(nome = "Produto 1", preco = 10.0) val produto2 = Produto(nome = "Produto 2", preco = 20.0) `when`(produtoRepository.findAll()).thenReturn(listOf(produto1, produto2)) val produtos = produtoService.findAll() assertEquals(2, produtos.size) verify(produtoRepository, times(1)).findAll() } // Testes adicionais para os métodos findById, save, update e deleteById }
Executando a Aplicação e Testes
Use Gradle para compilar e executar a aplicação. Utilize Postman ou cURL para testar os endpoints da API.
commands# Compilar e executar a aplicação
gradle bootRun
# Executar os testes unitários
gradle testcurl_examples# Listar todos os produtos
curl -X GET http://localhost:8080/api/produtos
# Criar um novo produto
curl -X POST -H "Content-Type: application/json" -d '{"nome":"Novo Produto", "preco":99.99}' http://localhost:8080/api/produtos
Conclusão
Neste tutorial, mostramos como integrar Kotlin com Spring Boot para construir uma API RESTful eficiente. Você aprendeu a configurar o ambiente, criar entidades, repositórios, serviços e controladores, além de implementar testes unitários. A interoperabilidade entre Kotlin e Spring Boot proporciona uma abordagem moderna no desenvolvimento de aplicações web, permitindo a construção de serviços escaláveis e de fácil manutenção. Agora que você completou este guia, está mais preparado para aplicar esses conceitos em seus próprios projetos e explorar ainda mais o potencial das tecnologias Java e Kotlin.