ScreenMatch - API de Frases de Películas y Series es un proyecto desarrollado con Spring Boot como parte del desafío educativo de Alura Latam. Su propósito es construir una API REST modular que integre servicios externos (Gemini API), permita la conversión estructurada de datos y almacene frases icónicas en una base de datos. El proyecto fortalece habilidades clave como consumo de APIs, persistencia, controladores REST y estructura orientada a buenas prácticas.
A través de endpoints accesibles, los usuarios pueden:
- Consultar frases aleatorias desde el repositorio local
- Buscar información sobre una película en tiempo real
- Guardar frases obtenidas en la base de datos para su reutilización
Este proyecto fue concebido con fines educativos, documentados con claridad para facilitar su adaptación en portafolios profesionales, clases de programación o integración con frontends dinámicos.
Temas Aprendidos:
Spring Boot Essentials
- Creación de endpoints REST con @RestController
- Configuración de @Autowired e inyección de dependencias
- Uso de @RequestParam para capturar parámetros de consulta
- Gestión de Optional y manejo de respuestas condicionales
Consumo de servicios externos (Gemini API)
- Integración HTTP para consulta de datos desde API externa
- Conversión de JSON plano a objetos Java (conversión manual)
Persistencia con Spring Data JPA
- Interacción con el repositorio FraseRepository
- Uso de findById, save, y lógica para selección aleatoria
- Configuración adaptable para H2 o PostgreSQL
Buenas prácticas en arquitectura
- Separación en capas: controlador, servicio, repositorio, modelo
- Modularidad y claridad de propósito en cada clase
- Preparación para refactorización y pruebas unitarias
Documentación y profesionalización
- Redacción de README técnico y narrativo
- Estructuración para destacar habilidades backend y educativas
package com.diego.desafio_backend.controller;
import com.diego.desafio_backend.model.DatosFrase;
import com.diego.desafio_backend.repository.FraseRepository;
import com.diego.desafio_backend.service.ConsultaGemini;
import com.diego.desafio_backend.service.ConvierteDatos;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
@RestController
public class FraseController {
private final FraseRepository repository;
private final ConsultaGemini consultaGemini;
private final ConvierteDatos conversor;
@Autowired
public FraseController(FraseRepository repository, ConsultaGemini consultaGemini, ConvierteDatos conversor) {
this.repository = repository;
this.consultaGemini = consultaGemini;
this.conversor = conversor;
}
@GetMapping("/series/frases")
public DatosFrase getFraseById() {
int randomId = (int) (Math.random() * 11) + 1; // número entre 1 y 11
Optional<DatosFrase> frase = repository.findById((long) randomId);
System.out.println(frase);
return frase.orElse(null); // or throw an exception if not found
}
@GetMapping("/series/obtenerDatos")
public String obtenerDatosFrase() {
String datos = consultaGemini.obtenerDatos("Seinfeld");
if (datos != null) {
return datos;
} else {
return "No se pudo obtener la frase para la película: " + "Seinfeld";
}
}
@PostMapping("/series/guardar")
public DatosFrase guardarDatosFrase(@RequestParam String pelicula) {
String datos = consultaGemini.obtenerDatos(pelicula);
if (datos == null) {
throw new RuntimeException("No se obtuvieron datos para la película: " + pelicula);
}
DatosFrase datosFrase = conversor.obtenerDatos(datos, DatosFrase.class);
repository.save(datosFrase);
return datosFrase;
}
}