Se solicita información sobre el paradero del estudiante Arshak Karhanyan

Clase 15

Viernes (Noche, 2025)

Temario

En esta clase los conceptos de arquitectura Web y sus protocolos. Para ello, y teniendo en cuenta que algunos de estos temas ya han sido dados en la materia de Desarrollo de Software, dejamos un video de repaso que cubre los temas de:

  1. La web y su historia
  2. Las arquitecturas cliente-servidor
  3. El protocolo HTTP
  4. El patrón MVC

Luego, profundizamos en la distinción entre cliente pesado y cliente liviano, el protocolo HTTP y las convenciones REST.

Por último, presentamos Javalin, un framework muy liviano para exponer nuestra aplicación via HTTP, y daremos un ejemplo de exposición de un API REST JSON y de una aplicación HTML.

Resumen

Primera parte: modelado REST

Esta primera parte está guiada por el ejercicio de QMP7.

Como usuarie de QueMePongo quiero ver todas las prendas que tengo en mi guardarropas desde el navegador para poder administrarlas.

Algunas opciones:

GET http://localhost:5000/api/[controller]/guardarropa
GET http://www.quemepongo.com/guardarropas/{id}/prendas
GET http://www.quemepongo.com/guardarropas/prendas
GET /quemepongo/{id_usuario}/guardarropas

Corolario 1: Cuidado, la URL/URI tiene que estar bien formada URI:

 protocolo://dominio[:puerto][/ruta]
 http://ddsjv.com:8080/algo

Otras opciones:

GET /api/[controller]/guardarropa
GET /guardarropas/{id}/prendas
GET /guardarropas/prendas
GET /quemepongo/{id_usuario}/guardarropas

Corolario 2: No nos va a importar ni el dominio, ni el puerto ni el protocolo para la comunicación de estar rutas

Veamos ahora la siguiente opción:

GET /api/[controller]/guardarropa # OJO, esto es una cuestión
                                  # de implementación
                                  # (además de que no sigue
                                  # ningún formato HTTP válido)

Corolario 3: Sólo nos vamos a concentrar en los problema de interfaz, no de implementación y vamos a respetar la estructura de HTTP y sus URLs

¿Y qué tal esta opción?

GET /quemepongo/{id_usuario}/guardarropas # OJO, vamos a evitar
                                         # colocar el nombre de
                                         # la aplicación en la ruta,
                                         # porque es **redundante**

Corolario 4: No vamos a incluir el nombre del sistema como parte de la ruta

GET /api/guardarropa # OJO, vamos a tener cuidado con utilizar prefijos como /api,
                     # **en principio** vamos a evitarlo
                     # Y en parciales NO lo usen y listo 😼

Corolario 5: Toda interfaz REST ES un API, independientemente de qué devuelva (de qué tipo de contenido, content-type en inglés), así que el /api es redundante

Si asumimos que tenemos un sólo guardarropas:

GET /guardarropas/prendas #  OJO, es redundante, porque el
                          # guardarropas ya es una colección de prendas

Corolario 6: vamos a evitar anidamientos innecesarios, que no aporten desde el punto de vista de la navegación (direccionamiento) de los recursos

GET /usuarios/{id}/prendas # OJO, no vamos a agregar información de sesión
                          # (es decir, que quién / en que
                          # contexto se está usando nuestra ruta)
                          # porque vamos a informarla utilizando
                          # otras herramientas:
                          #
                          # * Cabeceras (Basic Auth)
                          # * Cookies
                          # * Otras

¿Y por qué?

  • Porque es más limpio (hay que ingresar menos información en la ruta)
  • Porque es más seguro (porque no hay riesgo de que ingrese información de otre usuarie) No es que el manejo de sesión esté libre de hacks, pero eso es para otra materia :P
  • Porque es más fácil “espiar” por parte del servidor

Corolario 7: vamos a evitar expresar ideas de sesión (como por ejemplo id de usuario que está usando el sistema) como parte de la ruta

Mejores opciones son:

GET /guardarropas # un poco ambigua
                  # (interprentando _guardarropas_ como
                  # sinónimo de conjunto de prendas)
GET /prendas      # MEJOR

Se lee “Obtener todas las prendas”

Si asumimos que hay varios guardarropas por persona:

GET /guardarropas/{id}/prendas # OK, esto sí tiene sentido

Se lee “Obtener las prendas del guardarropas de id X”

