Creating a Basic Web App

Now that we are done going over the basics of HTTP, let’s create a simple but
useful web application in Go.

Pulling from our fileserver program that we implemented last chapter, we will
implement a Markdown generator using the github.com/russross/blackfriday
package.

HTML Form

For starters, we will need a basic HTML form for the markdown input:

  1. <html>
  2. <head>
  3. <link href="/css/bootstrap.min.css" rel="stylesheet">
  4. </head>
  5. <body>
  6. <div class="container">
  7. <div class="page-title">
  8. <h1>Markdown Generator</h1>
  9. <p class="lead">Generate your markdown with Go</p>
  10. <hr />
  11. </div>
  12. <form action="/markdown" method="POST">
  13. <div class="form-group">
  14. <textarea class="form-control" name="body" cols="30" rows="10"></textarea>
  15. </div>
  16. <div class="form-group">
  17. <input type="submit" class="btn btn-primary pull-right" />
  18. </div>
  19. </form>
  20. </div>
  21. <script src="/js/bootstrap.min.js"></script>
  22. </body>
  23. </html>

Put this HTML into a file named index.html in the “public” folder of our application
and the bootstrap.min.css from http://getbootstrap.com/ in the “public/css” folder.
Notice that the form makes an HTTP POST to the “/markdown” endpoint of our
application. We don’t actually handle that route right now, so let’s add it.

The “/markdown” route

The program to handle the ‘/markdown’ route and serve the public index.html
file looks like this:

  1. package main
  2. import (
  3. "net/http"
  4. "github.com/russross/blackfriday"
  5. )
  6. func main() {
  7. http.HandleFunc("/markdown", GenerateMarkdown)
  8. http.Handle("/", http.FileServer(http.Dir("public")))
  9. http.ListenAndServe(":8080", nil)
  10. }
  11. func GenerateMarkdown(rw http.ResponseWriter, r *http.Request) {
  12. markdown := blackfriday.MarkdownCommon([]byte(r.FormValue("body")))
  13. rw.Write(markdown)
  14. }

Let’s break it down into smaller pieces to get a better idea of what is going
on.

  1. http.HandleFunc("/markdown", GenerateMarkdown)
  2. http.Handle("/", http.FileServer(http.Dir("public")))

We are using the http.HandleFunc and http.Handle methods to define some
simple routing for our application. It is important to note that calling
http.Handle on the “/“ pattern will act as a catch-all route, so we define
that route last. http.FileServer returns an http.Handler so we use
http.Handle to map a pattern string to a handler. The alternative method,
http.HandleFunc, uses an http.HandlerFunc instead of an http.Handler.
This may be more convenient, to think of handling routes via a function
instead of an object.

  1. func GenerateMarkdown(rw http.ResponseWriter, r *http.Request) {
  2. markdown := blackfriday.MarkdownCommon([]byte(r.FormValue("body")))
  3. rw.Write(markdown)
  4. }

Our GenerateMarkdown function implements the standard http.HandlerFunc
interface and renders HTML from a form field containing
markdown-formatted text. In this case, the content is retrieved
with r.FormValue("body"). It is very common to get input from the
http.Request object that the http.HandlerFunc receives as an argument.
Some other examples of input are the r.Header, r.Body, and r.URL members.

We finalize the request by writing it out to our http.ResponseWriter. Notice
that we didn’t explicitly send a response code. If we write out to the response
without a code, the net/http package will assume that the response is a 200 OK. This means that if something did happen to go wrong, we should set the
response code via the rw.WriteHeader() method.

  1. http.ListenAndServe(":8080", nil)

The last bit of this program starts the server, we pass nil as our handler,
which assumes that the HTTP requests will be handled by the net/http packages
default http.ServeMux, which is configured using http.Handle and
http.HandleFunc, respectively.

And that is all you need to be able to generate markdown as a service in Go. It
is a surprisingly small amount of code for the amount of heavy lifting it does.
In the next chapter we will learn how to deploy this application to the web
using Heroku.