Skip to main content

Simple Go HTTP Server Template

When working on various Go projects for clients, one recurring need is setting up a basic HTTP server. Whether it’s for health checks, APIs, or serving simple content, having a lightweight server template is essential.

In this post, I’ll share a simple template I use to quickly spin up an HTTP server. This template can be extended to suit any project, and I’ll walk you through the key components.

The Main Package

In the main.go file, we initialize and start the server. I’ve also integrated graceful shutdown capabilities using the bsm/shutdown package to ensure that the server stops cleanly when interrupted.

package main

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

	"../simple-server/internal/server"
	"github.com/bsm/shutdown"
)

func main() {
	// Start the server
	fmt.Println("Starting server...")
	srv, err := server.New()
	if err != nil {
		log.Fatalln("failed to start server:", err)
	}
	defer func() {
		err := srv.Stop()
		if err != nil {
			log.Fatalln("failed to stop server:", err)
		}
	}()

	fmt.Println("Running...")
	if err := shutdown.Wait(srv.Start); err != nil && err != http.ErrServerClosed {
		log.Fatalln(err)
	}

	if err := srv.Stop(); err != nil {
		log.Fatalln(err)
	}

}


Key Features:
  • Graceful Shutdown: The server is set up to handle shutdown signals and cleanly close resources like database connections or background jobs.
  • Extensibility: This template can be extended with additional routes and middleware as needed.Server Package

The Server Package

The server package contains the core logic of the server, including HTTP handlers and the server's lifecycle (starting and stopping).

Server Struct
The Server struct wraps the http.Server from the Go standard library. It provides methods to start and stop the server, ensuring a smooth shutdown with a timeout of 5 seconds.

package server

import (
	"context"
	"net/http"
	"time"
)

// Server is the main server struct
type Server struct {
	srv *http.Server
}

// New returns a new server
func New() (*Server, error) {
	return &Server{
		srv: &http.Server{
			Addr:    ":8080",
			Handler: NewHandler(),
		},
	}, nil
}

// Start starts the server
func (s *Server) Start() error {
	return s.srv.ListenAndServe()
}

// Stop stops the server with a 5-second timeout
func (s *Server) Stop() error {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	return s.srv.Shutdown(ctx)
}
The Handler Functions 

Handlers in Go are responsible for processing incoming HTTP requests and sending responses. In this template, I’ve defined two simple routes:
  1. Root (/) – Returns a “Hello, world!” message.
  2. Ping (/ping) – Responds with “pong”, useful for health checks.

// Handler implements the http.Handler interface
type handler struct {
	*http.ServeMux
}

// NewHandler returns a new handler with routes
func NewHandler() http.Handler {
	h := &handler{
		ServeMux: http.NewServeMux(),
	}

	// Register the handler functions
	h.HandleFunc("/", h.handleRoot)
	h.HandleFunc("/ping", h.handlePing)

	return h
}

// handleRoot handles the root route
func (h *handler) handleRoot(w http.ResponseWriter, r *http.Request) {
	_, _ = w.Write([]byte("Hello, world!"))
}

// handlePing handles the /ping route
func (h *handler) handlePing(w http.ResponseWriter, r *http.Request) {
	_, _ = w.Write([]byte("pong"))
}

Conclusion

This simple Go HTTP server template can serve as the foundation for more complex applications. It provides a basic structure with routing and graceful shutdown support, and it’s easy to extend with additional routes, middleware, or database connections.

Comments

Popular posts from this blog

Working with Rails Importmap and Sprockets

When starting a new Rails project, you may find yourself juggling different asset management tools. In my recent project, Rails came pre-configured with both: gem "sprockets-rails" gem "importmap-rails" I was keen to use `importmap-rails`, as it offers a modern, gem-free way to manage JavaScript dependencies. However, I was already familiar with `sprockets-rails` from previous projects, which made the mixed setup feel a bit confusing. Since my project uses Bootstrap 5 alongside Turbo and Stimulus, it took some trial and error to get everything working smoothly—especially in production. The Challenge: Importmap in Production According to the Importmap documentation , JavaScript files should be served directly from the `/app/javascript` folder. This works perfectly in development. However, in production, I noticed that the JavaScript files were not being correctly referenced, leading to missing assets and broken functionality. The solution? Precompiling the...

Using Ruby on Rails and AWS SQS for Website Crawling

Recently, I returned to Ruby on Rails , one of my favourite web application frameworks. This time, I aimed to build a simple management tool for scheduling website crawls—a key component of a side project I'm working on. The tool's purpose is straightforward: Maintain a list of websites to crawl. Schedule crawls for these websites. Trigger a Golang process for the actual crawling task. To facilitate communication between the Rails app and the Golang service, I chose AWS SQS (Simple Queue Service). SQS provides a reliable way to send, receive, and manage messages between distributed systems. Adding an SQS Service in Rails In Rails, services are often used to encapsulate business logic that doesn’t belong in the standard MVC structure. For my application, I created a services/sqs_send_service.rb to handle sending messages to SQS queues. Here’s the implementation:   require "aws-sdk-sqs" class SqsSendService # Client is a class method that ...