Path params con @FormParam

Una de las cosas que pocos saben, es que REST nos permite crear servicios que se integren a la perfección con los formularios HTML, de tal forma que podemos lugar una etiqueta <form> directamente con un servicio REST. para ello, JAX-RS nos proporciona la anotación @FormParam.

NOTA: Este artículo es parte de un tutorial completo para crear API REST con JAX-RS, si quieres ver el índice completo entra aquí.

La diferencia fundamental que tienen los form params con respecto a los demás, es que se obtiene directamente los campo asociados al formulario desde el cual se ejecuta, pero para entender mejor, veamos el siguiente ejemplo:

<html>
	<body>
		<p>Customer form</p>
		<form action="http://localhost:8080/api-0.0.1-SNAPSHOT/customers" method="post">
			<div>
				<label for="firstname" style="display:inline-block; width: 100px;">Nombre</label>
				<input id="firstname" type="text" name="firstname" />
			</div>
			<div>
				<label for="lastname" style="display:inline-block; width: 100px;">Apellido</label>
				<input id="lastname" type="text" name="lastname" />
			</div>
			<div>
				<label for="status" style="display:inline-block; width: 100px;">Estatus</label>
				<select id="status" name="status" >
					<option value="active">Activo</option>
  					<option value="inactive">Inactivo</option>
				</select>
			</div>
			<br/>
			<input type="submit" value="Guardar" />
		</form>
	</body>
</html>

En este ejemplo debemos poner atención en la etiqueta <form>, la cual está apuntando a un servicios REST mediante la etiqueta action, con lo cual le estamos diciendo al navegador que envíe el formulario a nuestro servicio REST.

Otra de las cosas a tomar en cuenta son los campos dentro del form, como lo son el nombre, apellido y estatus, los cuales serán los que sean enviados al servicio REST.

Una vez explicado lo anterior, pasemos a la implementación en JAX-RS para recuperar estos parámetros:

package api.services;

import javax.ws.rs.*;
import javax.ws.rs.core.*;

@Path("customers")
public class CustomersService {

	@POST
	@Produces(MediaType.TEXT_PLAIN)
	@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	public Response saveCustomer(
			@FormParam("firstname") String firstname, 
			@FormParam("lastname") String lastname, 
			@FormParam("status") String status) {
		
		String result = String.format("firstname = %s, lastname = %s, status = %s", new String[]{firstname, lastname, status});
		return Response.ok(result).build();
	}
}

Veamos como hemos definido una anotación @FormParam para cada uno de los parámetros esperados del formulario, los cuales serán mapeados a cada uno de los parámetros del método en Java.

Las anotaciones @Consumes la utilizamos definir que esperamos el payload como un formulario.

Probando el servicio

Lo primero será abrir el la página HTML para verlo de la siguiente manera:

Una vez capturado el formulario, la damos grabar, lo que detonará el submit del formulario y la ejecución del servicio REST, lo que dará como resultado lo siguiente:

Podemos ver como el servicio REST ha recibido todos los parámetros y los ha regresado como una cadena de texto.

Mediante la anotación @FormParam es fácil recuperar los valores de un formulario, pues los mapeamos a una parámetro especifico del método Java, sin embargo, esta forma tiene la limitación de que requerimos N parámetros en Java para mapear los N form params, lo que puede llegar a ser complicado en formularios grandes o donde los nombres de los parámetros pudieran variar, en tales casos, podemos implementarlos de la siguiente manera para recuperar todos los form params como un colección:

package api.services;

import java.util.Map;

import javax.ws.rs.*;
import javax.ws.rs.core.*;

@Path("customers")
public class CustomersService {
	
	@POST
	@Produces(MediaType.TEXT_PLAIN)
	@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	public Response getFormDataUsingMultivaluedMap(MultivaluedMap<String, String> formParams) {
		String result = "";
		for(Map.Entry entry: formParams.entrySet() ) {
			result += entry.getKey() + "=" + entry.getValue() + ", ";
		}
		
		return Response.ok(result).build();
	}
}

Conclusiones

Los @FormParam pueden ser una buena alternativa cuando queremos ligar directamente un formulario con servicios REST, evitando tener que construir un request especifico.

Como inconveniente, tenemos que el servicio REST deberá retornar la estructura HTML de la siguiente página que verá el usuario, o en su defecto, podemos redireccionar al usuario a la siguiente página.

4 thoughts to “Path params con @FormParam”

  1. Hola Oscar, muchas gracias por esta parte del tutorial acerca de los @FormParam, ahora conozco una forma de trabajar con los formularios y los servicios web.

    ¿Como puedo hacer para que me redirija a una página web después de dar clic al botón Guardar?

    Saludos.

    1. Hola Salvador, si bien es posible hacer ese redirect, no funciona como cuando haces una petición a una página web, ya que los servicios REST son pensados para ser consumidos por sistemas o mediante AJAX, lo que hace que no sigan el proceso natural de redireccionamiento, en este sentido, podrías hacer dos cosas, retornar un código 301 (redirect permanent) o regresar algúna bandera en el body del response que luego el cliente que consume el servicio lo interprete y haga el redirecto.

  2. Hola
    ¿Cómo se entiende esos return tan extraños en REST?
    Me refiero a que parece que devuelves el código de éxito (ok) y a la vez el resultado. ¿Es así? La cadena devuelta está en formato String y “Texto plano” ¿se puede cambiar a XML, por ejemplo? Yo lo intento y me da error porque debo escribir (creo) un BodyWriter… ¿es necesario? Aún no he intentado ninguno de esos…
    Un saludo y enhorabuena por estos ejemplos.

    1. Es que lo que estas respondiendo es un Objeto Result, que contien un código de respuesta y un payload, luego Java combierte ese objeto a un respuesta HTTP. Por otro lado, si es posible cambiar la respuesta a XML cambiando la anotación @Produces

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *