Interface http.Handler
Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy. Lição 77 de 107.
A interface http.Handler é a base da arquitetura de servidores web do Go. Ela define como as solicitações HTTP são processadas, e qualquer tipo que a implemente pode atender a solicitações da web.
A interface é extremamente simples:
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}Qualquer tipo com um método ServeHTTP pode lidar com solicitações HTTP. Aqui está um manipulador personalizado:
type GreetHandler struct {
Greeting string
}
func (h GreetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%s, visitor!", h.Greeting)
}Você pode usar este manipulador diretamente com um servidor:
handler := GreetHandler{Greeting: "Welcome"}
http.Handle("/greet", handler)Para casos mais simples, Go fornece http.HandlerFunc, um tipo que permite converter uma função comum em um manipulador:
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello!")
}
http.Handle("/hello", http.HandlerFunc(hello))O poder dessa interface fica claro quando você percebe que os handlers podem envolver outros handlers. Isso possibilita padrões de middleware nos quais você adiciona registro em log, autenticação ou outras preocupações transversais sem modificar a lógica original do handler.
Desafio
FácilVamos criar um sistema simples de manipuladores HTTP que simula como as solicitações web são processadas! Como não podemos executar um servidor HTTP real neste ambiente, você criará manipuladores que implementam a interface http.Handler e demonstrará como eles processam solicitações trabalhando com objetos simulados de solicitação/resposta.
Você organizará seu código em dois arquivos:
handlers.go: Defina seus manipuladores HTTP personalizados.Crie uma struct
MockResponseWriterque capture o que seria escrito em uma resposta HTTP. Ela deve armazenar o corpo da resposta como uma string e implementar um métodoWrite(data []byte) (int, error)que anexa os dados ao corpo. Adicione um métodoBody() stringpara recuperar a resposta acumulada.Crie uma struct
MockRequestcom campos stringPatheMethodpara simular uma solicitação HTTP.Agora crie duas structs de manipuladores que implementem o padrão da interface
http.Handler(com um métodoServeHTTPque recebe um*MockResponseWritere um*MockRequest):WelcomeHandlercom um campoMessage— escreve a mensagem seguida pelo caminho da solicitaçãoMethodHandler— escreve respostas diferentes com base no método da solicitação:"Fetching data"para GET,"Creating resource"para POST e"Method not supported"para qualquer outra opção
main.go: Processe solicitações por meio dos seus manipuladores.Leia um tipo de manipulador (
welcomeoumethod) e, em seguida, leia os detalhes da solicitação. Para o manipulador de boas-vindas, leia também a mensagem de boas-vindas.Crie o manipulador apropriado, construa uma solicitação simulada e chame
ServeHTTPpara processá-la. Imprima o corpo da resposta.
As seguintes entradas serão fornecidas:
- Linha 1: Tipo de manipulador (
welcomeoumethod) - Linha 2: Caminho da solicitação
- Linha 3: Método da solicitação
- Linha 4 (somente para welcome): Mensagem de boas-vindas
Por exemplo, considerando:
welcome
/home
GET
Hello fromSua saída deve ser:
Hello from /homeE considerando:
method
/api/users
POSTSua saída deve ser:
Creating resourceE considerando:
method
/api/data
GETSua saída deve ser:
Fetching dataE considerando:
method
/api/items
DELETESua saída deve ser:
Method not supportedEste desafio demonstra o conceito central da interface http.Handler: qualquer tipo com um método ServeHTTP pode lidar com solicitações. Em aplicações reais, o http.ResponseWriter e o *http.Request vêm da biblioteca padrão do Go, mas o padrão de implementação dos manipuladores permanece exatamente o mesmo.
Experimente você mesmo
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Ler o tipo de handler
scanner.Scan()
handlerType := scanner.Text()
// Ler o caminho da requisição
scanner.Scan()
path := scanner.Text()
// Ler o método da requisição
scanner.Scan()
method := scanner.Text()
// Criar requisição mock
request := &MockRequest{
Path: path,
Method: method,
}
// Criar escritor de resposta mock
response := &MockResponseWriter{}
// TODO: Com base em handlerType, crie o handler apropriado
// Se handlerType for "welcome", leia a mensagem de boas-vindas e crie WelcomeHandler
// Se handlerType for "method", crie MethodHandler
// Chame ServeHTTP no handler com response e request
if handlerType == "welcome" {
scanner.Scan()
message := scanner.Text()
// TODO: Crie WelcomeHandler com a mensagem e chame ServeHTTP
_ = message // Remova esta linha ao implementar
} else if handlerType == "method" {
// TODO: Crie MethodHandler e chame ServeHTTP
}
// Imprime o corpo da resposta
fmt.Println(response.Body())
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de OOP em Go
Arquivos ExternosWorkspace e Módulos do GoPacotes e ImportsNomes Exportados vs. Não ExportadosIntrodução à OOP em GoStructs como ClassesDefinindo Métodos em StructsReceptores de Ponteiro vs. de ValorInicialização de StructsFunções ConstrutorasRecapitulação — Calculadora Simples4Interfaces
Introdução às InterfacesImplementação ImplícitaInterface como ContratoInterface Vazia (any)Asserção de TipoSwitch de TipoComposição de InterfacesInterfaces Stringer e ErrorRecapitulação - Calculadora de Formas7Encapsulamento
Campos Exportados vs. Não ExportadosEncapsulamento no Nível de PacoteMétodos Getters e SettersOcultação de Informações em GoRecapitulação - Registros de Alunos10Genéricos (Go 1.18+)
Introdução aos genéricosParâmetros de tipoRestrições de tipoStructs genéricasAlternativa para métodos genéricosRecapitulação - Coleção genérica13Padrões de Projeto — Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão Abstract FactoryPadrão ObserverPadrão Strategy2Tipos e Structs em Profundidade
Tipos Básicos e CompostosDefinições de Tipos PersonalizadosTags de StructStructs AnônimasStructs AninhadasValores Zero e PadrõesRecapitulação - Livro de Contatos5Composição em vez de herança
Por que Go não tem herançaNoções básicas de incorporação de structsPromoção de métodosIncorporação de várias structsIncorporação vs agregaçãoOcultação de métodos incorporadosRecapitulação - Hierarquia de funcionários8Tratamento de Erros e OOP
A interface errorTipos de Erro PersonalizadosEncapsulamento de Erros (fmt.Errorf)Erros Sentinelaerrors.Is() e errors.As()Panic, Defer e RecoverRecapitulação - Analisador de Arquivos11Biblioteca Padrão e POO
io.Reader e io.Writersort.InterfaceInterface fmt.Stringerencoding/json com StructsInterface http.HandlerRevisão - Modelos de API REST3Ponteiros e Memória
Fundamentos de Ponteiros em GoPonteiros para StructsPassagem por Valor vs. ReferênciaA Função new()Coleta de Lixo em GoRecapitulação - Construtor de Lista Ligada6Polimorfismo em Go
Polimorfismo via InterfacesDuck Typing em GoRegras de Satisfação de InterfacesColeções PolimórficasInjeção de DependênciasRecapitulação - Processador de Pagamentos9Concorrência e OOP
Fundamentos de GoroutinesCanais e comunicaçãoCanais com e sem bufferInstrução selectsync.Mutex e sync.RWMutexsync.WaitGroupDesign de structs thread-safeRevisão - Worker PoolPratique por conta própria: Compilador de Go online