Saltar al contenido principal

Introducción a los Servicios REST

Mensaje Importante para los Estudiantes​

ATENCIÓN: Este capítulo es una revisión opcional.

Este capítulo se ofrece como recurso adicional para quienes deseen profundizar su comprensión de los servicios web REST. Aunque este contenido no es obligatorio para el curso, puede ser útil para:

  • Estudiantes que tengan carencias en los conceptos de servicios web
  • Aquellos que deseen una revisión exhaustiva antes de abordar Spring Boot
  • Personas que quieran comprender los fundamentos teóricos de REST

Si usted ya se siente cómodo con los servicios web REST, puede pasar directamente al siguiente módulo.


Contenido del Capítulo​

Esta sección incluye cuatro partes:

  • Parte 1: Presentación de REST - Introducción a la arquitectura REST, principios clave y conceptos stateless vs stateful
  • Parte 2: Métodos HTTP - Detalles sobre los métodos HTTP en REST y ejemplos de uso con Java
  • Parte 3: Ejemplos prácticos - Uso de los métodos GET, POST, PUT y DELETE con código Java
  • Parte 4: Gestión de errores - Códigos de estado HTTP y manejo de errores en las APIs REST

Parte 1: Presentación de REST​

REST (Representational State Transfer) es una arquitectura de software diseñada para crear servicios web escalables y de alto rendimiento. Fue introducida en el año 2000 por Roy T. Fielding, uno de los principales creadores del protocolo HTTP. REST se basa en un conjunto de restricciones que hacen que los sistemas distribuidos sean más simples y eficientes.

Principios Clave de REST​

1. Uniformidad de la Interfaz​

Las interacciones entre el cliente y el servidor se estandarizan mediante el uso de métodos HTTP, URIs para identificar los recursos y formatos de representación estándar como JSON o XML. Esto permite una comunicación clara y coherente.

2. Stateless​

El servidor no conserva ninguna información sobre el estado de las sesiones entre las solicitudes. Cada solicitud del cliente debe contener toda la información necesaria para procesarla. Esto simplifica la gestión de las sesiones.

3. Cacheable​

Las respuestas del servidor pueden ser almacenadas en caché para mejorar el rendimiento. Las directivas de caché se especifican en las cabeceras HTTP, permitiendo reducir los tiempos de respuesta y la carga del servidor.

4. Cliente-Servidor​

Existe una separación de responsabilidades entre el cliente (que gestiona la interfaz de usuario) y el servidor (que gestiona el almacenamiento de datos y la lógica de negocio). Esto facilita el desarrollo independiente de la interfaz de usuario y del backend.

5. Sistema en Capas (Layered System)​

La arquitectura REST puede construirse en capas, lo que mejora la flexibilidad y escalabilidad del sistema. Por ejemplo, una capa puede gestionar la autenticación, mientras que otra puede encargarse del almacenamiento de datos.


Stateless vs Stateful​

Arquitectura Stateless​

En REST, la arquitectura es stateless (sin estado). Esto significa que cada solicitud enviada por un cliente al servidor debe contener toda la información necesaria para procesarla. El servidor no conserva información sobre el estado de interacciones previas, lo que simplifica la gestión del sistema.

Ejemplo:

GET /api/users/123 HTTP/1.1
Host: example.com
Authorization: Bearer <token>

En este ejemplo, el cliente envía toda la información necesaria para autenticar la solicitud (mediante la cabecera Authorization) e identificar el recurso solicitado (/api/users/123).

Arquitectura Stateful​

Por el contrario, en una arquitectura stateful (con estado), el servidor conserva el estado de la sesión entre las solicitudes. Esto puede complicar la gestión de las sesiones y hacer que el sistema sea menos flexible y menos escalable.


Métodos HTTP en REST​

Los métodos HTTP son verbos que indican la acción a realizar sobre un recurso identificado por una URI (Uniform Resource Identifier). A continuación se presentan los métodos más comúnmente utilizados en REST.

