Curso teórico e prático para criação de projeto backend API REST, utilizando Spring Boot com Kotlin (ORM hibernate JPA DAO). Projeto com funcionalidades CRUD (Create, Read/List, Update, Delete). Banco de dados MySQL. Testes via Postman. Deploy em AWS (EC2).
Sistema web backend que suporta métodos HTTP REST (GET, POST, PUT, DELETE), transportando dados via header/body em request - response entre dispositivos comunicados em rede, via IPs em protocolo HTTP. Framework Spring Boot possui tecnologias necessárias para implementar padrão REST em projetos Java/Kotlin, usando padrões de código OOP (Programação Orientada a Objetos) e MVC (Model-View-Controller).
Instalação de pré-requisitos em ambiente Windows.
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.jetbrains.kotlin:kotlin-reflect")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
runtimeOnly("com.mysql:mysql-connector-j")
spring.application.name=bookstore
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://localhost:3306/bookstore
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jackson.serialization.fail-on-empty-beans=false
server.error.include-message=always
server.error.include-binding-errors=always
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
server.port=8080
package ubsocial.com.bookstore.config
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.web.servlet.config.annotation.CorsRegistry
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
@Configuration
class WebConfig {
@Bean
fun corsConfigurer(): WebMvcConfigurer {
return object : WebMvcConfigurer {
override fun addCorsMappings(registry: CorsRegistry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8081")
.allowedMethods("GET","POST","PUT","DELETE","OPTIONS")
}
}
}
}
package ubsocial.com.bookstore.model.entity
import com.fasterxml.jackson.annotation.JsonFormat
import jakarta.persistence.*
import jakarta.validation.constraints.NotBlank
import jakarta.validation.constraints.NotNull
import jakarta.validation.constraints.Size
import java.time.LocalDate
@Entity
data class Book(
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
val id: Long? = null,
@field:NotBlank
@field:Size(min = 1, max = 255, message = "Título precisa ter entre 1 e 255 caracteres")
@Column(length = 255)
val title: String = "",
@field:NotBlank
@field:Size(min = 1, max = 255, message = "Autor precisa ter entre 1 e 255 caracteres")
@Column(length = 255)
val author: String = "",
@field:NotNull
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
@Column(name = "published_date")
val published_date: LocalDate = LocalDate.now(),
@field:NotBlank
@field:Size(min = 13, max = 13, message = "ISBN precisa ter 13 caracteres")
@Column(unique = true)
val isbn: String = "",
val pages: Int = 0,
@field:Size(min = 1, max = 255, message = "Capa/Gênero precisa ter entre 1 e 255 caracteres")
@Column(length = 255)
val cover: String? = null,
@field:NotBlank
@field:Size(min = 1, max = 255, message = "Idioma precisa ter entre 1 e 255 caracteres")
@Column(length = 255)
val language: String = ""
)
package ubsocial.com.bookstore.model.repositories
import org.springframework.data.jpa.repository.JpaRepository
import ubsocial.com.bookstore.model.entity.Book
interface BookRepository : JpaRepository<Book, Long>
package ubsocial.com.bookstore.controller
import jakarta.validation.Valid
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
import ubsocial.com.bookstore.model.entity.Book
import ubsocial.com.bookstore.model.repositories.BookRepository
@RestController
@RequestMapping("/books")
class BookResource(private val bookRepository: BookRepository) {
@GetMapping
fun getAll(): List<Book> = bookRepository.findAll()
@GetMapping("/{id}")
fun getById(@PathVariable id: Long): ResponseEntity<Book> {
val book = bookRepository.findById(id)
return if (book.isPresent) ResponseEntity.ok(book.get())
else ResponseEntity.notFound().build()
}
@PostMapping
fun create(@RequestBody @Valid book: Book): Book = bookRepository.save(book)
@PutMapping("/{id}")
fun update(@PathVariable id: Long, @RequestBody @Valid book: Book): ResponseEntity<Book> {
val optional = bookRepository.findById(id)
if (optional.isEmpty) return ResponseEntity.notFound().build()
val updated = optional.get().copy(
title = book.title,
author = book.author,
published_date = book.published_date,
isbn = book.isbn,
pages = book.pages,
cover = book.cover,
language = book.language
)
return ResponseEntity.ok(bookRepository.save(updated))
}
@DeleteMapping("/{id}")
fun delete(@PathVariable id: Long): ResponseEntity<Void> {
return if (bookRepository.existsById(id)) {
bookRepository.deleteById(id)
ResponseEntity.noContent().build()
} else {
ResponseEntity.notFound().build()
}
}
}
Postman é software que simula client para consumir API REST backend, através requests HTTP, usando verbos REST, respectivos métodos e header/body, e aguardando response HTTP.
{
"title": "O Senhor dos Anéis",
"author": "J.R.R. Tolkien",
"published_date": "1954-07-29",
"isbn": "9780261102385",
"pages": 1178,
"cover": "Ficção",
"language": "Português"
}
{
"title": "O Senhor dos Anéis - Edição Atualizada",
"author": "J.R.R. Tolkien",
"published_date": "1954-07-29",
"isbn": "9780261102385",
"pages": 1178,
"cover": "Ficção",
"language": "Português"
}
Publicar projeto API REST Spring Boot na Amazon Web Services (AWS), via criação de instância EC2 (Ubuntu) gratuita.
--- CRIAR INSTÂNCIA AWS ---
EC2 / Instâncias / Executar instâncias
- Nome: prjCursoSpringBoot1
- AMI: Ubuntu Server (nível gratuito)
- Tipo: t3.micro (verificar se região é t2 ou t3 nível gratuito)
- Criar par de chaves:
-- Nome: keySpringBoot1
-- Tipo: RSA
-- Formato: conforme SO de sua máquina
Criar par de chaves (download .pem ou .ppk)
- Rede:
-- Atribuir IP público automaticamente: habilitar
-- Grupo de segurança criado automaticamente, com regras:
--- Permitir tráfego HTTP qualquer lugar
--- Permitir tráfego HTTPS qualquer lugar
--- Permitir tráfego SSH qualquer lugar
- Armazenamento: 8GiB gp3 (nível gratuito)
Criar (executar instância)
--- HABILITAR PORTA SPRING BOOT ----
EC2 / Instâncias / Clicar na instância criada
Aba Segurança / Grupo de segurança
- Editar regras de entrada
-- Adicionar regra:
--- Tipo: TCP personalizado, Protocolo: TCP, Intervalo de portas: 8080, Origem: Qualquer-local-IPv4 (0.0.0.0/0), Descrição: API REST Spring Boot
Salvar regras
--- CONECTAR INSTÂNCIA AWS ---
EC2 / Instâncias / Clicar na instância criada / Conectar:
- Habilitar Conecte-se usando um IP público
Conectar
--- INSTALAR API REST SPRING BOOT ---
Na instância CLI, executar comandos:
- sudo apt update && sudo apt install git curl openjdk-21-jdk mysql-server -y && sudo systemctl enable mysql --now
- sudo mysql
-- ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '123';
-- FLUSH PRIVILEGES;
-- Ctrl+d (sair do MySQL)
- mysql -u root -p (informar senha 123)
-- CREATE DATABASE bookstore;
-- SHOW DATABASES;
-- Ctrl+d (sair do MySQL)
- git clone https://github.com/mateusschwede/workover_spring_boot_api_rest.git && cd workover_spring_boot_api_rest && cd bookstore && sudo chmod +x gradlew
- ./gradlew clean build --refresh-dependencies
- ./gradlew bootRun &
- curl http://localhost:8080/books
--- CONSUMIR API REST SPRING BOOT VIA CURL ---
- Listar books: curl http://localhost:8080/books
- Adicionar book:
curl -X POST http://localhost:8080/books \
-H "Content-Type: application/json" \
-d '{
"title": "O Senhor dos Anéis",
"author": "J.R.R. Tolkien",
"published_date": "1954-07-29",
"isbn": "9780261102385",
"pages": 1178,
"cover": "Ficção",
"language": "Português"
}'
- Visualizar book específico: curl http://localhost:8080/books/1
- Editar book:
curl -X PUT http://localhost:8080/books/1 \
-H "Content-Type: application/json" \
-d '{
"title": "O Senhor dos Anéis",
"author": "J.R.R. Tolkien",
"published_date": "1954-10-29",
"isbn": "9780261102385",
"pages": 1178,
"cover": "Ficção",
"language": "Português - ATUALIZADO"
}'
- Deletar book: curl -X DELETE http://localhost:8080/books/1
--- CONSUMIR API REST SPRING BOOT VIA POSTMAN ---
EC2 / Instâncias / Clicar na instância criada / Descrição / IPv4 público: copiar IP
- Pode-se visualizar IPv4 via CLI: ip addr show eth0
- Listar books: GET http://IPv4-PUBLICO-DA-EC2:8080/books
- Adicionar book: POST http://IPv4-PUBLICO-DA-EC2:8080/books
Body raw (JSON):
{
"title": "O Senhor dos Anéis",
"author": "J.R.R. Tolkien",
"published_date": "1954-07-29",
"isbn": "9780261102385",
"pages": 1178,
"cover": "Ficção",
"language": "Português"
}
- Visualizar book específico: GET http://IPv4-PUBLICO-DA-EC2:8080/books/1
- Editar book: PUT http://IPv4-PUBLICO-DA-EC2:8080/books/1
Body raw (JSON):
{
"title": "O Senhor dos Anéis",
"author": "J.R.R. Tolkien",
"published_date": "1954-10-29",
"isbn": "9780261102385",
"pages": 1178,
"cover": "Ficção",
"language": "Português - ATUALIZADO"
}
- Deletar book: DELETE http://IPv4-PUBLICO-DA-EC2:8080/books/1
--- PARAR INSTÂNCIA AWS ---
- Na instância, executar comandos:
-- Parar servidor Gradle: pkill -f gradle
-- Parar MySQL: sudo systemctl stop mysql
- EC2 / Instâncias / Selecionar instância / Ações / Estado da instância / Encerrar instância
- EC2 / Grupos de segurança / Selecionar grupo de segurança da instância / Excluir
- EC2 / Chaves de acesso / Selecionar keySpringBoot1.pem / Excluir
Elaborado por Mateus Schwede
ubsocial.github.io