En esta parte se complica bastante porque se juntan 2 conceptos que no se tocaron tan a detalle:
El tipo func: Es un type que es una función. Lo que hace es definir una firma definida y las funciones que cuadren con esa firma se consideran de ese tipo. Similar a los métodos de las interfaces.
Closures: Funciones anónimas que tienen acceso al scope que las está rodeando.
Se complica un poco más porque tenemos dos func types anidadas.
Aquí retorna un a func type Middleware Lo que significa que retorna una función con la firma func(http.HandlerFunc) http.HandlerFunc. Por eso regresa la función de la manera en que vemos:
returnfunc(f http.HandlerFunc) http.HandlerFunc
Lo relevante es que http.HandlerFunc también es una func type por eso debe tener en otro return la firma que tienen los handlers:
returnfunc(w http.ResponseWriter, r *http.Request)
Así explícitamente está regresando la firma definida.
Hasta aquí todo me hacia sentido, pero me preguntaba. ¿Cómo es que en main podemos pasarla sin parámetros y en AddMiddlewares cuando se vuelve m(f) si lleva uno? ¿Cómo llega esa f al final?
Luego de varios test haciendo debugging (y leer más acerca de closures), encontré que CheckAuth() se ejecutaba 3 veces dependiendo la sección y la firma con la que se llamó. Dejé los prints para experimentar como salía y fue así.
En Main cuando se mandaba a llamar solo CheckAuth() sin parámetros imprimía 1 y nada más, como si solo se inicializara la función y su scope. En AddMiddleware se ejecutaba la función del primer return y únicamente ese scope, ya teniendo acceso a la variable check, por eso se imprimía 2. Mientras que al final cuando hacia el request a localhost y ya llegaban el (writer y request) se ejecutaba la función del segundo return. Pero en esta se volvía a imprimir 2 porque la anterior modificación no persistía. Como en el ejemplo se quedaron las funciones en blanco era difícil de percibir, pero creo es un comportamiento interesante de las func types y confuso con tanto func type.
Un ejemplo más sencillo de visualizar:
type Add func(int)intfuncadder() Add {// es decir regresa una función con firma func(int) int sum :=0returnfunc(x int)int{ sum += x
return sum
}}funcmain(){// se manda a llamar sin recibir valores porque asi es la firma// pareciera solo se inicializara la variable función// asignando el valor de cero a la variable sum de dentro pos, neg :=adder(),adder()for i :=0; i <10; i++{ fmt.Println(// aquí es la verdadera implementación ya recibiendo un argumento// y se ejecuta la funcion del returnpos(i),neg(-2*i),)}}
Gracias Avelino Sánchez por tomarte la molestia detallando en tu comentario el ejemplo.
Como mencionas, es algo interesante pero bastante complejo.
Un saludo
en la sesion 34 estaba el codigo de AddMidleware. Que mala edición de los videos.
alguien me podría explicar qué hace esto??
for _,m:= range middlewares { f =m(f)}
Entiendo que itera los middlewares y toma cada uno, pero f es el http.HandlerFunc que recibimos por parámetro, qué está haciendo cuando asigna a f m(f) ???
Esta creando un Wrapper para la función handler original y al reasignar a f, el wrapper substituye la función original.
Un Wrapper en este caso es una función que ejecuta algo antes de invocar la función original.
wrapper = m(f)
De esa forma, si hubiera mas de un middleware definido, en la siguiente iteración del for el argumento es el wrapper ya no la función original.
Si por ejemplo en el slice de middlewares hubiera 3 de ellos, seria el equivalente a anidar 3 veces la función:
fFinal = m3(m2(m1(f)))
Sería bueno que usen otros tipos de nombres para identificar los handlers y no solo f así es difícil de entender
Ejemplo:
func CheckAuth()Middleware{returnfunc(nextHandler http.HandlerFunc) http.HandlerFunc{returnfunc(w http.ResponseWriter, r *http.Request){// Here we do the authentication logic fmt.Println("Authentication Middleware")// and then we call the next middleware in the chainnextHandler(w, r)}}}
SIn una explicación previa sobre funciones y clousres, esta sesión se complica extremadamente, hubiese sido mejor que agregaran un modulo explicando esto en vez de no sé todo eso que se hizo con la calculadora al comienzo que era super básico y sencillo
Para los que no pueden ver el autocompletar de Vscode en su código Go les dejo este tutorial muy bueno que me funcionó, es útil esta función ya que después de tanto código, tantos struct y funciones es necesario para no perderse
Es más fácil usar ...Middleware y menos verboso en el código
package main // Conoce todo lo de este paqueteimport"net/http"// Puerto del servidortype Server struct { port string
router *Router}// Instanciar servidor y escuchar conexcionesfunc NewServer(port string)*Server{return&Server{port: port,router:NewRouter(),}}// Asioca un handler con una rutafunc(s *Server)Handle(path string, handler http.HandlerFunc){ s.router.rules[path]= handler
}func(s *Server)AddMidleware(f http.HandlerFunc, middlewares ...Middleware) http.HandlerFunc{for _,m:= range middlewares { f =m(f)}return f
}func(s *Server)Listen() error {// Punto de entrada de la aplicacion http.Handle("/", s.router)// Seguno parametro es un handlererr:= http.ListenAndServe(s.port, nil)return err
}
En Go, Cómo se podría reducir el riesgo de suplantación de identidad o de ataques tipo Man in the Middle, que pueden porpagarse como middleware maliciosos ?
Alguien sabe como desactivar los subtitulos automaticos?
¡Hola Andres! 😄
En la barra de reproducción del video da click al icono que está entre el selector de velocidad y el marcador y luego en Subtitles off
¡Nunca pares de aprender! 💚
Gracias Tania,
Lo que busco es no estar haciendo eso en cada video que queden desactivados para siempre en los siguientes videos.
Hola como están es que no veo el código de
type Middleware func(http.HandlerFunc) http.HandlerFunc{
?
}
existe algún repositorio que el profesor haya suministrado?
package main
import (
"net/http"
)
type Middleware func(http.HandlerFunc) http.HandlerFunc
¿No hay una forma de renombrar, así sea internamente esos http.HandlerFunc y demás nombres (similar a como se hace en JS)? es que eso hace el código innecesariamente verboso, largo e ilegible.
Hasta lo que he entendido creo que Go no permite renombrar dichas funciones, lo que se me ocurre es usar las variables en las funciones
Habrá otra forma de hacer lo mismo?
Está iterando sobre los middleware para retornar un acumulador de funciones. Supongo que el proceso será una llamada recursiva. Pero se obtiene el mismo resultado con un array de funciones
cuando está en el for
y llega a tener esta estructura
fFinal = m3(m2(m1(f)))
de qué manera se comienza a llamar? m1 o desde m3?
Creo que es m1, o en su defecto, el que se encuentre en la primera posición
Me da este error:
./middleware.go:9:9: cannot use func literal (type func(http.HandlerFunc) http.HandlerFunc) as type Middleware in return argument
middleware.go
package main
import("fmt""net/http")func CheckAuth()Middleware{returnfunc(f http.HandlerFunc) http.HandlerFunc{returnfunc(w http.ResponseWriter, r *http.Request){flag:=false fmt.Println("Checking auth")if flag {f(w, r)}else{return}}}}
Ya lo arregle, era un error al definir el tipo de Middleware