DEV Community

Tirupathi Sekhar
Tirupathi Sekhar

Posted on

Building Observability-First Microservices in Go with GoFr

When developing backend microservices in Go, standard libraries and minimal routers give you complete control, but assembling production essentials—structured logging, OpenTelemetry tracing, Prometheus metrics, and datasource health checks—often leads to heaps of repetitive boilerplate.

Enter GoFr: an opinionated Go framework designed to simplify microservice architecture while providing built-in observability and container-ready defaults.

Here is a hands-on look at what makes GoFr stand out and how quickly you can get a production-ready REST service running.

What Makes GoFr Different?
Built-in Observability: Structured logs, OpenTelemetry traces, and runtime metrics work out of the box without requiring dozens of external middleware imports.

Standardized REST Routing: Idiomatic response handling and request binding that adhere strictly to REST conventions.

Datasource Health Checks: Native support for SQL, NoSQL, and key-value stores with integrated pinging and connection lifecycle management.

Zero-Downtime Reconfiguration: Built-in ability to adjust log levels dynamically at runtime without restarting processes.

Quickstart: Building an API in GoFr

  1. Prerequisites & Setup Ensure you have Go installed, then initialize your project and pull the framework:
mkdir gofr-quickstart && cd gofr-quickstart
go mod init gofr-quickstart
go get -u gofr.dev/pkg/gofr
Enter fullscreen mode Exit fullscreen mode
  1. Writing the Service Create a main.go file with a basic health and entity route:

'''
Go
package main

import (
"errors"
"gofr.dev/pkg/gofr"
)

type User struct {
ID int json:"id"
Name string json:"name"
Role string json:"role"
}

func main() {
// Initialize a new GoFr application
app := gofr.New()

// Simple greeting endpoint
app.GET("/greet", func(ctx *gofr.Context) (any, error) {
    name := ctx.Param("name")
    if name == "" {
        name = "Developer"
    }
    return "Hello, " + name + "!", nil
})

// JSON response endpoint with parameter binding
app.GET("/users/{id}", func(ctx *gofr.Context) (any, error) {
    id := ctx.PathParam("id")
    if id != "1" {
        return nil, errors.New("user not found")
    }

    return User{
        ID:   1,
        Name: "Alex Mercer",
        Role: "Software Engineer",
    }, nil
})

// Starts server on port 8000 by default
app.Run()
Enter fullscreen mode Exit fullscreen mode

}
'''

  1. Running and Testing Start your microservice:

Bash
go run main.go
Test your endpoints using curl:

Bash

Greet endpoint

curl http://localhost:8000/greet?name=GoDeveloper

User endpoint

curl http://localhost:8000/users/1
Notice the terminal output: every incoming request automatically generates structured logs containing trace IDs, latency metrics, and HTTP status codes with zero custom logging logic.

Final Thoughts
For engineering teams aiming to scale Go services efficiently without spending days configuring tracing exporters and routing boilerplate, GoFr offers a cohesive, battery-included framework. It bridges the gap between raw HTTP handlers and full-blown microservice platforms.

Repository: github.com/gofr-dev/gofr

Documentation: gofr.dev

Top comments (0)