¿De verdad necesitas una API REST para todo?
Por Esteban Guenul – Desarrollador Java que prefiere soluciones simples y claras
Introducción
En los últimos años, se ha vuelto común pensar que todas las aplicaciones web deben construirse con APIs REST, microservicios, React o Spring Boot. Pero no todos los proyectos lo necesitan.
Estoy desarrollando una aplicación de ventas con emisión de documentos tributarios (boletas, facturas, guías, etc.) y, lejos de complicarme, opté por una solución simple y efectiva:
- Java puro
- Servlets clásicos
- SQL directo
- Thymeleaf como motor de plantillas
- Empaquetado como
.jar
y desplegado en Jetty
Sin REST, sin SPA, sin sobreingeniería.
Código limpio y estructurado
Mi código actual se basa en una separación clara de responsabilidades. Por ejemplo, este servlet PosMovil
carga los datos necesarios para emitir documentos desde un punto centralizado:
package com.egga.appventas.posmovil;
import com.egga.appventas.cliprov.CliProv;
import com.egga.appventas.despacho.DespachoService;
import com.egga.appventas.documento.DocumentoService;
import com.egga.appventas.fpago.FPagoService;
import com.egga.appventas.include.ThymeleafConfig;
import com.egga.appventas.movimientos.MovimientoService;
import com.egga.appventas.producto.Producto;
import com.egga.appventas.referencia.ReferenciaService;
import com.egga.appventas.tpoventa.TpoVentaService;
import com.egga.appventas.traslado.TrasladoService;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.ParserConfigurationException;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.xml.sax.SAXException;
public class PosMovil extends HttpServlet {
private TemplateEngine templateEngine;
private FPagoService objFPagoService;
private TrasladoService objTrasladoService;
private TpoVentaService objTpoVentaService;
private DespachoService objDespachoService ;
private DocumentoService objDocumentoService ;
private ReferenciaService objReferenciaService;
@Override
public void init() {
ThymeleafConfig thymeleafConfig = new ThymeleafConfig();
templateEngine = thymeleafConfig.createTemplateEngine();
}
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
int empresaid = (int) request.getSession().getAttribute("empresaid");
MovimientoService objMovimientoService = new MovimientoService(empresaid);
int codsii = (int) request.getSession().getAttribute("codsii");
/* CARGO LAS TABLAS DE LA BASE DE DATOS */
objFPagoService = new FPagoService();
objTrasladoService = new TrasladoService();
objTpoVentaService = new TpoVentaService();
objDespachoService = new DespachoService();
objDocumentoService = new DocumentoService();
objReferenciaService = new ReferenciaService();
ArrayList<Producto> arrayproducto = objMovimientoService.obtenerProductos();
ArrayList<CliProv> arraylistcliprov = objMovimientoService.obtenerClientes();
/* OBTENGO LOS IDENTIFICADORES */
int idfpago = objFPagoService.getFagoId(1);
int idTraslado = objTrasladoService.getIdTraslado(1);
int idTpoVenta = objTpoVentaService.getTpoVentaId(3);
int idDespacho = objDespachoService.getDespachoId(1);
int idReferencia = objReferenciaService.getReferenciaId(0);
int idDocumento = objDocumentoService.getId(codsii);
String observacion = "NO APLICA";
/* PREPARO PLANTILLA Y ENVIO LOS DATOS AL HTML */
Context context = new Context();
context.setVariable("arrayproducto", arrayproducto);
context.setVariable("arraylistcliprov", arraylistcliprov);
context.setVariable("idFPago",idfpago);
context.setVariable("idTraslado",idTraslado);
context.setVariable("idTpoVenta",idTpoVenta);
context.setVariable("idDespacho", idDespacho);
context.setVariable("idReferencia", idReferencia);
context.setVariable("idDocumento", idDocumento);
context.setVariable("Observacion", observacion);
/* MUESTRO RESULTADOS EN EL NAVEGADOR */
String contenido = templateEngine.process("/movimientoview/posmovil", context);
response.setContentType("text/html");
response.getWriter().write(contenido);
} catch (SQLException ex) {
Logger.getLogger(PosMovil.class.getName()).log(Level.SEVERE, null, ex);
Context context = new Context();
context.setVariable("error", "Hubo un problema al obtener los productos.");
String contenido = templateEngine.process("/movimientoview/posmovil", context);
response.setContentType("text/html");
response.getWriter().write(contenido);
} catch (ClassNotFoundException | ParserConfigurationException | SAXException ex) {
Logger.getLogger(PosMovil.class.getName()).log(Level.SEVERE, null, ex);
} catch (Exception ex) {
Logger.getLogger(PosMovil.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Antes, todo estaba mezclado
No tenía un servlet más desordenado, pero sí había mucho acoplamiento. Por ejemplo:
- Lógica de negocio embebida en JSPs.
- Manejo de sesión disperso y sin modularidad.
- Servicios y DAOs mezclados directamente con el flujo del servlet.
Refactoricé todo eso y el resultado fue un sistema más simple y claro.
¿Por qué evitar REST aquí?
REST es útil cuando:
- El sistema está distribuido o necesita escalar horizontalmente.
- Ofreces un API pública a terceros.
Pero para una app interna, donde el formulario está en el mismo servidor, usar REST es innecesario. Ganas más manteniendo todo en un solo flujo clásico.
Ventajas de esta arquitectura
- ✅ Más fácil de mantener
- ✅ Reutilización de formularios
- ✅ Velocidad de desarrollo
- ✅ Menor dependencia externa
- ✅ Claridad total sobre cada flujo
Conclusión
No se trata de ir contra la modernidad, sino de elegir lo que realmente se necesita.
Si tu sistema no lo exige, no tienes por qué complicarte con capas innecesarias. Una arquitectura clásica, limpia y bien estructurada puede llevarte lejos.
¿Qué opinas tú? ¿Has trabajado con arquitecturas similares? ¿Te ha pasado lo mismo con REST o SPA?
Comentarios
Publicar un comentario