{
  "slug": "Simple-Golang-HTTP-server-fe7a88ef221e",
  "title": "Simple Golang HTTP server",
  "subtitle": "In this article, I guide you through the process of building a simple HTTP server in Golang using a structured three-layer architecture…",
  "excerpt": "In this article, I guide you through the process of building a simple HTTP server in Golang using a structured three-layer architecture…",
  "date": "2025-08-09",
  "tags": [
    "Go",
    "Architecture"
  ],
  "readingTime": "5 min",
  "url": "https://medium.com/@mobinshaterian/simple-golang-http-server-fe7a88ef221e",
  "hero": "https://cdn-images-1.medium.com/max/800/1*RloMC_42dRvXvlR9nViw-A.jpeg",
  "content": [
    {
      "type": "heading",
      "level": 2,
      "text": "Simple Golang HTTP server"
    },
    {
      "type": "paragraph",
      "html": "In this article, I guide you through the process of building a simple HTTP server in Golang using a structured three-layer architecture: router, controllers, and database. My goal was to create a clean and maintainable project while applying key design patterns in Go. I started by initializing a Go module and setting up a GitHub repository to share my code. Then, I implemented a basic server using Go’s <code>net/http</code> package, added graceful shutdown handling, and wrote unit tests to verify the server’s behavior. To make the project more robust, I later integrated the Gin framework for better routing and middleware support. Whether you're just starting with Go or looking to refine your architecture, I hope this guide helps you build with confidence."
    },
    {
      "type": "image",
      "src": "https://cdn-images-1.medium.com/max/800/1*RloMC_42dRvXvlR9nViw-A.jpeg",
      "alt": "Simple Golang HTTP server",
      "caption": "",
      "width": 1024,
      "height": 1024
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Build a Go Project"
    },
    {
      "type": "paragraph",
      "html": "By simply running the command, you can create a Go module file and start a project."
    },
    {
      "type": "code",
      "lang": "bash",
      "code": "go mod init go-simple"
    },
    {
      "type": "paragraph",
      "html": "The <code>go.mod</code> file will look as follows:"
    },
    {
      "type": "code",
      "lang": "text",
      "code": "module go-simplego 1.23.2"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Making a Git repository"
    },
    {
      "type": "paragraph",
      "html": "Since I want to share my code with others, I can use a Git repository. To do this, I should create a repository on GitHub and commit the initial version of the project."
    },
    {
      "type": "code",
      "lang": "text",
      "code": "echo \"# go-simple\" >> README.mdgit initgit add README.mdgit commit -m \"first commit\"git branch -M\nmaingit remote add origin git@github.com:mobintmu/go-simple.gitgit push -u origin main"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Repository GitHub Address"
    },
    {
      "type": "paragraph",
      "html": "This repository will contain and share all of my code."
    },
    {
      "type": "code",
      "lang": "text",
      "code": "https://github.com/mobintmu/go-simple"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Build a Golang HTTP server"
    },
    {
      "type": "paragraph",
      "html": "In this first step, I created a folder structure with a main.go file located in cmd/web. This file initializes a new instance of the application and starts the HTTP server. Since the server runs in a separate goroutine, I implemented a channel to receive a signal when the program should terminate, ensuring proper synchronization and graceful shutdown."
    },
    {
      "type": "code",
      "lang": "go",
      "code": "package main\nimport (\napplication \"go-simple/cmd/web/app\"\n\"os\"\n\"os/signal\"\n\"syscall\"\n)\nfunc main() {\n    app := application.New() app.StartServer() // Wait for interrupt signal to gracefully shut down\n    sig := make(chan os.Signal, 1) signal.Notify(sig, os.Interrupt, syscall.SIGTERM) <-sig // Blocks\n    until signal is received\n}"
    },
    {
      "type": "paragraph",
      "html": "The application file sets up a basic HTTP server that handles incoming requests on port 4000 via the HTTP protocol."
    },
    {
      "type": "paragraph",
      "html": "This Go code defines a simple web application using the standard <code>net/http</code> package. It starts by creating an <code>Application</code> struct that holds the server port, and a <code>New()</code> function that initializes the app by checking the <code>PORT</code> environment variable (using a default of&nbsp;<code>:4000</code> if not set). The port is formatted to include a colon if missing, ensuring it's valid for the server to use."
    },
    {
      "type": "paragraph",
      "html": "The <code>StartServer</code> method sets up a basic HTTP router (<code>ServeMux</code>) that routes incoming requests to the appropriate handler—in this case, only the root path <code>/</code> is handled by <code>helloHandler</code>. It starts the server in a separate goroutine so it runs in the background, logging the startup message and any errors. The <code>helloHandler</code> function responds with \"Hello World\" in plain text for GET requests, and returns a 405 error for any other HTTP method."
    },
    {
      "type": "code",
      "lang": "go",
      "code": "package application\nimport (\n\"fmt\"\n\"log\"\n\"net/http\"\n\"os\"\n)\ntype Application struct {\n    Port string\n}\nconst defaultPort = \":4000\"func New() *Application {\n    port := os.Getenv(\"PORT\") if port == \"\" {\n        port = defaultPort\n    }\n    else if port[0] != ':' {\n        port = \":\" + port\n    }\n    return &Application{\n        Port: port\n    }\n}\nfunc (app *Application) StartServer() {\n    // router mux := http.NewServeMux() mux.HandleFunc(\"/\", helloHandler) //start the server go\n    func() {\n        log.Printf(\"Starting server at port %s\", app.Port) err := http.ListenAndServe(app.Port, mux)\n        if err != nil {\n            log.Fatal(err)\n        }\n    }\n    ()\n}\nfunc helloHandler(w http.ResponseWriter, r *http.Request) {\n    if r.Method != http.MethodGet {\n        http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)\n        return\n    }\n    w.Header().Set(\"Content-Type\", \"text/plain; charset=utf-8\") fmt.Fprint(w, \"Hello World\")\n}"
    },
    {
      "type": "paragraph",
      "html": "To test the function, it is necessary to create a test file within the test folder. First, a simple server is set up, and then an HTTP request is sent to the endpoint to verify its behavior."
    },
    {
      "type": "code",
      "lang": "go",
      "code": "package test\nimport (\n\"io\"\n\"net/http\"\n\"testing\"\n\"time\" application \"go-simple/cmd/web/app\"\n)\nfunc startTestServer() {\n    a := application.New() a.StartServer() time.Sleep(200 * time.Millisecond) // Give server time to\n    start\n}\nfunc TestHelloWorldEndpoint(t *testing.T) {\n    startTestServer() resp, err := http.Get(\"http://localhost:4000/\") if err != nil {\n        t.Fatalf(\"Failed to send GET request: %v\", err)\n    }\n    defer resp.Body.Close() if resp.StatusCode != http.StatusOK {\n        t.Errorf(\"Expected status 200 OK, got %d\", resp.StatusCode)\n    }\n    body, err := io.ReadAll(resp.Body) if err != nil {\n        t.Fatalf(\"Failed to read response body: %v\", err)\n    }\n    expected := \"Hello World\" if string(body) != expected {\n        t.Errorf(\"Expected body '%s', got '%s'\", expected, string(body))\n    }\n}"
    },
    {
      "type": "image",
      "src": "https://cdn-images-1.medium.com/max/800/1*19PJYYquNdR5n61nJQGDqQ.png",
      "alt": "Simple Golang HTTP server",
      "caption": "",
      "width": 294,
      "height": 82
    },
    {
      "type": "paragraph",
      "html": "Run Golang project:"
    },
    {
      "type": "code",
      "lang": "bash",
      "code": "go run cmd/web/main.go"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "GitHub code for this part"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Gin Router"
    },
    {
      "type": "paragraph",
      "html": "In the next step, I will integrate the Gin router to handle routing in my Go project."
    },
    {
      "type": "embed",
      "provider": "youtube",
      "url": "https://www.youtube.com/embed/NcqNeguQlho"
    },
    {
      "type": "paragraph",
      "html": "Run this in your terminal:"
    },
    {
      "type": "code",
      "lang": "bash",
      "code": "go get -u github.com/gin-gonic/gin"
    },
    {
      "type": "paragraph",
      "html": "Add a gin router in the app.go file"
    },
    {
      "type": "code",
      "lang": "go",
      "code": "package application\nimport (\n\"log\"\n\"net/http\"\n\"os\"\n\"github.com/gin-gonic/gin\"\n)\ntype Application struct {\n    Port string\n    Router *gin.Engine\n}\nconst defaultPort = \":4000\"func New() *Application {\n    // Set release mode gin.SetMode(gin.DebugMode) // Use New() for full control, or Default() if\n    you're okay with built-ins router := gin.New() // Add middleware explicitly router.Use(gin.Logger()) router.Use(gin.Recovery()) port := os.Getenv(\"PORT\") if port == \"\" {  port = defaultPort } return &Application{Port: port, Router: router}}\n\nfunc (app *Application) StartServer() { //start the server go\nfunc() {  log.Printf(\"Starting Gin server at port %s\", app.Port)  err := app.Router.Run(app.Port)\nif err != nil {   log.Fatal(err)  } }()}\n\nfunc (a *Application) Routes() { a.Router.GET(\"/\", helloHandler)}\n\nfunc helloHandler(c *gin.Context) { c.JSON(http.StatusOK, gin.H{  \"message\": \"hello world\", })}"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Current commit on GitHub"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "🧩 Conclusion :"
    },
    {
      "type": "paragraph",
      "html": "Building this simple Golang HTTP server was a great exercise in applying clean architecture and exploring both the standard <code>net/http</code> package and the more powerful Gin framework. Starting from scratch—setting up the module, structuring the project, writing tests, and finally integrating Gin—helped me understand how to scale a Go application while keeping it modular and maintainable. Sharing the code on GitHub not only makes it easier for others to learn from or contribute to the project, but also keeps me accountable for writing clean, well-documented code. I’m excited to keep expanding this project, and I hope it serves as a helpful starting point for anyone diving into web development with Go."
    }
  ]
}