Tabla de Métodos HTTP​

+-------------+---------------------+---------------------------------------------------------+
| Método | Descripción | Ejemplos de Código |
+-------------+---------------------+---------------------------------------------------------+
| GET | Recuperar un | GET /api/users/123 HTTP/1.1 |
| | recurso | Host: example.com |
+-------------+---------------------+---------------------------------------------------------+
| POST | Crear un | POST /api/users HTTP/1.1 |
| | recurso | Host: example.com |
| | | Content-Type: application/json |
| | | |
| | | { |
| | | "name": "John Doe", |
| | | "email": "john@example.com" |
| | | } |
+-------------+---------------------+---------------------------------------------------------+
| PUT | Reemplazar un | PUT /api/users/123 HTTP/1.1 |
| | recurso completo | Host: example.com |
| | | Content-Type: application/json |
+-------------+---------------------+---------------------------------------------------------+
| PATCH | Modificar | PATCH /api/users/123 HTTP/1.1 |
| | parcialmente | Host: example.com |
| | un recurso | Content-Type: application/json |
+-------------+---------------------+---------------------------------------------------------+
| DELETE | Eliminar un | DELETE /api/users/123 HTTP/1.1 |
| | recurso | Host: example.com |
+-------------+---------------------+---------------------------------------------------------+

Métodos Menos Utilizados​

+-------------+---------------------+---------------------------------------------------------+
| OPTIONS | Determinar los | OPTIONS /api/users HTTP/1.1 |
| | métodos que | Host: example.com |
| | el servidor puede | |
| | procesar | Respuesta: |
| | | HTTP/1.1 200 OK |
| | | Allow: GET, POST, OPTIONS |
+-------------+---------------------+---------------------------------------------------------+
| HEAD | Recuperar las | HEAD /api/users/123 HTTP/1.1 |
| | cabeceras de un | Host: example.com |
| | recurso sin | |
| | cuerpo de respuesta | Respuesta: |
| | | HTTP/1.1 200 OK |
| | | Content-Type: application/json |
+-------------+---------------------+---------------------------------------------------------+

Cabeceras HTTP​

Las cabeceras HTTP son elementos importantes que proporcionan información adicional sobre los datos transmitidos durante las solicitudes y respuestas HTTP.

Tabla de Cabeceras HTTP​

+-------------------+----------------------------------+------------------------------------------------+
| Cabecera | Descripción | Ejemplo de Código |
+-------------------+----------------------------------+------------------------------------------------+
| Content-Type | Especifica el tipo de contenido | Content-Type: application/json |
| | del recurso | |
+-------------------+----------------------------------+------------------------------------------------+
| Accept | Indica los tipos de contenido | Accept: application/json |
| | que el cliente acepta | |
+-------------------+----------------------------------+------------------------------------------------+
| Authorization | Proporciona la información | Authorization: Bearer <token> |
| | de autenticación | |
+-------------------+----------------------------------+------------------------------------------------+
| Cache-Control | Define las directivas de | Cache-Control: no-cache |
| | almacenamiento en caché | |
+-------------------+----------------------------------+------------------------------------------------+
| Content-Length | Especifica el tamaño del cuerpo | Content-Length: 348 |
| | de la respuesta | |
+-------------------+----------------------------------+------------------------------------------------+
| Location | Indica la ubicación de un | Location: http://example.com/api/users/123 |
| | recurso creado | |
+-------------------+----------------------------------+------------------------------------------------+

Gestión de Códigos HTTP​

Los códigos de estado HTTP se utilizan para indicar el resultado de una solicitud HTTP.

Tabla de Códigos de Estado HTTP​

