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 versionto check) - A terminal/command prompt
- A text editor (VS Code, Vim, etc.)
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.
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.
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
}
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
}
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.
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))
}
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.
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
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
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)