Desafio Go
Middleware com closures
Enunciado
Crie um sistema de middlewares usando closures. Defina um tipo Handler que é func(string) string. Crie uma função aplicarMiddlewares que recebe um Handler e uma lista de middlewares (cada um é func(Handler) Handler) e retorna o Handler final. Implemente dois middlewares: comPrefixo que adiciona ">> " ao início da resposta, e comMaiusculas que converte a resposta para maiúsculas. No main, aplique ambos a um handler que retorna "olá, " + nome e teste com "mundo".
Requisitos
- O tipo
Handleréfunc(string) string. - Os middlewares têm assinatura
func(Handler) Handler. - A função
aplicarMiddlewaresaplica os middlewares na ordem em que aparecem na lista. - A saída final para
"mundo"é">> OLÁ, MUNDO".
Código inicial
package main
import (
"fmt"
"strings"
)
type Handler func(string) string
// comPrefixo adiciona ">> " ao início da resposta.
func comPrefixo(h Handler) Handler {
// implemente aqui
return nil
}
// comMaiusculas converte a resposta para maiúsculas.
func comMaiusculas(h Handler) Handler {
// implemente aqui
return nil
}
// aplicarMiddlewares aplica os middlewares na ordem.
func aplicarMiddlewares(h Handler, middlewares ...func(Handler) Handler) Handler {
// implemente aqui
return nil
}
func main() {
// handler base
base := func(nome string) string {
return "olá, " + nome
}
// aplique os middlewares e imprima o resultado
}
Saída esperada
>> OLÁ, MUNDO
Ver dica
Cada middleware retorna uma nova função que chama o handler original e modifica o resultado. Em aplicarMiddlewares, itere sobre os middlewares e vá envolvendo o handler. A ordem importa: o primeiro middleware da lista é o mais externo.
Mostrar solução
package main
import (
"fmt"
"strings"
)
type Handler func(string) string
// comPrefixo adiciona ">> " ao início da resposta.
func comPrefixo(h Handler) Handler {
return func(s string) string {
return ">> " + h(s)
}
}
// comMaiusculas converte a resposta para maiúsculas.
func comMaiusculas(h Handler) Handler {
return func(s string) string {
return strings.ToUpper(h(s))
}
}
// aplicarMiddlewares aplica os middlewares na ordem em que aparecem.
func aplicarMiddlewares(h Handler, middlewares ...func(Handler) Handler) Handler {
for _, m := range middlewares {
h = m(h)
}
return h
}
func main() {
base := func(nome string) string {
return "olá, " + nome
}
// Aplica comPrefixo e depois comMaiusculas
handler := aplicarMiddlewares(base, comPrefixo, comMaiusculas)
fmt.Println(handler("mundo"))
}
Passo a passo
- Definimos
Handlercomofunc(string) string, uma função que recebe e retorna string. comPrefixorecebe umHandlere retorna uma nova closure. Essa closure chama o handler original e adiciona">> "ao resultado.comMaiusculassegue o mesmo padrão, mas aplicastrings.ToUpperno resultado do handler original.aplicarMiddlewaresitera sobre a lista de middlewares. Para cada um, substituihporm(h), envolvendo o handler anterior.- Como
comPrefixovem primeiro, ele envolve obase. DepoiscomMaiusculasenvolve o resultado decomPrefixo. - No
main, chamamoshandler("mundo"). A execução ocorre de dentro para fora:basegera"olá, mundo",comPrefixoadiciona">> "resultando em">> olá, mundo", ecomMaiusculastransforma em">> OLÁ, MUNDO". - O resultado é impresso.
Por que funciona
Cada middleware é uma closure que captura o handler anterior. Ao encadear, criamos uma composição de funções. A ordem da lista define a ordem de execução: o primeiro middleware é o mais externo, então sua transformação ocorre por último na saída. Isso é o padrão de middlewares em servidores HTTP, por exemplo.
Erros comuns
- Inverter a ordem dos middlewares: se passar
comMaiusculasantes decomPrefixo, a saída seria">> OLÁ, MUNDO"? Não, seria">> OLÁ, MUNDO"? Vamos ver:comMaiusculasenvolvebase, depoiscomPrefixoenvolve esse resultado. A execução:base->"olá, mundo",comMaiusculas->"OLÁ, MUNDO",comPrefixo->">> OLÁ, MUNDO". O resultado é o mesmo! Mas em middlewares reais, a ordem altera o comportamento. - Esquecer de retornar a closure: se
comPrefixoretornarnil, o programa entra em pânico ao chamar o handler. - Modificar o handler original em vez de envolver: não faça
h = func...dentro do middleware; retorne uma nova função.
Outra forma de resolver
Usar uma struct com método Aplicar para middlewares, mas closures são mais concisas e idiomáticas em Go para esse caso.
Saída esperada
>> OLÁ, MUNDO