DEV Community

Cover image for 🚀 The 20-Minute Production API Challenge with GoFr
Umang Mundhra
Umang Mundhra

Posted on

🚀 The 20-Minute Production API Challenge with GoFr

Most developers spend 4 hours setting up what GoFr does in 20 minutes.
 Let’s prove it.


⏱️ The Setup Fatigue Every Go Developer Knows

ou’ve been there.
 Your product manager says, “We just need a simple API that stores orders in a database and publishes events.”
Simple, right?

Then it begins:

  • ⏱️ Hour 1: Database setup, pooling, and error handling
  • ⏱️ Hour 2: Logging, context propagation
  • ⏱️ Hour 3: Metrics and tracing configuration
  • ⏱️ Hour 4: Health checks and graceful shutdowns

Four hours later… you finally write your first line of actual business logic.

GoFr changes that.
 
It ships with production-grade defaults — observability, migrations, PubSub, metrics — all wired automatically.

Your job? Just write code that matters.


🧩 Minute 0–5: Your First Endpoint

package main

import "gofr.dev/pkg/gofr"

func main() {
 app := gofr.New()

 app.GET("/ping", func(c *gofr.Context) (any, error) {
  return map[string]string{"message": "pong"}, nil
 })

 app.Run()
}
Enter fullscreen mode Exit fullscreen mode

✅ Health checks
 
✅ Metrics & tracing
 
✅ Structured logs
 
âś… Graceful shutdown

No config. No boilerplate. Just business logic.

🔌 Minute 5–10: Add Database & PubSub

package main

import "gofr.dev/pkg/gofr"

func main() {
    app := gofr.New()

    app.GET("/ping", func(c *gofr.Context) (any, error) {
       return map[string]string{"message": "pong"}, nil
    })

    app.Run()
}

func PublishOrder(c *gofr.Context) (any, error) {
    var order struct {
       ID     string `json:"id"`
       Status string `json:"status"`
    }

    if err := c.Bind(&order); err != nil {
       return nil, err
    }

    msg, _ := json.Marshal(order)
    return "Published", c.GetPublisher().Publish(c, "orders", msg)
}
Enter fullscreen mode Exit fullscreen mode

In a few lines, you:

  • Parse JSON input
  • Serialize and publish events
  • Get automatic tracing, retries, and logs

Everything observable — out of the box.


🧱 Minute 10–15: Migrations as Code

package migrations

import "gofr.dev/pkg/gofr/migration"

func createUsersTable() migration.Migrate {
 return migration.Migrate{
  UP: func(d migration.Datasource) error {
   _, err := d.SQL.Exec(`CREATE TABLE IF NOT EXISTS users (
                id INT PRIMARY KEY AUTO_INCREMENT,
                name VARCHAR(50) NOT NULL
            )`)
   return err
  },
 }
}
Enter fullscreen mode Exit fullscreen mode

Wire it up in main.go:

a.Migrate(migrations.All())
Enter fullscreen mode Exit fullscreen mode

Run your app — GoFr automatically applies and tracks migrations.
 No separate tools, no manual SQL scripts.


⚙️ Minute 15–20: CRUD in One Line

type User struct {
    ID   int    `json:"id" sql:"auto_increment"`
    Name string `json:"name" sql:"not_null"`
}

func (u *User) RestPath() string { return "users" }

app.AddRESTHandlers(&User{})
Enter fullscreen mode Exit fullscreen mode

Boom.
 

Instant REST endpoints:

  • POST /users
  • GET /users
  • GET /users/{id}
  • PUT /users/{id}
  • DELETE /users/{id}

All with SQL generation, validation, logging, and metrics — no extra setup.


📊 What You Built in 20 Minutes



| Capability          | Traditional Setup Time | With GoFr     |
|---------------------|------------------------|---------------|
| Database & pooling  | 45 min                 | Built-in      |
| Logging & metrics   | 60 min                 | Automatic     |
| Health checks       | 15 min                 | Automatic     |
| Tracing             | 45 min                 | Automatic     |
| Migrations          | 30 min                 | 5 min         |
| CRUD endpoints      | 60 min                 | 1 line        |
| PubSub              | 30 min                 | 5 min         |
| 
    Total**           | 4–5 hr                 | 20 min ✅     |
Enter fullscreen mode Exit fullscreen mode

🔍 Observability You Didn’t Write

Structured logs:

INFO [21:30:35] Loaded config from file: ./configs/.env
DEBU [21:30:35] Container is being created
DEBU [21:30:35] connecting to redis at 'localhost:2002' on database 0
DEBU [21:30:35] hello                            REDIS      3369µs hello 3
DEBU [21:30:35] pipeline                         REDIS       399µs client setinfo LIB-NAME go-redis(,go1.25.0): ERR unknown subcommand 'setinfo'. Try CLIENT HELP.
DEBU [21:30:35] ping                             REDIS      8551µs ping
INFO [21:30:35] connected to redis at localhost:2002 on database 0
DEBU [21:30:35] generating database connection string for 'mysql'
DEBU [21:30:35] registering sql dialect 'mysql' for traces
DEBU [21:30:35] connecting to 'root' user to 'test' database at 'localhost:2001'
INFO [21:30:35] connected to 'root' user to 'test' database at 'localhost:2001'
INFO [21:30:35] Exporting traces to GoFr at https://tracer.gofr.dev
INFO [21:30:35] registered static files at endpoint /static/ from directory /Users/zopdev/Projects/GoFr.dev/gofr/examples/http-server/static
INFO [21:30:35] GoFr records the number of active servers. Set GOFR_TELEMETRY=false in configs to disable it.
INFO [21:30:35] Starting server on port: 9000
INFO [21:30:35] Starting metrics server on port: 2121
INFO [21:30:40] 82266bb78cdd997f43ce242b665c3b49 Name came empty
INFO [21:30:40] 82266bb78cdd997f43ce242b665c3b49 200         271µs GET /hello 
DEBU [21:30:44] QueryRowContext                  SQL           4µs select 2+2
INFO [21:30:44] dfcdd5085b9542dc5ef17bf52bbae508 200        4858µs GET /mysql
Enter fullscreen mode Exit fullscreen mode

Metrics (Prometheus):

  • app_http_response
  • app_sql_stats
  • app_pubsub_publish_total_count

Tracing:
 Every request is automatically traced through HTTP → SQL → PubSub.
 No extra code, no instrumentation needed.

💡 Why This Matters

When setup takes hours, iteration slows.
 GoFr removes that friction.

✅ Faster onboarding
 
✅ Consistent architecture
 
✅ Built-in reliability
 
âś… Zero boilerplate

Production-ready doesn’t have to mean setup-heavy.

🧭 Your Turn:

Step 1:

go get gofr.dev

Step 2:
 Set a timer for 20 minutes.
Step 3:
 Build your first fully observable, database-backed API.
Step 4:
 Share your result with the community.

👉 Quick Start Guide →
 
👉 Example Repos →

The best code is the code you don’t have to write.

 GoFr lets you skip the setup — and start shipping.

💬 If You Enjoyed This

Leave a comment with how fast you built yours.


 Tag it with #GoFrChallenge — and let’s see how many developers can beat the 20-minute mark.

Top comments (0)