Saltearse al contenido

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:

1
import static spark.Spark.*;
2
3
public 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:

1
get("/usuarios", (req, res) -> "Lista de usuarios");

GET con parámetros de ruta:

1
get("/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):

1
get("/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:

1
import com.google.gson.Gson;
2
import java.util.HashMap;
3
import java.util.Map;
4
5
public 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
29
class Usuario {
30
String id;
31
String nombre;
32
String email;
33
34
// Constructor, getters y setters
35
}
36
37
class 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:

1
post("/usuarios", (req, res) -> "Crear nuevo usuario");

POST con cuerpo de la solicitud:

1
post("/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:

1
import com.google.gson.Gson;
2
import java.util.HashMap;
3
import java.util.Map;
4
5
public 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 usuarios
9
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); // Creado
22
return gson.toJson(nuevoUsuario);
23
} catch (Exception e) {
24
res.status(400); // Bad Request
25
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:

1
exception(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
7
notFound((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:

1
import com.google.gson.Gson;
2
3
import java.util.HashMap;
4
import java.util.Map;
5
import java.util.List;
6
import java.util.ArrayList;
7
8
import static spark.Spark.*;
9
10
public 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 respuestas
19
before((req, res) -> res.type("application/json"));
20
21
// GET: Obtener todos los usuarios
22
get("/usuarios", (req, res) -> {
23
return gson.toJson(usuarios.values());
24
});
25
26
// GET: Obtener un usuario por ID
27
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 usuario
39
post("/usuarios", (req, res) -> {
40
Usuario nuevoUsuario = gson.fromJson(req.body(), Usuario.class);
41
// mostrar req.body
42
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 nombre
50
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 errores
68
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
81
class 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 setters
95
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
121
class Message {
122
private String contenido;
123
124
public Message(String contenido) {
125
this.contenido = contenido;
126
}
127
128
// Getters y setters
129
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.