Criando um App Web Básico
Agora que terminamos de revisar o básico do HTTP, vamos criar uma aplicação web simples porém útil em Go.
Usando o nosso programa que serve arquivos implementado no último capítulo,
vamos implementar um gerador de Markdown usando o pacote github.com/russross/blackfriday.
Form HTML
Para começar, vamos precisar de um form HTML básico para o input em markdown:
<html>
<head>
<link href="/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="page-title">
<h1>Gerador de Markdown</h1>
<p class="lead">Gere o seu markdown usando Go</p>
<hr />
</div>
<form action="/markdown" method="POST">
<div class="form-group">
<textarea class="form-control" name="body" 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>
Coloque esse HTML em um arquivo chamdo index.html no diretório "public" da nossa aplicação
e o arquivo bootstrap.min.css do http://getbootstrap.com/ no diretório "public/css".
Note que o form envia os dados via HTTP POST para o endpoint "/markdown" da nossa aplicação.
Ainda não temos um handler para essa rota, então vamos criar um.
A rota "/markdown"
O programa para tratar a rota '/markdown' e servir o arquivo index.html a partir do diretório
public é assim:
package main
import (
"net/http"
"github.com/russross/blackfriday"
)
func main() {
http.HandleFunc("/markdown", GenerateMarkdown)
http.Handle("/", http.FileServer(http.Dir("public")))
http.ListenAndServe(":8080", nil)
}
func GenerateMarkdown(rw http.ResponseWriter, r *http.Request) {
markdown := blackfriday.MarkdownCommon([]byte(r.FormValue("body")))
rw.Write(markdown)
}
Vamos dividí-lo em partes menores para analisar melhor.
http.HandleFunc("/markdown", GenerateMarkdown)
http.Handle("/", http.FileServer(http.Dir("public")))
Estamos usando os métodos http.HandleFunc e http.Handle
para definir rotas simples para a nossa aplicação. É importante notar que
chamar o http.Handle usando o padrão "/" funciona como uma rota genérica
que pega todos os requests, por isso definimos ela por último.
O http.FileServer retorna um http.Handler então usamos o http.Handle
para mapear um padrão em string para um handler. A forma alternativa,
http.HandleFunc, usa um http.HandlerFunc em vez de um http.Handler.
Pode ser mais conveniente pensar dessa forma, tratar rotas através de uma
função em vez de um objeto.
func GenerateMarkdown(rw http.ResponseWriter, r *http.Request) {
markdown := blackfriday.MarkdownCommon([]byte(r.FormValue("body")))
rw.Write(markdown)
}
Nossa função GenerateMarkdown implementa a interface padrão http.HandlerFunc
e renderiza HTML a partir de um campo do form contendo texto formatado em markdown.
Nesse caso, o conteúdo do campo é obtido através do r.FormValue("body").
É bem comum receber dados de input do objeto http.Request que o http.HandlerFunc
recebe como argumento. Alguns outros exemplos de input são os membros r.Header,
r.Body e r.URL.
Finalizamos o tratamento do request escrevendo no nosso http.ResponseWriter. Note
que não mandamos um código de resposta HTTP explicitamente. Quando escrevemos
no response sem definir um código, o pacote net/http assume que o código é um
200 OK. Isso significa que se algo tivesse dado errado, deveríamos setar o código
através do método rw.WriterHeader().
http.ListenAndServe(":8080", nil)
A última parte do programa inicia o servidor e passamos nil como handler,
que assume que os requests HTTP serão gerenciados pelo http.ServeMux padrão
do pacote net/http, que é configurado usando o http.Handle e o http.HandleFunc.
Isso é tudo que é necessário para gerar markdown como um serviço em Go. É uma quantidade surpreendentemente pequena de código para a quantidade de trabalho pesada que está sendo feita. No próximo capítulo vamos aprender como fazer deploy da nossa aplicação para web usando o Heroku.