Building a Simple Web Server. Duration: 9.59 mins

Understanding net/http package

Click Play Button to Start

The net/http Package in Go

  • Core Go library for building HTTP servers and clients
  • Functions handle HTTP requests and responses
  • Manages cookies, builds web servers, and handles routing

Starting an HTTP Server

  • Use http.ListenAndServe to start an HTTP server on a specific address and port
  • Requires a handler to respond to HTTP requests
  • http.Handler interface has one method: ServeHTTP
flowchart TD Start["Start HTTP Server"] -->|Specify address and port| B(Define Address & Port) B --> C{Require Handler} C -->|Yes| D[Define Handler] C -->|No| E[Error] D --> F{Implement ServeHTTP} F -->|Yes| G[Respond to HTTP requests] E --> Stop["Stop"] G --> Stop

Simple HTTP Server Example


package main

import (
	"fmt"
	"net/http"
)

// helloHandler responds to an HTTP request with "Hello, World!"
func helloHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprint(w, "Hello, World!")
}

func main() {
	// Convert the helloHandler function to a type that implements http.Handler
	http.HandleFunc("/", helloHandler)

	// Start the server and listen on port 8080
	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal(err)
	}
}
  • http.HandleFunc takes URL path and function with func(http.ResponseWriter, *http.Request) signature
  • Handler function is called when a request is received
  • Uses http.ResponseWriter to write response to the client

Understanding Request and Response

  • http.ResponseWriter is an interface for assembling HTTP response
  • *http.Request type represents client's request
  • Holds URL, query parameters, body, headers, etc.

Comparison with Flask in Python

  • Similar to Flask's route decorators
  • http.HandleFunc associates URL pattern with function
  • Unlike Flask, net/http is part of Go standard library
  • No additional frameworks needed

Moving to Advanced Topics

  • Understand the net/http package first
  • Implement more functions of the package
  • Organize your code following the MVC design pattern
journey title Advancing with net/http package section Learn net/http package Research: 5: Developer Read documentation: 3: Developer section Implement more functions Choose new functions: 2: Developer Write code: 4: Developer section Code organization Study MVC pattern: 3: Developer Refactor code using MVC: 5: Developer

Handling Requests and Responses

Click Play Button to Start

Example: Creating a Simple HTTP Server in Go

  • Imports net/http package for HTTP implementations
  • Defines a handler function
  • Handles incoming HTTP requests
  • Sends appropriate responses
  • Attaches handler function to root path ("/")
  • Starts server with http.ListenAndServe
flowchart TD A((Imports net/http package for HTTP implementations)) B((Defines a handler function)) C((Handles incoming HTTP requests)) D((Sends appropriate responses)) E((Attaches handler function to root path ("/"))) F((Starts server with http.ListenAndServe)) A --> B B --> C C --> D D --> E E --> F

Importing net/http Package


import ( 
  "net/http"
)

Defining the Handler Function

The handler function receives two parameters:

  1. w : http.ResponseWriter - to send responses
  2. r : *http.Request - holds incoming request details

func handler(w http.ResponseWriter, r *http.Request) {
  if r.Method == "GET" {
    w.WriteHeader(http.StatusOK)
    w.Write([]byte("Hello, this is a GET request!"))
  } else {
    w.WriteHeader(http.StatusMethodNotAllowed)
    w.Write([]byte("Method Not Allowed"))
  }
}

Attaching the Handler Function


http.HandleFunc("/", handler)

Starting the HTTP Server


http.ListenAndServe(":8080", nil)

Pre-requisite Knowledge

  • Understanding the net/http package in Go
  • Basics of handling HTTP requests and responses

Key Considerations

  • Recognize HTTP methods
  • Appropriately set status codes
  • Handle different HTTP methods
  • Set correct response headers and body contents
flowchart TB Recognize["Recognize HTTP methods"] -->|Yes| Status["Appropriately set status codes"] Status -->|Yes| Handle["Handle different HTTP methods"] Handle --> Set["Set correct response headers and body contents"]

Implementing MVC design pattern

Click Play Button to Start

In Go, the Model-View-Controller (MVC) Design Pattern

The Model-View-Controller (MVC) design pattern is a way to organize code and separate concerns in web applications. It divides an application into three interconnected components, helping developers to manage complexity and scalability.

flowchart TB A(Model) --- B(View) A --- C(Controller) B --- C

Model

  • The Model represents the data and the business logic of the application.
  • Manages the state and queries the database.
  • Handles data manipulation operations.
flowchart TD A[Model] A -->|Manages the state and queries the database| B[Data Management] B --> C[Query Database] A -->|Handles data manipulation operations| D[Data Manipulation]

View

  • The View is the user interface of the application.
  • Presents data to the user.
  • Generates output representations like HTML pages.

Controller

  • The Controller ties the Model and the View together.
  • Receives requests from the client.
  • Instructs the Model to perform operations.
  • Sends the output to the View.

Let's look at an example of implementing the MVC pattern in Go for a simple blog application:

Model (BlogPost.go)

Represents a blog post.

package models

// BlogPost models a blog post for the application
type BlogPost struct {
    ID      int
    Title   string
    Content string
}

// FetchAllPosts would fetch all blog posts from the database
func FetchAllPosts() ([]BlogPost, error) {
    // logic to retrieve all posts from the database
}

// FetchPostByID would fetch a single post given its ID
func FetchPostByID(id int) (BlogPost, error) {
    // logic to retrieve a post by ID from the database
}

View (Templates in HTML)

Presents the data in HTML format.


{{range .}}

{{.Title}}

{{.Content}}

{{else}}
No posts to show.
{{end}}

{{.Title}}

{{.Content}}

Controller (BlogController.go)

Processes requests, interacts with the Model, and selects the View.

package controllers

import (
    "net/http"
    "html/template"
    "path/filepath"
    "myapp/models"
)

func ListBlogPosts(w http.ResponseWriter, r *http.Request) {
    posts, err := models.FetchAllPosts()
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    tmpl := template.Must(template.ParseFiles(filepath.Join("view", "blog", "index.html")))
    tmpl.Execute(w, posts)
}

func GetBlogPost(w http.ResponseWriter, r *http.Request) {
    // here we'd parse the ID from the request, e.g., using a router

    post, err := models.FetchPostByID(someID)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    tmpl := template.Must(template.ParseFiles(filepath.Join("view", "blog", "show.html")))
    tmpl.Execute(w, post)
}

Routing (main.go)

Sets up the server and routes the requests to appropriate controllers.

package main

import (
    "net/http"
    "myapp/controllers"
)

func main() {
    http.HandleFunc("/", controllers.ListBlogPosts)
    http.HandleFunc("/post/", controllers.GetBlogPost)
    
    http.ListenAndServe(":8080", nil)
}

In this scenario, for every request, the Controller decides which Model method should be

Quiz

Click Play Button to Start

Question 1/2

Which of the following statements regarding the http.ListenAndServe function in Go is true?

Question 2/2

In the Model-View-Controller (MVC) pattern implemented in Go, what is the primary responsibility of the Controller?