So I'm participating in the HNG13 internship program and our stage 0 task was to build a simple API to Return your Profile and a Random Cat Fact.
I’ve been learning Go (Golang) for a while now and wanted to build it with that and here's how it went.
In this post, I’ll walk you through how I built this tiny Go + Gin API.
🔧 Stack
Go (Golang)
Gin - HTTP web framework
catfact.ninja API - Free API to fetch random cat facts
🛠️ What the API Does
When you hit the endpoint /me, the API returns:
My name, email, and stack
The current timestamp (UTC)
A random cat fact 🐱
Here’s an example response:
{
"status": "success",
"user": {
"email": "",
"name": "",
"stack": "Go/Gin"
},
"timestamp": "2025-10-21T14:42:11Z",
"fact": "Cats sleep for 70% of their lives."
}
🚀 Setting Up the Controller
The core logic lives inside the controller. Here's the full code:
package controllers
import (
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
func GetProfile(c *gin.Context) {
ctx := c.Request.Context()
fact, err := fetchCatFact(ctx)
if err != nil {
log.Printf("Error fetching cat fact: %v", err)
fact = "Unable to fetch cat fact at this time. Did you know cats are amazing creatures?"
}
c.JSON(200, gin.H{
"status": "success",
"user": gin.H{
"email": "<your-email>",
"name": "<your-name>",
"stack": "Go/Gin",
},
"timestamp": time.Now().UTC().Format(time.RFC3339),
"fact": fact,
})
}
🐾 Fetching the Cat Fact
This function handles calling the catfact.ninja
API and parsing the response.
func fetchCatFact(ctx context.Context) (string, error) {
catFactAPIURL := "https://catfact.ninja/fact"
req, err := http.NewRequestWithContext(ctx, http.MethodGet, catFactAPIURL, nil)
if err != nil {
return "", fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Accept", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", fmt.Errorf("failed to fetch cat fact: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("cat fact API returned status: %d", resp.StatusCode)
}
type CatFactResponse struct {
Fact string `json:"fact"`
Length int `json:"length"`
}
var catFact CatFactResponse
if err := json.NewDecoder(resp.Body).Decode(&catFact); err != nil {
return "", fmt.Errorf("failed to decode response: %w", err)
}
return catFact.Fact, nil
}
🌐 Routing
To expose this functionality, I created a route under /me:
package routes
import (
"profile-api/internal/controllers"
"github.com/gin-gonic/gin"
)
func RegisterRoutes() {
r := gin.Default()
// Optional: Skip ngrok browser warning
r.Use(func(c *gin.Context) {
c.Header("ngrok-skip-browser-warning", "1")
c.Next()
})
r.GET("/me", controllers.GetProfile)
r.Run(":8080") // Start server on port 8080
}
🧪 Testing It Out
Run your app:
go run main.go
Then visit: http://localhost:8080/me
You should see your profile and a random cat fact returned in JSON.
📌 Final Thoughts
This was a small but fun project to reinforce using context, external APIs, and building structured JSON responses in Go. Plus, it’s always nice to sprinkle a little joy into development — and what’s more joyful than random cat facts?
Want to build your own version? Fork the idea, make it your own, and maybe add facts from other APIs (dog facts next? 🐶)
Let me know what you think!
Top comments (0)