Go Lesson 43 – REST API Handlers | Dataplexa

REST API Handlers in Go

REST APIs are the backbone of modern backend systems. Go is widely used to build fast, reliable, and scalable REST APIs using its standard net/http package.

In this lesson, you will learn how to design, structure, and implement real REST API handlers using Go — the same way production systems do.


What Is a REST API?

REST (Representational State Transfer) is an architectural style that uses HTTP methods to perform operations on resources.

  • GET – Read data
  • POST – Create data
  • PUT – Update data
  • DELETE – Remove data

Each resource is identified by a URL.


Real-World Example: User Service

Imagine a backend service that manages users for an application. Each user has:

  • ID
  • Name
  • Email

We will build REST handlers for this scenario.


Defining a Data Model

Start by defining a Go struct to represent a user.

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

In-Memory Data Store

For learning purposes, we will store users in memory.

var users = []User{
    {ID: 1, Name: "Alice", Email: "alice@example.com"},
    {ID: 2, Name: "Bob", Email: "bob@example.com"},
}

In real systems, this would be replaced by a database.


GET Handler – Fetch All Users

This endpoint returns all users as JSON.

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

POST Handler – Create a New User

This endpoint reads JSON from the request body and adds a new user.

func createUser(w http.ResponseWriter, r *http.Request) {
    var newUser User

    err := json.NewDecoder(r.Body).Decode(&newUser)
    if err != nil {
        http.Error(w, "Invalid input", http.StatusBadRequest)
        return
    }

    newUser.ID = len(users) + 1
    users = append(users, newUser)

    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(newUser)
}

Routing REST Endpoints

Use http.HandleFunc to map endpoints.

http.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {
    if r.Method == http.MethodGet {
        getUsers(w, r)
    } else if r.Method == http.MethodPost {
        createUser(w, r)
    } else {
        http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
    }
})

Handling Status Codes Properly

Status codes communicate the result of a request.

  • 200 – OK
  • 201 – Created
  • 400 – Bad Request
  • 404 – Not Found
  • 500 – Server Error

Correct status codes improve API reliability and client integration.


GET User by ID

You can extract query parameters to fetch a specific user.

func getUserByID(w http.ResponseWriter, r *http.Request) {
    idStr := r.URL.Query().Get("id")
    id, _ := strconv.Atoi(idStr)

    for _, user := range users {
        if user.ID == id {
            json.NewEncoder(w).Encode(user)
            return
        }
    }

    http.Error(w, "User not found", http.StatusNotFound)
}

Validating Input Data

Always validate incoming data to prevent invalid or unsafe requests.

For example, ensure that email and name fields are not empty before processing.


Separating Logic for Clean Code

In production systems:

  • Handlers manage HTTP logic
  • Services handle business logic
  • Repositories manage database access

This separation makes APIs easier to maintain and scale.


Testing REST Handlers

Go provides excellent tools to test HTTP handlers.

Well-tested APIs reduce bugs and downtime in production.


Real-World Use Cases

  • User management systems
  • E-commerce backends
  • Mobile and web app APIs
  • Microservice communication

Practice Exercises

Exercise 1

Add a DELETE endpoint to remove a user by ID.

Exercise 2

Add input validation to reject empty names or invalid emails.


Key Takeaways

  • REST APIs rely on HTTP methods
  • Handlers map requests to logic
  • JSON is the standard data format
  • Clean structure improves scalability

What’s Next?

In the next lesson, you will work with Go modules in real projects and learn how APIs scale across multiple services.