Menu
Coddy logo textTech

Interfaz http.Handler

Parte de la sección Programación Orientada a Objetos del Journey de GO de Coddy. Lección 77 de 107.

La interfaz http.Handler es la base de la arquitectura de servidores web de Go. Define cómo se procesan las solicitudes HTTP, y cualquier tipo que la implemente puede atender solicitudes web.

La interfaz es extraordinariamente sencilla:

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

Cualquier tipo con un método ServeHTTP puede gestionar solicitudes HTTP. Aquí tienes un controlador personalizado:

type GreetHandler struct {
    Greeting string
}

func (h GreetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "%s, visitor!", h.Greeting)
}

Puedes usar este controlador directamente con un servidor:

handler := GreetHandler{Greeting: "Welcome"}
http.Handle("/greet", handler)

Para casos más sencillos, Go proporciona http.HandlerFunc, un tipo que te permite convertir una función normal en un controlador:

func hello(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello!")
}

http.Handle("/hello", http.HandlerFunc(hello))

El poder de esta interfaz se vuelve evidente cuando te das cuenta de que los controladores pueden envolver a otros controladores. Esto permite aplicar patrones de middleware en los que puedes añadir registro, autenticación u otras preocupaciones transversales sin modificar la lógica del controlador original.

challenge icon

Desafío

Fácil

¡Construyamos un sistema sencillo de controladores HTTP que simule cómo se procesan las solicitudes web! Como no podemos ejecutar un servidor HTTP real en este entorno, crearás controladores que implementen la interfaz http.Handler y demostrarás cómo procesan las solicitudes trabajando con objetos simulados de solicitud/respuesta.

Organizarás tu código en dos archivos:

  • handlers.go: Define tus controladores HTTP personalizados.

    Crea una estructura MockResponseWriter que capture lo que se escribiría en una respuesta HTTP. Debe almacenar el cuerpo de la respuesta como una cadena e implementar un método Write(data []byte) (int, error) que añada los datos al cuerpo. Añade un método Body() string para recuperar la respuesta acumulada.

    Crea una estructura MockRequest con campos de tipo cadena Path y Method para simular una solicitud HTTP.

    Ahora crea dos estructuras de controlador que implementen el patrón de la interfaz http.Handler (con un método ServeHTTP que reciba un *MockResponseWriter y un *MockRequest):

    • WelcomeHandler con un campo Message: escribe el mensaje seguido de la ruta de la solicitud
    • MethodHandler: escribe respuestas diferentes según el método de la solicitud: "Fetching data" para GET, "Creating resource" para POST y "Method not supported" para cualquier otro método
  • main.go: Procesa las solicitudes mediante tus controladores.

    Lee un tipo de controlador (welcome o method) y después lee los detalles de la solicitud. Para el controlador de bienvenida, lee también el mensaje de bienvenida.

    Crea el controlador adecuado, construye una solicitud simulada y llama a ServeHTTP para procesarla. Imprime el cuerpo de la respuesta.

Se proporcionarán las siguientes entradas:

  • Línea 1: Tipo de controlador (welcome o method)
  • Línea 2: Ruta de la solicitud
  • Línea 3: Método de la solicitud
  • Línea 4 (solo para welcome): Mensaje de bienvenida

Por ejemplo, dada la siguiente entrada:

welcome
/home
GET
Hello from

Tu salida debe ser:

Hello from /home

Y dada la siguiente entrada:

method
/api/users
POST

Tu salida debe ser:

Creating resource

Y dada la siguiente entrada:

method
/api/data
GET

Tu salida debe ser:

Fetching data

Y dada la siguiente entrada:

method
/api/items
DELETE

Tu salida debe ser:

Method not supported

Este desafío demuestra el concepto fundamental de la interfaz http.Handler: cualquier tipo que tenga un método ServeHTTP puede gestionar solicitudes. En aplicaciones reales, http.ResponseWriter y *http.Request provienen de la biblioteca estándar de Go, pero el patrón de implementación de controladores sigue siendo exactamente el mismo.

Pruébalo tú mismo

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Leer el tipo de handler
	scanner.Scan()
	handlerType := scanner.Text()
	
	// Leer la ruta de la solicitud
	scanner.Scan()
	path := scanner.Text()
	
	// Leer el método de la solicitud
	scanner.Scan()
	method := scanner.Text()
	
	// Crear la solicitud mock
	request := &MockRequest{
		Path:   path,
		Method: method,
	}
	
	// Crear el escritor de respuesta mock
	response := &MockResponseWriter{}
	
	// TODO: Basado en handlerType, crear el handler apropiado
	// Si handlerType es "welcome", leer el mensaje de bienvenida y crear WelcomeHandler
	// Si handlerType es "method", crear MethodHandler
	// Llamar a ServeHTTP en el handler con response y request
	
	if handlerType == "welcome" {
		scanner.Scan()
		message := scanner.Text()
		// TODO: Crear WelcomeHandler con el mensaje y llamar a ServeHTTP
		_ = message // Eliminar esta línea al implementar
	} else if handlerType == "method" {
		// TODO: Crear MethodHandler y llamar a ServeHTTP
	}
	
	// Imprime el cuerpo de la respuesta
	fmt.Println(response.Body())
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos

Practica por tu cuenta: Compilador de Go online