REST es una arquitectura muy popular en internet hoy, porque esta en estándares bien definidos y estrictos y es facil de entender y expandir. Más y más sitios web están basando sus diseños encima de REST. En esta sección, vamos a echarle un vistaso de cerca a la implementación de una arquitectura rEST en Go y (esperando) aprender como usarla para nuestro beneficio.
La primera declaración del concepto de REST fue (REpresentational State Transfer) en el año 2000 en la disertación de doctorado de Roy Thomas Fielding, que también es el cofundador del protocolo HTTP. Este especifica las restricciones de arquitectura y los principios, y cualquier cosa implementada en esta arquitectura puede se llamada sistema RESTful.
Antes que entendamos lo que es REST, necesitamos entender los siguientes conceptos:
-
Recursos
REST es la Capa de Presentación de la Transferencia de Estado, donde la capa de presentación actualmente es la capa de presentación del recurso.
Entonces ¿Qué son los recursos? Imagenes, documentos, videos, etc. Todos son ejemplos de recursos que pueden ser localizados por una URI.
-
Representación
Los recursos son entidades de información específica que pueden ser mostrados de una variedad de maneras en la capa de presentación. Por ejemplo, un documento TXT puede ser representado como un HTML, JSON, XML, etc; una imagen puede representarse como jpg, png, etc.
Las URIs son utilizadas para indentificar recursos, pero ¿cómo determinamos la manifestación específica? Está referido a los encabezados HTTP Accept y Content-Type; estos dos campos describen la capa de presentación.
- Estado de transferencia
Un proceso interactivo es iniciado entre el cliente y el servidor cada vez que visitas una página de un sitio web. Durante este proceso, ciertos datos relacionados con la página actual necesitan ser guardados. Sin embargo, ¡HTTP es un protocolo sin estado! Es obvio que necesitamos guardar este estado del cliente del lado del servidor. Esto prosigue en que si el cliente modifica alguna información y quiere que los cambios persistan, debe exister una manera de informar al servidor sobre el nuevo estado.
La mayor parte del tiempo, los clientes le informan al servidor los cambios de estado usadno HTTP. Existen cuatro operaciones con las que se hace esto:
- GET es usado para obteer recursos
- POST es usado para crear o actualizar recursos
- PUT es usado para actualizar recursos
- DELETE elimina recursos
Para resumir lo anterior:
- (1) Caca URI representa un recurso.
- (2) Existe una capa de presentación para transferir recursos entre clientes y servidores.
- (3) Los clientes usan 4 métodos HTTP para implementar la "Capa de Presentación de Transferencia de Estado", permitiéndoles a ellos operar con recursos remotos.
El principio mas importande de las aplicaciones web que implementan REST es que la interacción entre clientes y servidores es sin estado; cada petición debe encapsular toda la información requerida. Los servidores deberían ser capaces de reiniciarse en cualquier momento sin que los clientes sean notificados. Además, las peticiones pueden ser respondidas por cualquier servidor del mismo servicio, lo cual es ideal para la computación en la nube. Por último, como es sin estado, los clientes pueden cachear la data para mejorar el rendimiento.
Otro principio importante de un sistema REST es la delaminación, que significa que una capa no tiene una manera de interactuar directamente con componentes de otras capaz. Esto puede limitar la complejidad del sistema y motivar la independencia entre componentes inferiores.
Figura 8.5 Arquitectura REST
Cuando las restricciones RESTful son acatadas juiciosamente, las aplicaciones web pueden escalar para acomodarse a un número masivo de clientes. Usando una arquitectura rEST también podemos reducir las demoras entre clientes y servidores, simplificando la arquitectura y mejorando la visibilidad de los susbistemas.
Figure 8.6 Expansibilidad de REST
Go no tiene soporte durecto para REST, pero desde que las aplicaciones RESTful están basadas en HTTP, podemos usar el paquete net/http
para implementarla nosotros mismos. Por supuesto, primero necesitamos hacer algunas modificaciones antes de implementar completamente REST.
REST usa diferentes métodos para manejar recursos, dependiendo de la interacción que es requerida por ese recurso. Muchas aplicaciones existentes dicen ser RESTful pero no implementan REST. Voy a categorizar estas aplicaciones en varios niveles dependiendo de que métdos HTTP implementan.
Figura 8.7 Niveles de REST
La figura de arriba nos muestra tres niveles actualmente implementados en REST. puedes escoger no seguir todas las reglas y restricciones de REST cuando estás desarrollando tus aplicaciones propias, porque a veces no encajan en todas las situaciones. Las aplicaciones RESTful usan todos los métodos HTTP incluyendo DELETE
y PUT
, pero en muchos casos, los clientes solo envían peticiones GET
y POST
.
- El estándar de HTML permite a los clientes enviar
GET
yPOST
a través de enlaces y formularios. No es posible enviar peticionesPUT
oDELETE
sin soporte de AJAX. - Algunos firewalls interceptan peticiones
PUT
yDELETE
y los clientes tienenPOST
para implementarlos. Los servicios completamente RESTful usan los métodos originales HTTP y los reestablecen.
Podemos simular las peticiones PUT
y DELETE
agregando un campo oculto llamado _method
en nuestras peticiones POST
, sin embargo estas peticiones tienen que ser convertidas en el servidor antes de que puedan ser procesadas. En mis aplicaciones personales, uso este flujo de trabajo para implmentar iterfaces REST. Las interfaces RESTful son fáciles de implementar en Go, como se puede ver en el siguiente ejemplo:
package main
import (
"fmt"
"github.com/julienschmidt/httprouter"
"log"
"net/http"
)
func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprint(w, "Welcome!\n")
}
func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
fmt.Fprintf(w, "hello, %s!\n", ps.ByName("name"))
}
func getuser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
uid := ps.ByName("uid")
fmt.Fprintf(w, "you are get user %s", uid)
}
func modifyuser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
uid := ps.ByName("uid")
fmt.Fprintf(w, "you are modify user %s", uid)
}
func deleteuser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
uid := ps.ByName("uid")
fmt.Fprintf(w, "you are delete user %s", uid)
}
func adduser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
// uid := r.FormValue("uid")
uid := ps.ByName("uid")
fmt.Fprintf(w, "you are add user %s", uid)
}
func main() {
router := httprouter.New()
router.GET("/", Index)
router.GET("/hello/:name", Hello)
router.GET("/user/:uid", getuser)
router.POST("/adduser/:uid", adduser)
router.DELETE("/deluser/:uid", deleteuser)
router.PUT("/moduser/:uid", modifyuser)
log.Fatal(http.ListenAndServe(":8080", router))
}
Este ejemplo muestra como puedes escribir aplicaciones REST muy básicas. Nuestros recursos son usuarios y usamos diferentes funciones para diferentes métods. Aquí, importamos un paquete de terceros llamado github.com/julienschmidt/httprouter
. Ya hemos cubierto como implementar un manejador de rutas personalizado en capítulos anteriores. El paquete julienschmidt/httprouter
implementa un mapeo de rutas muy conveniente de seguir y muy fácil para implementar arquitecturas REST. Como puedes ver, REST requiere que implementes diferente lógica para cada método HTTP de el mismo recurso.
REST es un estilo de arquitectura web, construido en las experiencias pasadas con WWW: sin estado, centrado en los recursos, uso completo de protocolos HTTP y URI y la provisión de interfaces unificadas. Estas consideraciones de diseño superior le han permitido a REST convertirse en estándar mas popular para servicios web. En cierta manera, al enfatizar la carga en las URIs y el uso de estándares tempranos de Internet como HTTP, REST a pavimentado el camino para aplicaciones grandes y escalables. Actualmente el soporte que Go da para REST es muy básico, sin embargo, al implementar rutas personalizads y diferentes manejadores de petición para cada tipo de petición HTTP, podemos alcanzar una arquitectura RESTful en nuestras aplicaciones web de Go.