Me siento frustrado por la cantidad de personas que llaman a cualquier interfaz basada en HTTP una API REST. El ejemplo de hoy es la API REST de SocialSite. Eso es RPC. Grita RPC. Hay tanto acoplamiento en la pantalla que se le debe dar una calificación X.
¿Qué se debe hacer para dejar claro el estilo arquitectónico REST sobre la noción de que el hipertexto es una restricción? En otras palabras, si el motor del estado de la aplicación (y, por lo tanto, la API) no está siendo impulsado por hipertexto, entonces no puede ser RESTful y no puede ser una API REST. Período. ¿Hay algún manual roto en algún lugar que deba repararse?
¿Qué se debe hacer para dejar claro el estilo arquitectónico REST sobre la noción de que el hipertexto es una restricción? En otras palabras, si el motor del estado de la aplicación (y, por lo tanto, la API) no está siendo impulsado por hipertexto, entonces no puede ser RESTful y no puede ser una API REST. Período. ¿Hay algún manual roto en algún lugar que deba repararse?
Con esto claro, en nuestra API no hay ningún enlace que dirija al método que expusimos en la entrada anterior: no se puede autodescubrir, o conoces la URL o navegando no hay un camino hasta ella. Vamos a añadir un link a nuestro nuevo endpoint para que no se frustre Roy.
Para ello vamos a usar
RepositorySearchesResource
. Éste bean permite añadir links a todos los que se crean automáticamente por Spring Data Rest. Hay varias formas de hacerlo, aunque las que he encontrado por Internet normalmente usan la versión antigua de HATEOAS (ResourceProcessor
como veíamos también en la documentación de la entrada anterior). Voy a hacerlo migrado ya a la versión actual y de la forma que me parece mejor por ser más reutilizable.Me voy a crear un bean del tipo
RepresentationModelProcessor<RepositorySearchesResource>
en mi clase de configuración. Es decir, voy a indicar el modo en el que se debe procesar el recurso utilizado para las búsquedas. El código quedaría así:@Bean
RepresentationModelProcessor<RepositorySearchesResource> searchLinks(RepositoryRestConfiguration config) {
return new RepresentationModelProcessor<RepositorySearchesResource>() {
@Override
public RepositorySearchesResource process(RepositorySearchesResource searchResource) {
if (searchResource.getDomainType().equals(PartidoConId.class)) {
try {
String nombreMetodo = "getPartidosConParticipanteComo";
Method method = PartidoController.class.getMethod(nombreMetodo, String.class,
PersistentEntityResourceAssembler.class);
URI uri = org.springframework.hateoas.server.mvc.WebMvcLinkBuilder
.linkTo(method, null, null).toUri();
String url = new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(),
config.getBasePath() + uri.getPath(), uri.getQuery(), uri.getFragment()).toString();
searchResource.add(new Link(url + "{?txt}", nombreMetodo));
} catch (NoSuchMethodException | URISyntaxException e) {
e.printStackTrace();
}
}
return searchResource;
}
};
}
Lo importante de todo este código es que el objeto searchResource
se usa para todos los /search
. Eso quiere decir que si añadimos un enlace aparecerá en todos ellos. Si queremos añadir el enlace en sólo uno (en nuestro caso para partidos) debemos filtrar para que coincida con el tipo correcto: PartidoConId
. Podría ponerse el enlace a mano, pero entonces cualquier cambio posterior nos obligaría a recordar que hay que cambiarlo aquí también.Lo mejor es recuperar el enlace que apunta a un método. Voy a usar
linkTo
y le pasaré el método al que quiero apuntar y los parámetros con null
(estos son para incluir valores en las variables del path y completar la URL, pero nuestro método sólo tiene query params).
NOTA: Para usar
linkTo
se puede usar la importación estática para evitar poner su paquete, pero lo he dejado en el código para que quede claro de dónde viene el método.
Lamentablemente, el link no incluye el
basePath
y hay que añadírselo (como dicen ellos: "por ahora") por eso se construye de nuevo la URI incluyéndolo. Para recuperar ese valor lo mejor es usar RepositoryRestConfiguration
que puede ser inyectada en el método.Ya con la información completa podemos añadir el enlace en
searchResource
incluyendo los query params.Si ejecutamos veremos que nuestro enlace aparece al final de los que se han añadido automáticamente.
No obstante, supongo que a cualquiera le dolerá ver esos "magic number" y pensará que debe haber una forma más automática de hacerlo. Personalmente no la he encontrado y tiene sentido (no se puede saber cómo se van a añadir los endpoints porque hay varias formas). Si alguno encuentra algo oficial agradecería que lo compartiera en los comentarios para completar la entrada.
Además en la siguiente entrada voy a añadir otro endpoint usando una variable en el path y también habrá que añadir el link.
Para arreglar esta falta de automatización, después de la siguiente entrada voy a compartir una clase de configuración base que puede utilizarse de manera generalizada en los proyectos igual que hicimos con el
jpa-config.xml
y explicaré la forma en que debe usarse. Así veremos que sólo con eso detecta y añade este endpoint y el que veamos a continuación que incluye path variable (y es otro parámetro que debemos controlar).Puedes obtener el código hasta aquí en su repositorio.
No hay comentarios:
Publicar un comentario