Building APIs with Go
One of the most common real-world uses of Go is building fast, reliable, and scalable REST APIs. Go’s standard library provides everything needed to create production-ready APIs without heavy frameworks.
In this lesson, you will learn how to design, build, and run a basic REST API using Go, step by step.
What Is an API?
An API (Application Programming Interface) allows different software systems to communicate with each other over a network.
In web development, APIs usually exchange data using HTTP and return data in JSON format.
Why Go for APIs?
Go is widely used for APIs because:
- It is fast and memory-efficient
- It handles concurrency extremely well
- The standard library includes HTTP tools
- It produces standalone binaries
Many cloud services and microservices are written in Go for these reasons.
Understanding HTTP Basics
Before building an API, it is important to understand basic HTTP concepts:
- GET – Retrieve data
- POST – Create new data
- PUT – Update existing data
- DELETE – Remove data
APIs usually respond with a status code such as 200, 201,
or 404.
Creating a Simple HTTP Server
Go’s net/http package allows you to create a web server easily.
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Welcome to the Go API")
})
http.ListenAndServe(":8080", nil)
}
Running this program starts a server on port 8080.
Creating an API Endpoint
Let’s create an endpoint that returns user data in JSON format.
package main
import (
"encoding/json"
"net/http"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
func userHandler(w http.ResponseWriter, r *http.Request) {
user := User{
ID: 1,
Name: "Alice",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(user)
}
func main() {
http.HandleFunc("/user", userHandler)
http.ListenAndServe(":8080", nil)
}
Visiting /user returns JSON data for a user.
Handling Different HTTP Methods
APIs must respond differently based on request methods.
func handler(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
w.Write([]byte("GET request"))
case http.MethodPost:
w.Write([]byte("POST request"))
default:
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
}
Reading JSON from Request Body
APIs often accept JSON input from clients.
func createUser(w http.ResponseWriter, r *http.Request) {
var user User
json.NewDecoder(r.Body).Decode(&user)
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(user)
}
This allows clients to send JSON data to the API.
Returning Proper HTTP Status Codes
Good APIs always return correct status codes.
200 OK– Successful request201 Created– Resource created400 Bad Request– Invalid input500 Internal Server Error– Server failure
Error Handling in APIs
Always validate input and handle errors gracefully.
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
Structuring API Projects
In real projects, APIs are organized into:
- Handlers
- Models
- Services
- Routes
This keeps code clean and maintainable.
Testing API Endpoints
Go provides tools for testing HTTP handlers.
req := httptest.NewRequest("GET", "/user", nil)
w := httptest.NewRecorder()
userHandler(w, req)
fmt.Println(w.Body.String())
Real-World Use Case
A production API may:
- Handle thousands of requests per second
- Use concurrency for performance
- Connect to databases
- Run behind load balancers
Go’s design makes all of this achievable with minimal complexity.
Practice Exercises
Exercise 1
Create an API endpoint that returns a list of products.
Exercise 2
Implement a POST endpoint that accepts JSON input.
Key Takeaways
- Go is ideal for building APIs
- The standard library is powerful
- JSON handling is simple
- Proper structure improves scalability
What’s Next?
In the next lesson, you will learn how to use the HTTP package in depth to build more advanced API features.