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.