+-------------------+----------------------------------+------------------------------------------------+
| Código HTTP | Significado | Ejemplo de Escenario |
+-------------------+----------------------------------+------------------------------------------------+
| 200 OK | La solicitud fue exitosa | Respuesta a una solicitud GET para recuperar un |
| | | recurso |
+-------------------+----------------------------------+------------------------------------------------+
| 201 Created | Se ha creado un nuevo recurso | Respuesta a una solicitud POST para crear un |
| | | nuevo usuario |
+-------------------+----------------------------------+------------------------------------------------+
| 204 No Content | La solicitud fue exitosa pero no | Respuesta a una solicitud DELETE tras eliminar |
| | hay contenido para devolver | un recurso |
+-------------------+----------------------------------+------------------------------------------------+
| 400 Bad Request | La solicitud está mal formada o | El cliente envía una solicitud con datos |
| | contiene errores | inválidos |
+-------------------+----------------------------------+------------------------------------------------+
| 401 Unauthorized | Autenticación requerida | El cliente intenta acceder a un recurso sin |
| | | proporcionar un token de autenticación |
+-------------------+----------------------------------+------------------------------------------------+
| 403 Forbidden | Acceso prohibido | El cliente no tiene la autorización necesaria |
| | | para acceder al recurso |
+-------------------+----------------------------------+------------------------------------------------+
| 404 Not Found | El recurso no fue encontrado | El cliente intenta acceder a un recurso que no |
| | | existe |
+-------------------+----------------------------------+------------------------------------------------+
| 500 Internal | Se produjo un error interno en | Se produce una excepción inesperada en el |
| Server Error | el servidor | servidor al procesar la solicitud |
+-------------------+----------------------------------+------------------------------------------------+

Parte 2: Métodos HTTP en Detalle​

En una arquitectura REST, los métodos HTTP definen la acción que el cliente desea realizar sobre un recurso.

Tabla Resumen​

MétodoDescripciónUso típico
GETRecupera un recurso sin modificar su estadoLectura de una página web, obtención de datos
POSTEnvía datos para crear un nuevo recursoEnvío de un formulario, agregar una nueva entrada
PUTActualiza un recurso enviando la versión completaReemplazo o creación de un recurso
PATCHActualiza parcialmente un recursoModificación parcial de un recurso existente
DELETEElimina un recurso específicoEliminación de una entrada, de un archivo
HEADRecupera las cabeceras de un recurso, similar a GET, sin el cuerpoVerificación de la última modificación
OPTIONSConsulta al servidor sobre los métodos disponiblesPreparación de una solicitud, descubrimiento de métodos

Parte 3: Ejemplos Prácticos con Java​

Ejemplo GET: Recuperar un Recurso​

@GET
@Path("/testGet")
public Response getTestResource() {
// Lógica para recuperar el recurso
return Response.ok("Recurso recuperado con éxito").build();
}

Detalles:

  1. @GET: Esta anotación indica que el método responderá a una solicitud HTTP GET
  2. @Path("/testGet"): Define la URL relativa para este método
  3. Response.ok(): Crea una respuesta HTTP con código 200 (OK)

Uso típico: Mostrar información al usuario (detalles de un usuario, de un producto, etc.)


Ejemplo POST: Crear un Nuevo Recurso​

@POST
@Path("/testPost")
@Consumes(MediaType.APPLICATION_JSON)
public Response createTestResource(String json) {
// Lógica para crear un recurso a partir del JSON recibido
return Response.status(Response.Status.CREATED).entity("Recurso creado").build();
}

Detalles:

  1. @POST: Esta anotación indica que el método responderá a una solicitud HTTP POST
  2. @Consumes(MediaType.APPLICATION_JSON): Indica que el método espera datos en formato JSON
  3. Response.Status.CREATED: Código 201 que indica que se ha creado un nuevo recurso

Uso típico: Registro de un nuevo usuario, creación de un nuevo producto


Ejemplo PUT: Actualizar un Recurso​

@PUT
@Path("/testPut/{id}")
@Consumes(MediaType.APPLICATION_JSON)
public Response updateTestResource(@PathParam("id") String id, String json) {
// Lógica para actualizar el recurso identificado por id
return Response.ok("Recurso actualizado").build();
}

