APIs com Kotlin e Spring Data REST: parte 1

APIs com Kotlin e Spring Data REST: parte 1

Muitas vezes nos encontramos numa situação onde precisamos criar rapidamente uma API REST, seja para fins educacionais, para explorar algum novo recurso, ou até mesmo, para colocar no ar algum teste de prova de conceito. Foi exatamente o que aconteceu por aqui na Alura!

Desenvolvendo uma aplicação que desse suporte e visibilidade a determinadas informações, surgiu a necessidade de termos uma API REST que disponibilizasse os dados relativos às instrutoras e instrutores que fazem parte da produção de conteúdo.

Foi nesse contexto, que Camila, a mais nova contratada da nossa equipe, veio até mim, pedindo uma orientação, pois gostaria de saber qual a forma mais rápida de colocar uma API REST no ar que fizesse ao menos as operações mais básicas (o famoso CRUD).

Spring Data REST

Como a ideia era utilizar o Kotlin para o desenvolvimento da API, a dúvida da minha colega era referente à quais bibliotecas ela poderia utilizar em conjunto com essa linguagem.

Eu expliquei que uma boa vantagem do Kotlin é ser uma linguagem que roda na JVM e completamente interoperável com o Java. Portanto, estando apta a se valer de todo o ecossistema criado para esta linguagem.

Assim, minha sugestão foi de utilizar o Spring Data REST para a criação rápida da API! Dando uma rápida olhada na página inicial da documentação 1, veremos que o Spring Data REST é parte integrante do projeto Sprint Data e tem como principais características:

  • Expõe uma API REST detectável para seu modelo de domínio usando HAL como um tipo de mídia.
  • Expõe recursos de coleção, item e associação, que representam seu modelo.
  • Atualmente, suporta JPA, MongoDB, Neo4j, Solr, Cassandra, Gemfire.
  • Permite personalizações avançadas dos recursos padrões expostos.

Dentre outros. Mas de todas essas características, a que mais se destaca é a facilidade na exposição de recursos baseados nas classes de modelo da aplicação. Um detalhe importante é que o Spring Data REST é fortemente baseado na JSON Hypertext Application Language ( HAL ). O HAL é uma padronização para tráfego de informações que está em desenvolvimento e visa, basicamente, criar uma representação da informação baseada em links que possibilitem a navegação e descobrimento de novas informações.

Contudo, o nosso foco é a API que queremos desenvolver! Sendo assim, apenas a título de teste, criei com a Camila, um projeto no Spring Initializr com as configurações a seguir.

print do projeto

Observem a biblioteca Rest Repositories. Ela será a responsável por nos ajudar em nossa tarefa. Após baixar o projeto e importação para sua IDE favorita, podemos colocar a mão na massa!

Banner da Escola de Programação: Matricula-se na escola de Programação. Junte-se a uma comunidade de mais de 500 mil estudantes. Na Alura você tem acesso a todos os cursos em uma única assinatura; tem novos lançamentos a cada semana; desafios práticos. Clique e saiba mais!

Expondo os recursos da API

Para começar, disse à Camila que precisaremos criar um modelo de dados da nossa aplicação. Isso é fácil e já estamos bem acostumados, portanto, criamos uma classe Instructors no pacote br.com.alura.instructorsapi.model com os atributos necessários.

package br.com.alura.instructorsapi.model

import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.Id

@Entity
data class Instructor (
   @Id @GeneratedValue
   var id: Long? = null,
   var name: String? = null,
   var surname: String? = null,
   var email: String? = null
)

Não há nada de novo aqui, apenas o bom e velho JPA sendo configurado através de suas anotações.

O grande pulo do gato vem agora! Após configurar nosso modelo, queremos expor endpoints para as principais operações do CRUD da forma mais rápida possível! E é aí que o Spring Data REST entra, e nos possibilita fazer algo como:

package br.com.alura.instructorsrest.model

// Demais importes.
import org.springframework.data.repository.CrudRepository

@Entity
data class Instructor (

   // Restante das definições da classe.
)

interface InstructorRepository: CrudRepository<Instructor, Long> {
}

Nós criamos uma interface InstructorRepository que estende de CrudRepository<T, ID>, interface que pertence ao Spring Data REST e que é a responsável por identificar o modelo de dados a partir do tipo genérico T e criar todos os endpoints necessários para as operações de CRUD, dentre outros detalhes. Como em nosso caso, o tipo genérico T foi definido como Instructor, os endpoints foram criados para o nosso modelo de dados. Antes de testar tudo, o último passo importante é indicar que por padrão, a nossa aplicação trabalhará com JSON. Essa configuração é feita no arquivo application.properties, adicionando a linha a seguir.

# src/main/resources/application.properties

spring.data.rest.defaultMediaType=application/json

Feito isso, podemos executar a aplicação e em seguida efetuar requisições para a nossa API! Simples assim!

Sendo assim, utilizando o cURL, poderíamos enviar algumas requisições de cadastro, como visto a seguir:

curl --location --request POST 'localhost:8080/instructors' \
--header 'Content-Type: application/json' \
--data-raw '{
 "name": "Gabriel",
 "surname": "Leite",
 "email": "[email protected]"
}'

Que resultariam em respostas parecidas com essa:

{
 "name": "Gabriel",
 "surname": "Leite",
 "email": "[email protected]",
 "content": [],
 "links": [
   {
     "rel": "self",
     "href": "http://localhost:8080/instructors/1"
   },
   {
     "rel": "instructor",
     "href": "http://localhost:8080/instructors/1"
   }
 ]
}

Por fim, após alguns cadastros, para verificar que as operações ocorreram com sucesso, podemos listar os dados cadastrados em nossa API.

curl --location --request GET 'localhost:8080/instructors'
{
 "links": [
   {
     "rel": "self",
     "href": "http://localhost:8080/instructors"
   },
   {
     "rel": "profile",
     "href": "http://localhost:8080/profile/instructors"
   }
 ],
 "content": [
   {
     "name": "Gabriel",
     "surname": "Leite",
     "email": "[email protected]",
     "content": [],
     "links": [
       {
         "rel": "self",
         "href": "http://localhost:8080/instructors/1"
       },
       {
         "rel": "instructor",
         "href": "http://localhost:8080/instructors/1"
       }
     ]
   },
   {
     "name": "Joana",
     "surname": "Maria",
     "email": "[email protected]",
     "content": [],
     "links": [
       {
         "rel": "self",
         "href": "http://localhost:8080/instructors/2"
       },
       {
         "rel": "instructor",
         "href": "http://localhost:8080/instructors/2"
       }
     ]
   }
 ]
}

Após essa jornada, minha colega ficou extremamente animada com a novidade e com a rapidez do desenvolvimento. Mas logo em seguida, ela me revelou com um pouco de apreensão, que precisaria fazer algumas alterações, dentre as quais: padronizar a URL da API com o prefixo /api, não permitir que requisições com o verbo DELETE sejam recebidas e outras mais.

Eu respondi que após uma pausa eu lhe ajudaria a dar um mergulho mais profundo no Spring Data REST para entender alguns detalhes que, por baixo dos panos, iriam permitir que ela chegasse aos objetivos dela. Esse relato vocês podem encontrar na parte 2 deste artigo.

Gabriel Leite
Gabriel Leite

Gabriel é desenvolvedor e instrutor com foco em Java, Ionic e Node.js.

Veja outros artigos sobre Programação