Welcome back to the KpolitX tech blog! In our first post, we built out a pristine development environment. Now, it is time to put that environment to work by building a foundational backend component: an API.
When building microservices or backend applications in Go, two primary architectural patterns dominate the conversation: REST (Representational State Transfer) and gRPC (Google Remote Procedure Call).
In this guide, we will break down the fundamental differences between them and look at how they perform in code.
1. The Core Philosophical Differences
- REST (JSON over HTTP/1.1): REST has been the web standard for decades. It is resource-oriented, uses human-readable JSON payloads, and relies heavily on standard HTTP methods (GET, POST, PUT, DELETE). It is universally compatible with web browsers.
- gRPC (Protocol Buffers over HTTP/2): Developed by Google, gRPC uses binary serialization (Protocol Buffers) and runs on HTTP/2. Instead of exposing web resources, it focuses on calling methods on a remote server as if they were local functions. It is built for raw speed, contract enforcement, and high-performance microservice communication.
2. Building a Simple REST API in Go
Go's standard library (net/http) makes spinning up a basic REST server remarkably straightforward without needing heavy external frameworks.
package main
import (
"encoding/json"
"net/http"
)
type Message struct {
Status string `json:"status"`
Content string `json:"content"`
}
func handlePing(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
response := Message{Status: "success", Content: "Pong from Go REST API!"}
json.NewEncoder(w).Encode(response)
}
func main() {
http.HandleFunc("/ping", handlePing)
println("REST API server running on port 8080...")
http.ListenAndServe(":8080", nil)
}
3. Building a gRPC Service in Go
With gRPC, you define your service contract first using a .proto file, and then compile it into Go code using the Protocol Buffers compiler.
Step A: Define the Contract (service.proto)
syntax = "proto3";
package api;
option go_package = "/api";
service PingService {
rpc Ping (PingRequest) returns (PingResponse);
}
message PingRequest {
string name = 1;
}
message PingResponse {
string message = 1;
}
Step B: Implement the Server in Go
Once compiled, you implement the generated interface:
package main
import (
context "context"
"log"
"net"
pb "your_project/api"
"google.golang.org/grpc"
)
type server struct {
pb.UnimplementedPingServiceServer
}
func (s *server) Ping(ctx context.Context, req *pb.PingRequest) (*pb.PingResponse, error) {
return &pb.PingResponse{Message: "Hello " + req.Name + " from gRPC!"}, nil
}
func main() {
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterPingServiceServer(s, &server{})
log.Println("gRPC server running on port 50051...")
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
4. Performance & When to Use Which
When you benchmark them side-by-side:
- Payload Size: gRPC uses binary serialization, making messages significantly smaller than verbose text-based JSON.
- Speed & Throughput: HTTP/2 allows gRPC to multiplex multiple requests over a single TCP connection, drastically cutting down latency under high concurrency.
The Golden Rule: Use REST when building public-facing APIs or web applications where browser compatibility and human-readability are critical. Use gRPC for internal high-throughput communication between backend microservices.

Comments
Post a Comment