Detalles:

  1. @PUT: Esta anotación indica que el método responderá a una solicitud HTTP PUT
  2. @PathParam("id"): Extrae el identificador del recurso desde la URL
  3. Response.ok(): Código 200 para indicar que la actualización fue exitosa

Uso típico: Modificar los detalles de un producto, actualizar un perfil de usuario


Ejemplo DELETE: Eliminar un Recurso​

@DELETE
@Path("/testDelete/{id}")
public Response deleteTestResource(@PathParam("id") String id) {
// Lógica para eliminar el recurso identificado por id
return Response.status(Response.Status.NO_CONTENT).build();
}

Detalles:

  1. @DELETE: Esta anotación indica que el método responderá a una solicitud HTTP DELETE
  2. Response.Status.NO_CONTENT: Código 204 que indica que un recurso ha sido eliminado sin contenido para devolver

Uso típico: Eliminación de un usuario, de un producto, de un comentario


Parte 4: Gestión de Errores​

La gestión adecuada de los errores es esencial en las APIs REST. A continuación se muestra cómo devolver los códigos de estado más utilizados.

Código 200 OK​

El código 200 OK indica que la solicitud se ha procesado correctamente.

@GET
@Path("/testGet")
public Response getTestResource() {
return Response.ok("Recurso recuperado con éxito").build();
}

Código 301 Moved Permanently​

El código 301 Moved Permanently indica que el recurso ha sido movido de forma permanente.

@GET
@Path("/oldPath")
public Response redirectResource() {
return Response.status(Response.Status.MOVED_PERMANENTLY)
.location(URI.create("/newPath"))
.build();
}

Código 400 Bad Request​

El código 400 Bad Request indica que el servidor no puede procesar la solicitud debido a un error del cliente.

@POST
@Path("/testPost")
@Consumes(MediaType.APPLICATION_JSON)
public Response createTestResource(String json) {
if (json == null || json.isEmpty()) {
return Response.status(Response.Status.BAD_REQUEST)
.entity("Datos inválidos: el cuerpo de la solicitud está vacío.")
.build();
}
return Response.status(Response.Status.CREATED)
.entity("Recurso creado")
.build();
}

Código 404 Not Found​

El código 404 Not Found se devuelve cuando el recurso solicitado no existe.

@GET
@Path("/testGet/{id}")
public Response getTestResource(@PathParam("id") String id) {
boolean resourceExists = false;

if (!resourceExists) {
return Response.status(Response.Status.NOT_FOUND)
.entity("Recurso no encontrado para el ID: " + id)
.build();
}
return Response.ok("Recurso encontrado").build();
}

Código 500 Internal Server Error​

El código 500 Internal Server Error indica que se ha producido un error inesperado en el servidor.

@GET
@Path("/testGet/{id}")
public Response getTestResource(@PathParam("id") String id) {
try {
String resource = retrieveResource(id);
return Response.ok(resource).build();
} catch (Exception e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Error interno del servidor: " + e.getMessage())
.build();
}
}

Recomendaciones para la Gestión de Errores​

  • Utilice los códigos HTTP apropiados: Cada código tiene un significado preciso y permite al cliente comprender el resultado de su solicitud
  • Proporcione mensajes de error claros: Incluya un mensaje de error explicativo en el cuerpo de la respuesta
  • Considere la seguridad: No revele demasiados detalles técnicos para evitar proporcionar información explotable

Conclusión​

Este capítulo proporciona una base sólida para comprender e interactuar con las APIs RESTful. Estos conceptos son fundamentales para trabajar con Spring Boot, que simplifica considerablemente la creación de APIs REST gracias a sus anotaciones y su autoconfiguración.

En los siguientes módulos, verá cómo Spring Boot facilita la implementación de estos conceptos REST de manera elegante y eficiente.