Aclaración: las {} no son parte de HTTP, son una forma de expresar un patrón denominado uri-param, url-param, path-parm, parámetro de la ruta, etc:

  • /guardarropas/5/prendas
  • /guardarropas/10/prendas
  • /guardarropas/56/prendas
  • /guardarropas/89/prendas

Se podría haber expresado usando cualquiera de las siguientes convenciones:

  • /guardarropas/{id}/prendas
  • /guardarropas/[id]/prendas
  • /guardarropas/:id/prendas
  • /guardarropas/<id>/prendas

En resumen, lo que vimos fue una ruta de listado de recursos, también llamada colección:

GET /nombreDelRecursoEnPlural

Como usuario de QueMePongo, quiero crear una prenda desde el navegador:

POST /prendas/                   # esto está bien, asumiendo
                                 # que hay un solo guardarropas
POST /guardarropas/{id}/prendas/ # esto está bien, asumiendo que
                                 # hay múltiples guardarropas

# ¡Procuremos mantener consistencia con las decisiones del punto anterior 😉!

POST /prenda/ # OJO, no está en plural, no sigue la convención

Corolario 8: siempre las colecciones se escriben en plural

POST /guardarropas  # Quizás, pero como ya charlamos antes es ambiguo
POST /prendas/?id=2 # En principio no vamos a indicar el ID al crear un recurso,
                    # vamos a dejar que el sistema elija el
                    # mejor id vacante
                    # (Y SOBRE TODO EN PARCIALES)
  1. Al crear recursos, los ids deberían ser autogenerados, por lo que no los especificaremos.

En resumen, lo que vimos fue una ruta de creación

POST /nombreDelRecursoEnPlural

Como usuarie de QueMePongo quiero ver una prenda en particular que tengo en mi guardarropas para poder editarla

Para consulta:

GET /prendas/{id}
GET /guardarropas/{id}/prendas/{id} # Si hubiera varios guardarropas.
                                    # PEEEEEEROO incluso si hubiera varios
                                    # guardarropas, probablemente lo seguiría modelando como
                                    # GET /prendas/{id}

En resumen, lo que vimos fue una ruta de detalle

GET /nombreDelRecursoEnPlural/{id}

Para edición:

PATCH /prendas/{id}
PUT /prendas/{id}

En resumen, lo que vimos fue una ruta de edición

PUT /nombreDelRecursoEnPlural/{id}
PATCH /nombreDelRecursoEnPlural/{id}

Paréntesis: tipos de contenidos

$ curl -XGET http://qmp.com/prendas/42 -H "Accept: text/plain"
"Hola, soy un pantalón negro"
$ curl -XGET http://qmp.com/prendas/42 -H "Accept: application/json"
{
  "tipo": "pantalon",
  "color": "negro"
}
$ curl -XGET http://qmp.com/prendas/42 -H "Accept: text/xml"
<prenda>
  <tipo>pantalon</tipo>
  <color>negro</color>
</prenda>
$ curl -XGET http://qmp.com/prendas/42 -H "Accept: text/html"
<article>
  <span class="tipo">pantalon</span>
  <span class="color">negro</span>
</article>
  • Accept (Cabecera de pedido que indica como quiero que me representen algo)
  • Content-Type (Cabecera de respuesta que indica como está representado algo en mi respuesta)
  • Content-Type (Cabecera de pedido que indica como te estoy representado algo en mi pedod)

Ahora sí, asumiendo que hay un solo guardarropas:

$ curl -XPOST /prenda/ \
       -H 'Content-Type: application/json' \
       --data '{ "tipo": "pantalon", "color": "negro" }'

Ahora sí, asumiendo que hay un muchos guardarropas:

# OJO, no queremos romper la consistencia de nuestra rutas
$ curl -XPOST /prenda/ \
       -H 'Content-Type: application/json' \
       --data '{ "tipo": "pantalon", "color": "negro", "guardarropa_id": 15 }'
$ curl -XPOST /guardarropas/15/prenda/ \
       -H 'Content-Type: application/json' \
       --data '{ "tipo": "pantalon", "color": "negro" }' # ahora sí

Segunda parte: Javalin y exposición de APIs

Exploramos el código de un API REST JSON

  1. Observamos la estructura de archivos (modelos, controladores, archivo semilla, rutas y código de aplicación)
  2. Extendemos el API para /usuarios/{nombre}

Tercera parte: Javalin y exposición de contenido HTML

Exploramos el código de una Aplicación cliente liviano

Material

Para la próxima clase