Create Your First Go Project

Step-by-step guide to building a dummy project with proper structure

This tutorial walks you through creating a complete Go project from scratch. We'll build a simple "User Management API" following the standard Go project structure. You'll learn how to organize code, create handlers, models, and set up a basic HTTP server.

Prerequisites

  • Go 1.18 or higher installed (go version to check)
  • A terminal/command prompt
  • A text editor (VS Code, Vim, etc.)
1

Initialize the Go Module

First, create a new directory and initialize a Go module. This creates the go.mod file that tracks dependencies.

# Create project directory
mkdir user-api
cd user-api

# Initialize Go module
go mod init github.com/yourusername/user-api

Note: Replace yourusername with your GitHub username or organization name.

2

Create Directory Structure

Create the standard directory structure for your project:

# Create directory structure
mkdir -p cmd/server
mkdir -p internal/handlers
mkdir -p internal/models
mkdir -p internal/config
mkdir -p pkg/utils
mkdir -p configs
mkdir -p docs

This creates all the necessary directories following Go best practices. The internal/ folder contains private application code, while pkg/ is for reusable library code.

3

Create Configuration File

Create a simple configuration file:

# Create config file
cat > configs/config.env << 'EOF'
PORT=8080
HOST=localhost
DEBUG=true
EOF

Create the config loader in internal/config/config.go:

package config

import (
    "os"
)

type Config struct {
    Port  string
    Host  string
    Debug string
}

func Load() *Config {
    return &Config{
        Port:  getEnv("PORT", "8080"),
        Host:  getEnv("HOST", "localhost"),
        Debug: getEnv("DEBUG", "false"),
    }
}

func getEnv(key, defaultValue string) string {
    if value := os.Getenv(key); value != "" {
        return value
    }
    return defaultValue
}
4

Create the User Model

Create the User model in internal/models/user.go:

package models

type User struct {
    ID    int    `json:"id"`
    Name  string `json:"name"`
    Email string `json:"email"`
}

// Dummy in-memory storage (for demo purposes)
var users []User
var nextID = 1

func GetAllUsers() []User {
    return users
}

func GetUserByID(id int) *User {
    for i := range users {
        if users[i].ID == id {
            return &users[i]
        }
    }
    return nil
}

func CreateUser(name, email string) *User {
    user := User{
        ID:    nextID,
        Name:  name,
        Email: email,
    }
    nextID++
    users = append(users, user)
    return &user
}

func DeleteUser(id int) bool {
    for i := range users {
        if users[i].ID == id {
            users = append(users[:i], users[i+1:]...)
            return true
        }
    }
    return false
}
5

Create HTTP Handlers

Create HTTP handlers in internal/handlers/user.go:

package handlers

import (
    "encoding/json"
    "net/http"
    "strconv"

    "github.com/gorilla/mux"
    "github.com/yourusername/user-api/internal/models"
)

func GetUsers(w http.ResponseWriter, r *http.Request) {
    users := models.GetAllUsers()
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(users)
}

func GetUser(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    id, _ := strconv.Atoi(vars["id"])
    
    user := models.GetUserByID(id)
    if user == nil {
        http.Error(w, "User not found", http.StatusNotFound)
        return
    }
    
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(user)
}

func CreateUser(w http.ResponseWriter, r *http.Request) {
    var newUser struct {
        Name  string `json:"name"`
        Email string `json:"email"`
    }
    
    if err := json.NewDecoder(r.Body).Decode(&newUser); err != nil {
        http.Error(w, "Invalid request body", http.StatusBadRequest)
        return
    }
    
    user := models.CreateUser(newUser.Name, newUser.Email)
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(user)
}

func DeleteUser(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    id, _ := strconv.Atoi(vars["id"])
    
    if !models.DeleteUser(id) {
        http.Error(w, "User not found", http.StatusNotFound)
        return
    }
    
    w.WriteHeader(http.StatusNoContent)
}

Note: We'll install the Gorilla Mux router in the next step for routing.

6

Create Main Application

Create the main entry point in cmd/server/main.go:

package main

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

    "github.com/gorilla/mux"
    "github.com/yourusername/user-api/internal/config"
    "github.com/yourusername/user-api/internal/handlers"
)

func main() {
    cfg := config.Load()
    
    r := mux.NewRouter()
    
    // Routes
    r.HandleFunc("/users", handlers.GetUsers).Methods("GET")
    r.HandleFunc("/users/{id}", handlers.GetUser).Methods("GET")
    r.HandleFunc("/users", handlers.CreateUser).Methods("POST")
    r.HandleFunc("/users/{id}", handlers.DeleteUser).Methods("DELETE")
    
    // Health check
    r.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusOK)
        fmt.Fprintf(w, "OK")
    }).Methods("GET")
    
    addr := fmt.Sprintf("%s:%s", cfg.Host, cfg.Port)
    log.Printf("Server starting on http://%s", addr)
    log.Fatal(http.ListenAndServe(addr, r))
}
7

Install Dependencies

Install the Gorilla Mux router package:

go get github.com/gorilla/mux
go mod tidy

go mod tidy cleans up and updates the go.mod and go.sum files.

8

Create README and .gitignore

Create README.md:

# User API

A simple REST API for user management built with Go.

## Features

- Create users
- Get all users
- Get user by ID
- Delete user

## Run

```bash
go run cmd/server/main.go
```

## Endpoints

- `GET /health` - Health check
- `GET /users` - Get all users
- `GET /users/{id}` - Get user by ID
- `POST /users` - Create user
- `DELETE /users/{id}` - Delete user

Create .gitignore:

# Binaries
*.exe
*.exe~
*.dll
*.so
*.dylib
user-api

# Test binary
*.test

# Go workspace file
go.work

# IDE
.vscode/
.idea/
*.swp
*.swo

# OS
.DS_Store
Thumbs.db
9

Run Your Project

Start the server:

go run cmd/server/main.go

The server should start on http://localhost:8080. Test it with curl:

# Health check
curl http://localhost:8080/health

# Create a user
curl -X POST http://localhost:8080/users \
  -H "Content-Type: application/json" \
  -d '{"name":"John Doe","email":"john@example.com"}'

# Get all users
curl http://localhost:8080/users

# Get user by ID
curl http://localhost:8080/users/1

# Delete user
curl -X DELETE http://localhost:8080/users/1

Final Project Structure

user-api/
├── go.mod
├── go.sum
├── README.md
├── .gitignore
├── cmd/
│ └── server/main.go
├── internal/
│ ├── handlers/user.go
│ ├── models/user.go
│ └── config/config.go
├── pkg/
│ └── utils/
├── configs/
│ └── config.env
└── docs/

Next Steps

  • Add database integration (PostgreSQL, MySQL, or SQLite)
  • Add middleware for logging, authentication, and CORS
  • Write unit tests using Go's testing package
  • Add input validation and error handling
  • Deploy to cloud platforms (AWS, GCP, or Heroku)