Los controladores son un tema bastante familiar en otras comunidades de desarrollo web. Como la mayoría de los desarrolladores web está alrededor de una interfaz de poderosos red/http, ni muchas implementaciones del regulador han pegado fuerte. Sin embargo, hay un gran beneficio en el uso de un modelo controlador. Permite limpias y bien definidas abstracciones más allá de lo de la interfaz de controlador de red/http solo puede proporcionar.
En este ejemplo vamos a experimentar con la construcción de nuestra propia implementación de controlador utilizando algunas de las características estándar en Go. Pero primero, vamos a empezar con los problemas que estamos tratando de resolver.
Digamos que estamos usando el paquete render
de la biblioteca estándar
del que hablamos en capítulos anteriores:
var render = render.New(render.Options{})
Si queremos que nuestros http.Handler
s puedan acceder a nuestra instancia render.Render
, tenemos un par de opciones.
http.Handler
: Esta es
una gran idea, y la deberíamos estar usando la mayor parte del tiempo.La aplicación termina pareciéndose a esto:
func MiControlador (r *render.Render) http.Handler {
return http.HandlerFunc(func (rw http.ResponseWriter, r *http.Request) {
// ahora podemos acceder a 'r'
})
}
Cuando el programa crece en tamaño, comenzarás a notar que muchos de tus
http.Handler
s compartirán las mismas dependencias y tendrás una gran
cantidad de estos cierres http.Handler
s con los mismos argumentos. La
forma en que me gusta limpiar esto es escribiendo una implementación del
controlador base que me ofrezca un par de pequeñas victorias:
http.Handler
s que tienen objetivos o conceptos similares.¡Gran parte de los controladores nos proporcionan todas estas cosas sin importar un paquete externo! La mayor parte de esta funcionalidad viene de un uso inteligente del conjunto de características Go, a saber estructuras Go e incrustación. Echemos un vistazo a la implementación.
package main
import "net/http"
// Acción define una firma de función estándar para que la podamos utilizar
// al crear acciones del controlador. Una acción del controlador básicamente
// es un método asociado a un controlador.
type Acción func(rw http.ResponseWriter, r *http.Request) error
// Este es nuestro controlador base
type ControladorAplic struct {}
// La función Acción ayuda con el manejo de errores en un controlador
func (c *ControladorAplic) Acción(a Acción) http.Handler {
return http.HandlerFunc(func (rw http.ResponseWriter, r *http.Request) {
if err := a(rw, r); err != nil {
http.Error(rw, err.Error(), 500)
}
})
}
¡Eso es todo! Esa es toda la aplicación en que debemos tener el poder de los controladores a nuestro alcance. Todo lo que resta por hacer es implementar un controlador de ejemplo:
package main
import (
"net/http"
"gopkg.in/unrolled/render.v1"
)
type miControlador struct {
ControladorAplic
*render.Render
}
func (c *miControlador) Índice(rw http.ResponseWriter, r *http.Request) error {
c.JSON(rw, 200, map[string]string {"Hola": "JSON"})
return nil
}
func main() {
c := &miControlador {Render: render.New(render.Options{})}
http.ListenAndServe(":8080", c.Acción(c.Índice))
}