Construyendo aplicaciones Web con Go

Creando una aplicación web básica

Ahora que terminamos de repasar los conceptos básicos de HTTP, vamos a crear una sencilla pero útil aplicación web en Go.

Mejorando nuestro programa servidor de ficheros que implementamos en el capítulo anterior, vamos a implementar un pequeño editor de texto en el cual podemos introducir marcas del formato markdown, a partir del cual generaremos código HTML con el paquete github.com/russross/blackfriday.

Un formulario HTML

Para empezar, necesitamos un formulario HTML básico para introducir texto:

    <!DOCTYPE html>
    <html lang="es">
      <head>
        <meta charset="utf-8">
        <title>Generador de HTML</title>
        <link href="/css/bootstrap.min.css" rel="stylesheet">
      </head>
      <body>
        <div class="container">
          <div class="page-title">
            <h1>Editor de texto en formato markdown</h1>
            <p class="lead">Go genera HTML a partir de markdown</p>
            <hr />
          </div>

          <form action="/markdown" method="POST">
            <div class="form-group">
              <textarea class="form-control" name="cuerpo" cols="30" rows="10"></textarea>
            </div>

            <div class="form-group">
              <input type="submit" class="btn btn-primary pull-right" />
            </div>
          </form>
        </div>
        <script src="/js/bootstrap.min.js"></script>
      </body>
    </html>

Pon este código HTML en un fichero llamado index.html en el directorio "publico" de la aplicación y el bootstrap.min.css de http://getbootstrap.com/ en el directorio "publico/css". Observa que el formulario hace un POST HTTP al destino final "/markdown" de nuestra aplicación. Realmente en este momento todavía no manejamos esta ruta, por lo tanto la vamos a añadir.

La ruta "/markdown"

El programa para manejar la ruta '/markdown' y para servir el fichero index.html al público en general se ve así:

    package main

    import (
        "net/http"

        "github.com/russross/blackfriday"
    )

    func main () {
        http.HandleFunc("/markdown", GeneraDesdeMarkdown)
        http.Handle("/", http.FileServer(http.Dir("publico")))
        http.ListenAndServe(":8080", nil)
    }

    func GeneraDesdeMarkdown(rw http.ResponseWriter, r *http.Request) {
        html := blackfriday.MarkdownCommon([]byte (r.FormValue("cuerpo")))
        rw.Write(html)
    }

Dividamos este código en pequeñas piezas para tener una mejor idea de lo que está pasando:

http.HandleFunc("/markdown", GeneraDesdeMarkdown)
http.Handle("/", http.FileServer(http.Dir("publico")))

Estamos utilizando los métodos http.HandleFunc y http.Handle para definir algún sencillo enrutamiento para nuestra aplicación. Es importante señalar que llamar a http.Handle en el patrón "/" actuará como una ruta comodín que captura todo, motivo por el cual definimos esa ruta al último. http.FileServer devuelve un http.Handler así que usamos http.Handle para asignar una cadena de caracteres como patrón a un controlador. El método alternativo, http.HandleFunc, utiliza un http.HandlerFunc en lugar de un http.Handler. Este posiblemente sea más conveniente, para pensar en el manejo de las rutas a través de una función en lugar de con un objeto.

func GeneraDesdeMarkdown(rw http.ResponseWriter, r *http.Request) {
    html := blackfriday.MarkdownCommon([]byte (r.FormValue("cuerpo")))
    rw.Write (html)
}

Nuestra función GeneraDesdeMarkdown implementa la interfaz http.HandlerFunc estándar y renderiza código HTML de un campo del formulario que contiene texto con formato markdown. En este caso, el contenido se recupera con r.FormValue("cuerpo"). Es muy común conseguir entrada desde el objeto http.Request que recibe el http.HandlerFunc como argumento. Algunos otros ejemplos de entrada son los miembros r.Header, r.Body y r.URL.

Finalizamos la petición escribiendo a nuestro http.ResponseWriter. Nótese que no enviamos explícitamente un código de respuesta. Si escribimos a la respuesta sin un código, el paquete net/http asumirá que la respuesta es 200 OK. Esto significa que si sucedió algo malo para Go, debemos establecer el código de respuesta a través del método rw.WriteHeader().

http.ListenAndServe(":8080", nil)

La última parte de este programa inicia el servidor, le pasamos nil como nuestro controlador, con lo cual asume que las peticiones HTTP serán manejadas de manera predeterminada por los paquetes net/http y http.ServeMux, que se configuran utilizando http.Handle y http.HandleFunc, respectivamente.

Y eso es todo lo que se necesita para poder generar código HTML a partir de markdown con un servicio en Go. Es una sorprendentemente pequeña cantidad de código para la cantidad de trabajo pesado que hace. En el próximo capítulo aprenderemos cómo desplegar esta aplicación en la web usando Heroku.