REST API with Go: Practical Examples

Explore practical examples of building a REST API with Go, focusing on clear implementations for various use cases.
Written by
Jamie

Examples of Building a REST API with Go

Building a REST API with Go can be a straightforward task, thanks to its robust standard library and third-party packages. Below are three practical examples demonstrating how to create a basic REST API using Go. Each example addresses different use cases and provides code snippets to help you understand the implementation.

Example 1: Simple Todo List API

Context

This example demonstrates how to create a simple REST API for managing a todo list. The API allows users to create, read, update, and delete todo items.

package main

import (
    "encoding/json"
    "net/http"
    "sync"
)

type Todo struct {
    ID    int    `json:"id"`
    Title string `json:"title"`
    Done  bool   `json:"done"`
}

var (
    todos  = make(map[int]Todo)
    nextID = 1
    mu     sync.Mutex
)

func getTodos(w http.ResponseWriter, r *http.Request) {
    mu.Lock()
    defer mu.Unlock()

    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(todos)
}

func createTodo(w http.ResponseWriter, r *http.Request) {
    var todo Todo
    if err := json.NewDecoder(r.Body).Decode(&todo); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    mu.Lock()
    todo.ID = nextID
    nextID++
    todos[todo.ID] = todo
    mu.Unlock()

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

func main() {
    http.HandleFunc("/todos", getTodos)
    http.HandleFunc("/todos/create", createTodo)
    http.ListenAndServe(":8080", nil)
}

Notes

  • You can extend this API by adding update and delete functionalities.
  • For persistence, consider integrating a database.

Example 2: Book Management API with CRUD Operations

Context

This example illustrates how to implement a REST API for managing books in a library. The API supports create, read, update, and delete operations.

package main

import (
    "encoding/json"
    "net/http"
    "sync"
)

type Book struct {
    ID     int    `json:"id"`
    Title  string `json:"title"`
    Author string `json:"author"`
}

var (
    books  = make(map[int]Book)
    nextID = 1
    mu     sync.Mutex
)

func getBooks(w http.ResponseWriter, r *http.Request) {
    mu.Lock()
    defer mu.Unlock()

    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(books)
}

func createBook(w http.ResponseWriter, r *http.Request) {
    var book Book
    if err := json.NewDecoder(r.Body).Decode(&book); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    mu.Lock()
    book.ID = nextID
    nextID++
    books[book.ID] = book
    mu.Unlock()

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

func updateBook(w http.ResponseWriter, r *http.Request) {
    // Implement update logic here
}

func deleteBook(w http.ResponseWriter, r *http.Request) {
    // Implement delete logic here
}

func main() {
    http.HandleFunc("/books", getBooks)
    http.HandleFunc("/books/create", createBook)
    // Add handlers for update and delete
    http.ListenAndServe(":8080", nil)
}

Notes

  • Consider using route parameters for the update and delete functions.
  • Implementing a database connection will enhance data persistence.

Example 3: User Authentication API

Context

In this example, we will create a simple user authentication API. Users can register and log in, receiving a token for subsequent requests.

package main

import (
    "encoding/json"
    "net/http"
    "sync"
)

type User struct {
    Username string `json:"username"`
    Password string `json:"password"`
}

var (
    users = make(map[string]string)
    mu    sync.Mutex
)

func registerUser(w http.ResponseWriter, r *http.Request) {
    var user User
    if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    mu.Lock()
    users[user.Username] = user.Password
    mu.Unlock()

    w.WriteHeader(http.StatusCreated)
}

func loginUser(w http.ResponseWriter, r *http.Request) {
    var user User
    if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    mu.Lock()
    password, exists := users[user.Username]
    mu.Unlock()

    if !exists || password != user.Password {
        http.Error(w, "Unauthorized", http.StatusUnauthorized)
        return
    }

    w.WriteHeader(http.StatusOK)
    json.NewEncoder(w).Encode("Login successful")
}

func main() {
    http.HandleFunc("/register", registerUser)
    http.HandleFunc("/login", loginUser)
    http.ListenAndServe(":8080", nil)
}

Notes

  • For real-world applications, consider using hashed passwords and tokens for user sessions.
  • Implement JWT for a more secure authentication mechanism.

These examples provide a foundation for building various REST APIs using Go. You can expand upon these by integrating databases, adding more sophisticated error handling, and enhancing security measures.

Explore More Go Code Snippets

Discover more examples and insights in this category.

View All Go Code Snippets