Building a URL Shortener in Go: A Step-by-Step Guide
Tags: go, backenddevelopment, programming, webdev
Published: 2024-03-03 21:06:56

Introduction

A server is a specialized system whose role is to respond to requests made by computers over a network. Servers are very critical since they provide hosting for websites and applications, and they also facilitate communication over a network. In this article, let's dive into creating a simple HTTP server that serves files and handles form submissions and requests to specific endpoints.
Prerequisites

    Basic understanding of Go and web development concepts.

    Must have Go installed. If you do not have Go installed, first navigate here https://go.dev/doc/manage-install to install Go.

Project directory structure

    Open terminal.

    Create a directory with the name 'WebServer'.

    Navigate into the 'WebServer' directory.

    Initialize a new Go module.

    Create a file with the name 'main.go'.

    Create a new directory inside the 'WebServer' directory and name it 'files'.

    Navigate into the files directory.

    Create two files with the names index.html and form.html.

     mkdir WebServer
     cd WebServer
     go mod init example/WebServer
     touch main.go
     mkdir files
     cd files
     touch index.html
     touch form.html

The code

    Open the index.html file and write the code as shown below. This will display a static web page.

  <html>
      <head>
          <title>static website</title>        
      </head>
      <body>
          <h2>static website</h2>
      </body>
  </html>

Open the form.html file and write the code as shown below: When rendered, this will display a form with name and address text fields.

  <!DOCTYPE html>
  <html>
      <head>
          <meta charset = "UTF-8"/>
      </head>
      <body>
          <div>
              <form method="POST" action="/form">
              <label>Name</label><input name="name" type="text" value=""/>
              <label>Address</label><input name="address" type="text" value=""/>

              <input type="submit" value="submit"/>
              </form>
          </div>
      </body>
  </html>

Open main.go. Here we start off by declaring the main package, then import the packages that are necessary for the working of our program.

      package main

      import (
          "fmt"
          "log"      // Importing the log package for logging
          "net/http" // Importing the net/http package for HTTP server functionality
      )

    Next we create a function that handles form submissions.

func formHandler(w http.ResponseWriter, r *http.Request) {
    // ParseForm parses the raw query from the URL and updates r.Form
    if err := r.ParseForm(); err != nil {
        fmt.Fprintf(w, "ParseForm() err: %v", err)
        return
    }
    fmt.Fprintf(w, "POST request successful")
    name := r.FormValue("name")               // Retrieve the value of the 'name' parameter from the form
    address := r.FormValue("address")         // Retrieve the value of the 'address' parameter from the form
    fmt.Fprintf(w, "Name = %s\n", name)       // Print the name to the response writer
    fmt.Fprintf(w, "Address = %s\n", address) // Print the address to the response writer
}

    Create a function that handles requests to the /hello endpoint.

func helloHandler(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path != "/hello" {
        http.Error(w, "404 not found", http.StatusNotFound)
        return
    }
    if r.Method != "GET" {
        http.Error(w, "method is not supported", http.StatusNotFound)
        return
    }
    fmt.Fprintf(w, "hello!") // Respond with "hello!" for GET requests to /hello endpoint
}

    Create a main function that defines a simple HTTP server that serves static files from the ./files directory and handles requests to specific endpoints (/form and /hello) with custom handler functions.

func main() {
    fileServer := http.FileServer(http.Dir("./files"))
    // Create a file server handler for serving static files from ./files directory
    http.Handle("/", fileServer)            // Handle requests to root path with fileServer handler
    http.HandleFunc("/form", formHandler)   // Handle requests to /form endpoint with formHandler function
    http.HandleFunc("/hello", helloHandler) // Handle requests to /hello endpoint with helloHandler function

    fmt.Printf("Starting server at port 8080\n")

    if err := http.ListenAndServe(":8080", nil); err != nil {
        log.Fatal(err) // Log any errors that occur during server startup and exit with error status
    }
}

Executing the program

    Save the files you have created.

    On the terminal type the following command:

go run main.go

    When you see "Starting server at port 8080" displayed on the terminal, head over to your browser and search "localhost:8080".

    Open new tab on your browser and search "localhost:8080/form.html".

    A form as the one shown below will be displayed.

    Upon submitting the form after filling in the name and address field, the following message is displayed.

    This shows that our web server is working as expected.

Resources

    Find the code in my GitHub repository. Here is the link

    https://github.com/JosephOkumu/WebServer