ZetCode

Go HTTP server

last modified November 26, 2020

Go HTTP server tutorial shows how to create simple HTTP servers in Golang.

HTTP

The Hypertext Transfer Protocol (HTTP) is an application protocol for distributed, collaborative, hypermedia information systems. HTTP protocol is the foundation of data communication for the World Wide Web.

Go http

In Go, we use the http package to create GET and POST requests. The package provides HTTP client and server implementations.

Go simple HTTP server

In the following example, we create a simple HTTP server in Go.

simple_server.go
package main

import (
    "fmt"
    "log"
    "net/http"
)

func main() {

    http.HandleFunc("/", HelloHandler)
    fmt.Println("Server started at port 8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

func HelloHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, there\n")
}

The example creates a simple HTTP server listening on port 8080. Upon sending a request, the server responds with a "Hello, there" message.

http.HandleFunc("/", HelloHandler)

The HandleFunc registers the handler function for the given URL pattern.

log.Fatal(http.ListenAndServe(":8080", nil))

The ListenAndServe listens on the TCP network address and then handles requests on incoming connections.

func HelloHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, there\n")
}

The handler responds to an HTTP request. It takes two parameters: the response writer and the request object.

$ go run get_post.go 
Starting server at port 8080

We start the server.

$ curl localhost:8080/
Hello, there

We generate a GET request to the server with the curl tool.

Go URL path parameter

We can send data to the server in the URL.

greet.go
package main

import (
    "fmt"
    "log"
    "net/http"
)

func main() {

    http.HandleFunc("/", HelloServer)
    fmt.Println("Server started at port 8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

func HelloServer(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, %s!\n", r.URL.Path[1:])
}

In the example, we get the URL path value with r.URL.Path[1:] and build a message with the data.

$ go run greet.go 
Server started at port 8080

We start the server.

$ curl localhost:8080/John
Hello, John!

We send the name inside the URL path; the server responds with a greeting.

Go query parameter

A query string is a part of a uniform resource locator (URL) that assigns values to specified parameters.

A generic URL has the following form:

scheme:[//[user:password@]host[:port]][/]path[?query][#fragment]

The query parameters start with the ? character. Multiple query parameters are separated with & character.

https://example.com/path/page?name=John&occupation=teacher

This is an example of a URL with two query parameters.

query_param.go
package main

import (
    "fmt"
    "log"
    "net/http"
)

func main() {

    http.HandleFunc("/", handler)

    fmt.Printf("Starting server at port 8080\n")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

func handler(w http.ResponseWriter, r *http.Request) {

    keys, ok := r.URL.Query()["name"]

    name := "guest"

    if ok {

        name = keys[0]
    }

    fmt.Fprintf(w, "Hello %s!\n", name)
}

In the example, we accept a name parameter. We get the parameter with r.URL.Query()["name"].

$ curl localhost:8080/?name=Peter
Hello Peter!

We send the name as a query parameter; the server responds with a message.

Go file server

With http.FileServer, we send files to the client.

public/about.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>About page</title>
</head>
<body>
    <p>
        About page
    </p>
</body>
</html>

This is the about.html page.

public/file_server.go
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Home page</title>
</head>
<body>
    <p>
        Home page
    </p>

</body>
</html>

This is the home page.

file_server.go
package main

import (
    "fmt"
    "io"
    "log"
    "net/http"
)

func main() {

    fileServer := http.FileServer(http.Dir("./public"))
    http.Handle("/", fileServer)

    http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
        io.WriteString(w, "Hello there!\n")
    })

    fmt.Printf("Starting server at port 8080\n")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

In the example, we have a file server and a simple hello handler.

fileServer := http.FileServer(http.Dir("./public"))
http.Handle("/", fileServer)

A file server is registered with Handle; it serves files from the public directory.

$ curl localhost:8080
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Home page</title>
</head>
<body>
    <p>
        Home page
    </p>

</body>
</html>
$ curl localhost:8080/about.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>About page</title>
</head>
<body>
    <p>
        About page
    </p>
</body>
</html>

We request the home page and the about page.

Go process GET/POST request

In the following example, the servers processes the GET and the POST requests from a client.

form.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Form</title>
</head>
<body>

    <form method="POST" action="/">
        <div>
            <label>Name:</label><input name="name" type="text">
        </div>
        <div>
            <label>Occupation:</label><input name="occupation" type="text">
        </div>
        <button type="submit" value="submit">Submit</button>
    </form>

</body>
</html>

The HTML page presents a simple form.

get_request.go
package main

import (
    "fmt"
    "log"
    "net/http"
)

func process(w http.ResponseWriter, r *http.Request) {

    if r.URL.Path != "/" {
        http.Error(w, "404 not found.", http.StatusNotFound)
        return
    }

    switch r.Method {
    case "GET":

        http.ServeFile(w, r, "form.html")
    case "POST":

        if err := r.ParseForm(); err != nil {
            fmt.Fprintf(w, "ParseForm() err: %v", err)
            return
        }

        name := r.FormValue("name")
        occupation := r.FormValue("occupation")

        fmt.Fprintf(w, "%s is a %s\n", name, occupation)

    default:
        fmt.Fprintf(w, "Sorry, only GET and POST methods are supported.")
    }
}

func main() {

    http.HandleFunc("/", process)

    fmt.Printf("Starting server at port 8080\n")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

For a GET request, we send a web page with a form. For a POST request, we process the data from the form.

case "GET":

    http.ServeFile(w, r, "form.html")

If the request is a GET request, we send the form.html to the client.

case "POST":

    if err := r.ParseForm(); err != nil {
        fmt.Fprintf(w, "ParseForm() err: %v", err)
        return
    }

In case of a POST request, we call the ParseForm function; it parses the raw query from the URL and updates r.Form.

name := r.FormValue("name")
occupation := r.FormValue("occupation")

fmt.Fprintf(w, "%s is a %s\n", name, occupation)

We get the form values with FormValue and build a message.

In this tutorial, we have created simple HTTP servers in Go.

List all Go tutorials.