Introducción a Spark
Introducción a Spark
Spark es un micro framework de Java diseñado para crear aplicaciones web de forma rápida y con mínimo esfuerzo. Sus principales características incluyen:
- Sintaxis simple y expresiva
- Configuración mínima
- Soporte para Java 8 lambdas
- Fácil integración con otras bibliotecas Java
- Ideal para APIs RESTful y microservicios
Configuración Inicial
Para comenzar con Spark, debemos añadir esta dependencia al archivo pom.xml
:
<dependency> <groupId>com.sparkjava</groupId> <artifactId>spark-core</artifactId> <version>2.9.4</version></dependency>
Primera aplicación Spark
Un ejemplo básico de una aplicación Spark:
1import static spark.Spark.*;2
3public class HolaMundo {4 public static void main(String[] args) {5 get("/hola", (req, res) -> "Hola Mundo");6 }7}
Este código crea un servidor web que responde con “Hola Mundo” cuando accedemos a http://localhost:4567/hola
.
Métodos HTTP
: GET
y POST
Spark
soporta los principales métodos HTTP
. Nos centraremos en GET
y POST
, que son los más comunes.
Método GET
El método GET
se usa para solicitar datos de un recurso específico. Veamos algunos ejemplos:
Ejemplo básico de GET
:
1get("/usuarios", (req, res) -> "Lista de usuarios");
GET
con parámetros de ruta:
1get("/usuarios/:id", (req, res) -> {2 String id = req.params(":id");3 return "Detalles del usuario con ID: " + id;4});
GET
con parámetros de consulta (query):
1get("/buscar", (req, res) -> {2 String query = req.queryParams("q");3 return "Resultados de búsqueda para: " + query;4});
Ejemplo GET
:
Supongamos que tenemos una lista de usuarios y queremos devolver sus detalles en formato JSON:
1import com.google.gson.Gson;2import java.util.HashMap;3import java.util.Map;4
5public class UsuarioController {6 private static Map<String, Usuario> usuarios = new HashMap<>();7 private static Gson gson = new Gson();8
9 static {10 usuarios.put("1", new Usuario("1", "Alice", "alice@email.com"));11 usuarios.put("2", new Usuario("2", "Bob", "bob@email.com"));12 }13
14 public static void setupRoutes() {15 get("/usuarios/:id", (req, res) -> {16 String id = req.params(":id");17 Usuario usuario = usuarios.get(id);18 if (usuario != null) {19 res.type("application/json");20 return gson.toJson(usuario);21 } else {22 res.status(404);23 return gson.toJson(new Mensaje("Usuario no encontrado"));24 }25 });26 }27}28
29class Usuario {30 String id;31 String nombre;32 String email;33
34 // Constructor, getters y setters35}36
37class Mensaje {38 String texto;39
40 Mensaje(String texto) {41 this.texto = texto;42 }43}
Método POST
El método POST se usa para enviar datos al servidor para crear o actualizar un recurso.
Ejemplo POST
:
1post("/usuarios", (req, res) -> "Crear nuevo usuario");
POST
con cuerpo de la solicitud:
1post("/usuarios", (req, res) -> {2 String body = req.body();3 // Procesar el body...4 return "Usuario creado";5});
Ejemplo nuevo usuario con POST
:
Continuando con nuestro ejemplo de usuarios, vamos a implementar la creación de un nuevo usuario:
1import com.google.gson.Gson;2import java.util.HashMap;3import java.util.Map;4
5public class UsuarioController {6 private static Map<String, Usuario> usuarios = new HashMap<>();7 private static Gson gson = new Gson();8 private static int nextId = 3; // Suponiendo que ya tenemos 2 usuarios9
10 public static void setupRoutes() {11 // ... rutas GET previas ...12
13 post("/usuarios", (req, res) -> {14 res.type("application/json");15
16 try {17 Usuario nuevoUsuario = gson.fromJson(req.body(), Usuario.class);18 nuevoUsuario.id = String.valueOf(nextId++);19 usuarios.put(nuevoUsuario.id, nuevoUsuario);20
21 res.status(201); // Creado22 return gson.toJson(nuevoUsuario);23 } catch (Exception e) {24 res.status(400); // Bad Request25 return gson.toJson(new Mensaje("Error al crear usuario: " + e.getMessage()));26 }27 });28 }29}30
31// Clases Usuario y Mensaje definidas anteriormente
Manejo de JSON con Gson
Como vimos en los ejemplos anteriores, Gson
es muy útil para trabajar con JSON en Spark. Debemos añadir la dependencia de Gson
al archivo pom.xml
:
<dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.11.0</version></dependency>
Consideraciones sobre JSON
- Utilizar
res.type("application/json");
para establecer el tipo de contenido correcto. - Manejar los errores de parsing JSON adecuadamente.
Manejo de Errores y Excepciones
Spark
proporciona mecanismos para manejar errores y excepciones:
1exception(Exception.class, (e, req, res) -> {2 res.status(500);3 res.type("application/json");4 res.body(gson.toJson(new Mensaje("Error interno del servidor")));5});6
7notFound((req, res) -> {8 res.type("application/json");9 return gson.toJson(new Mensaje("Recurso no encontrado"));10});
Código completo de ejemplo
Aquí tenemos el código completo de ejemplo que hemos estado desarrollando:
1import com.google.gson.Gson;2
3import java.util.HashMap;4import java.util.Map;5import java.util.List;6import java.util.ArrayList;7
8import static spark.Spark.*;9
10public class Main {11 private static Map<String, Usuario> usuarios = new HashMap<>();12 private static Gson gson = new Gson();13 private static int nextId = 1;14
15 public static void main(String[] args) {16 port(4567);17
18 // Configurar el tipo de contenido para todas las respuestas19 before((req, res) -> res.type("application/json"));20
21 // GET: Obtener todos los usuarios22 get("/usuarios", (req, res) -> {23 return gson.toJson(usuarios.values());24 });25
26 // GET: Obtener un usuario por ID27 get("/usuarios/:id", (req, res) -> {28 String id = req.params(":id");29 Usuario usuario = usuarios.get(id);30 if (usuario != null) {31 return gson.toJson(usuario);32 } else {33 res.status(404);34 return gson.toJson(new Message("Usuario no encontrado"));35 }36 });37
38 // POST: Crear un nuevo usuario39 post("/usuarios", (req, res) -> {40 Usuario nuevoUsuario = gson.fromJson(req.body(), Usuario.class);41 // mostrar req.body42 System.out.println(req.body());43 nuevoUsuario.setId(String.valueOf(nextId++));44 usuarios.put(nuevoUsuario.getId(), nuevoUsuario);45 res.status(201);46 return gson.toJson(nuevoUsuario);47 });48
49 // GET: Buscar usuarios por nombre50 get("/buscar", (req, res) -> {51 String query = req.queryParams("nombre");52 if (query == null) {53 return gson.toJson(new Message("Parámetro 'nombre' requerido"));54 }55
56 List<Usuario> resultados = new ArrayList<>();57 for (Usuario u : usuarios.values()) {58 System.out.println("Nombre: " + u.getNombre());59 if (u.getNombre().toLowerCase().contains(query.toLowerCase())) {60 resultados.add(u);61 }62 }63
64 return gson.toJson(resultados);65 });66
67 // Manejo de errores68 exception(Exception.class, (e, req, res) -> {69 e.printStackTrace();70 res.status(500);71 res.body(gson.toJson(new Message("Error interno del servidor")));72 });73
74 notFound((req, res) -> {75 res.type("application/json");76 return gson.toJson(new Message("Ruta no encontrada"));77 });78 }79}80
81class Usuario {82 private String id;83 private String nombre;84 private String email;85
86 public Usuario() {}87
88 public Usuario(String id, String nombre, String email) {89 this.id = id;90 this.nombre = nombre;91 this.email = email;92 }93
94 // Getters y setters95
96 public void setId(String id) {97 this.id = id;98 }99
100 public String getId() {101 return id;102 }103
104 public String getNombre() {105 return nombre;106 }107
108 public void setNombre(String nombre) {109 this.nombre = nombre;110 }111
112 public String getEmail() {113 return email;114 }115
116 public void setEmail(String email) {117 this.email = email;118 }119}120
121class Message {122 private String contenido;123
124 public Message(String contenido) {125 this.contenido = contenido;126 }127
128 // Getters y setters129
130 public String getContenido() {131 return contenido;132 }133
134 public void setContenido(String contenido) {135 this.contenido = contenido;136 }137}
Mejores Prácticas
- Organizar el código en controladores, servicios y modelos.
- Implementar logging para facilitar el debugging.
- Usar una configuración externalizada para manejar diferentes entornos.
- Implementar validación de entrada en tus rutas
POST
. - Usar
HTTPS
en producción para seguridad. - Considerar implementar rate limiting para proteger las APIs.