How to Write a REST API in Go in 30 Minutes: A Practical Guide

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: Why Go for REST API?

\n

Go (Golang) is a modern compiled language with built-in concurrency support and high performance. A REST API in Go runs fast, consumes little memory, and scales easily. In 30 minutes, you will create a full-fledged REST service with GET, POST, PUT, and DELETE requests, using only the standard library.

\n

In this guide, we will write an API for managing a task list (Todo app). You will learn how to set up routing, handle JSON, add middleware for logging, and correctly return errors. No third-party frameworks — just pure Go!

\n\n

1. Project Setup and Structure

\n

Create a new directory for the project and initialize the Go module:

\n
mkdir go-todo-api\ncd go-todo-api\ngo mod init todo-api
\n

The project structure will be simple:

\n
    \n
  • main.go — entry point and server startup
  • \n
  • handlers.go — request handlers
  • \n
  • models.go — data structures
  • \n
  • middleware.go — middleware
  • \n
\n

Create the models.go file with the task structure:

\n
package main\n\ntype Task struct {\n    ID        int    `json:"id"`\n    Title     string `json:"title"`\n    Completed bool   `json:"completed"`\n}
\n

We will store tasks in memory (a tasks slice) for simplicity. In a real project, use a database.

\n\n

2. Routing and Handlers

\n

Go uses the built-in net/http package. Let's create the handlers.go file with the main handlers.

\n

2.1. GET /tasks — Get all tasks

\n
package main\n\nimport (\n    "encoding/json"\n    "net/http"\n    "strconv"\n)\n\nvar tasks = []Task{}\nvar nextID = 1\n\nfunc getTasks(w http.ResponseWriter, r *http.Request) {\n    w.Header().Set("Content-Type", "application/json")\n    json.NewEncoder(w).Encode(tasks)\n}
\n

2.2. POST /tasks — Create a new task

\n
func createTask(w http.ResponseWriter, r *http.Request) {\n    var newTask Task\n    if err := json.NewDecoder(r.Body).Decode(&newTask); err != nil {\n        http.Error(w, "Invalid JSON", http.StatusBadRequest)\n        return\n    }\n    newTask.ID = nextID\n    nextID++\n    tasks = append(tasks, newTask)\n    w.Header().Set("Content-Type", "application/json")\n    w.WriteHeader(http.StatusCreated)\n    json.NewEncoder(w).Encode(newTask)\n}
\n

2.3. PUT /tasks/{id} — Update a task

\n
func updateTask(w http.ResponseWriter, r *http.Request) {\n    idStr := r.PathValue("id")\n    id, err := strconv.Atoi(idStr)\n    if err != nil {\n        http.Error(w, "Invalid task ID", http.StatusBadRequest)\n        return\n    }\n    \n    var updatedTask Task\n    if err := json.NewDecoder(r.Body).Decode(&updatedTask); err != nil {\n        http.Error(w, "Invalid JSON", http.StatusBadRequest)\n        return\n    }\n    \n    for i, t := range tasks {\n        if t.ID == id {\n            tasks[i].Title = updatedTask.Title\n            tasks[i].Completed = updatedTask.Completed\n            w.Header().Set("Content-Type", "application/json")\n            json.NewEncoder(w).Encode(tasks[i])\n            return\n        }\n    }\n    http.Error(w, "Task not found", http.StatusNotFound)\n}
\n

2.4. DELETE /tasks/{id} — Delete a task

\n
func deleteTask(w http.ResponseWriter, r *http.Request) {\n    idStr := r.PathValue("id")\n    id, err := strconv.Atoi(idStr)\n    if err != nil {\n        http.Error(w, "Invalid task ID", http.StatusBadRequest)\n        return\n    }\n    \n    for i, t := range tasks {\n        if t.ID == id {\n            tasks = append(tasks[:i], tasks[i+1:]...)\n            w.WriteHeader(http.StatusNoContent)\n            return\n        }\n    }\n    http.Error(w, "Task not found", http.StatusNotFound)\n}
\n

Please note

Blogs

Book Recommendations