<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Umang Mundhra</title>
    <description>The latest articles on DEV Community by Umang Mundhra (@umang01hash).</description>
    <link>https://dev.to/umang01hash</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1204067%2F52b77154-92d0-4c62-88b6-82d97af25d59.jpeg</url>
      <title>DEV Community: Umang Mundhra</title>
      <link>https://dev.to/umang01hash</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/umang01hash"/>
    <language>en</language>
    <item>
      <title>🚀 From “Works Fine” to “Feels Instant”: Tuning a GoFr API Like Engineers, Not Magicians</title>
      <dc:creator>Umang Mundhra</dc:creator>
      <pubDate>Fri, 26 Dec 2025 11:41:57 +0000</pubDate>
      <link>https://dev.to/umang01hash/from-works-fine-to-feels-instant-tuning-a-gofr-api-like-engineers-not-magicians-4h2m</link>
      <guid>https://dev.to/umang01hash/from-works-fine-to-feels-instant-tuning-a-gofr-api-like-engineers-not-magicians-4h2m</guid>
      <description>&lt;p&gt;A real-world story of making a GoFr API go from “fine” to “feels instant” using observability, DB tuning &amp;amp; service-level reliability.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F27cfvxgvyhprww2herdb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F27cfvxgvyhprww2herdb.png" alt="From “Works Fine” to “Feels Instant”: Tuning a GoFr API Like Engineers, Not Magicians" width="800" height="906"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most performance stories begin dramatically — with outages, angry PMs, dashboards on fire.&lt;/p&gt;

&lt;p&gt;Ours began mundanely.&lt;/p&gt;

&lt;p&gt;The API was fine. It returned order details, fetched user info, stitched both, responded in a couple hundred ms. P50 looked good. No error spikes. Monitoring wasn’t screaming.&lt;/p&gt;

&lt;p&gt;But the UI told a different story.&lt;/p&gt;

&lt;p&gt;Click → …loading… → click → …loading again…&lt;/p&gt;

&lt;p&gt;Not broken.&lt;br&gt;
Not slow.&lt;br&gt;
Just not delightful.&lt;/p&gt;

&lt;p&gt;So we decided to see how far we could push fine toward fast — without rewriting the architecture, adding new libraries, or making the code unpleasant to work with.&lt;/p&gt;

&lt;p&gt;This is how GoFr made that journey almost embarrassingly smooth.&lt;/p&gt;


&lt;h2&gt;
  
  
  🧩 The Starting Point
&lt;/h2&gt;

&lt;p&gt;A simple GoFr handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func GetOrderDetails(ctx *gofr.Context) (any, error) {
    orderID := ctx.Param("id")

    // DB call
    var order Order
    err := ctx.SQL.QueryRowContext(ctx,
        "SELECT id, user_id, status, total FROM orders WHERE id=?", orderID,
    ).Scan(&amp;amp;order.ID, &amp;amp;order.UserID, &amp;amp;order.Status, &amp;amp;order.Total)
    if err != nil {
        return nil, err
    }

    // HTTP call
    userService := ctx.GetHTTPService("user-service")
    resp, err := userService.Get(ctx, "/users/"+order.UserID, nil)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    var user User
    json.NewDecoder(resp.Body).Decode(&amp;amp;user)

    return OrderDetailsResponse{Order: order, User: user}, nil
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clean. Predictable. One context.&lt;br&gt;
Nothing to rewrite — we just needed to understand what was eating time.&lt;/p&gt;


&lt;h2&gt;
  
  
  🔍 Step 1 — Let Observability Tell the Story
&lt;/h2&gt;

&lt;p&gt;No custom tracing, no slogging through logs, no extra plugins.&lt;br&gt;
GoFr already ships with:&lt;/p&gt;

&lt;p&gt;✔ Tracing per request&lt;br&gt;
✔ SQL + HTTP span instrumentation&lt;br&gt;
✔ Structured logs linked to traces&lt;/p&gt;

&lt;p&gt;Within minutes, patterns emerged:&lt;/p&gt;

&lt;p&gt;⛔ occasional DB spans ballooned&lt;br&gt;
🟢 HTTP calls were steady&lt;br&gt;
📈 latency spikes mapped to DB wait time&lt;/p&gt;

&lt;p&gt;Mystery solved.&lt;br&gt;
No guessing → just graphs.&lt;/p&gt;


&lt;h2&gt;
  
  
  ⚡ Step 2 — Fixing the Real Culprit (SQL)
&lt;/h2&gt;

&lt;p&gt;The query looked harmless:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT id, user_id, status, total FROM orders WHERE id = ?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But on a growing table, “harmless” becomes “sluggish”.&lt;/p&gt;

&lt;p&gt;We added the correct index + tuned connection pooling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DB_MAX_OPEN_CONNS=25
DB_MAX_IDLE_CONNS=10
DB_CONN_MAX_LIFETIME=5m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No code change.&lt;/p&gt;

&lt;p&gt;Spans shrank immediately. P95 dipped.&lt;br&gt;
The app felt faster.&lt;/p&gt;


&lt;h2&gt;
  
  
  Step 3: Hardening the HTTP Call — The Right Way in GoFr
&lt;/h2&gt;

&lt;p&gt;The downstream user service wasn’t slow, but it was still a point of risk:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if it slowed down → our API slowed down&lt;/li&gt;
&lt;li&gt;if it failed → we returned errors upstream&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of wrapping custom retry logic manually, GoFr lets us configure reliability at the service layer itself — once, globally.&lt;/p&gt;

&lt;p&gt;We updated the service registration like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a.AddHTTPService("user-service", "https://users.internal",
    &amp;amp;service.RetryConfig{MaxRetries: 3},
    &amp;amp;service.CircuitBreakerConfig{
        Threshold: 5,
        Interval:  2 * time.Second,
    },
    &amp;amp;service.RateLimiterConfig{
        Requests: 50,
        Window:   time.Second,
        Burst:    75,
    },
    &amp;amp;service.HealthConfig{HealthEndpoint: "health"},
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now every request to &lt;code&gt;user-service&lt;/code&gt; automatically benefits from:&lt;/p&gt;

&lt;p&gt;✔ retry handling&lt;br&gt;
✔ backoff behavior&lt;br&gt;
✔ rate limiting&lt;br&gt;
✔ circuit breaker protection&lt;br&gt;
✔ unified tracing + logging through ctx&lt;/p&gt;

&lt;p&gt;No wrappers, no middleware sprawl, no rewriting handlers.&lt;/p&gt;

&lt;p&gt;The handler stayed as clean as before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func GetOrderDetails(ctx *gofr.Context) (any, error) {
    orderID := ctx.Param("id")

    // fetch order (unchanged)
    ...

    userService := ctx.GetHTTPService("user-service")

    resp, err := userService.Get(ctx, "/users/"+order.UserID, nil)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    var user User
    json.NewDecoder(resp.Body).Decode(&amp;amp;user)

    return OrderDetailsResponse{Order: order, User: user}, nil
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This step didn’t drastically reduce average response time —&lt;br&gt;
but it made latency spikes vanish and failures behave predictably.&lt;/p&gt;

&lt;p&gt;That’s the difference between being fast and being reliable.&lt;/p&gt;




&lt;h2&gt;
  
  
  🪶 Step 4 — Send Only What UI Needs
&lt;/h2&gt;

&lt;p&gt;We removed unused fields from the response payload.&lt;/p&gt;

&lt;p&gt;Smaller payload = faster in real networks.&lt;br&gt;
Performance is rarely one giant win — it’s a hundred tiny wins.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 The Most Interesting Part?
&lt;/h2&gt;

&lt;p&gt;Through all improvements, our handler never got messy.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;func GetOrderDetails(ctx *gofr.Context) (any, error) { ... }&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;One context for everything:&lt;/p&gt;

&lt;p&gt;🟦 DB&lt;br&gt;
🟦 HTTP&lt;br&gt;
🟦 Logs&lt;br&gt;
🟦 Tracing&lt;br&gt;
🟦 Metrics&lt;/p&gt;

&lt;p&gt;No glue code. No noise. Only logic.&lt;/p&gt;

&lt;p&gt;That’s the real win.&lt;/p&gt;




&lt;p&gt;💭 What We Learned&lt;br&gt;
Observability first → performance second&lt;br&gt;
Small DB + HTTP improvements beat fancy rewrites&lt;br&gt;
A unified context keeps code elegant under load&lt;br&gt;
Fast is good. Predictably fast is better.&lt;br&gt;
GoFr didn’t give us magic.&lt;br&gt;
It gave us clarity — and clarity made us faster.&lt;/p&gt;




&lt;h2&gt;
  
  
  If Your API is “Fine” Today…
&lt;/h2&gt;

&lt;p&gt;Before optimizing everything:&lt;/p&gt;

&lt;p&gt;👉 trace it&lt;br&gt;
👉 index what matters&lt;br&gt;
👉 configure retries&lt;br&gt;
👉 fix first bottleneck&lt;br&gt;
👉 keep code simple&lt;/p&gt;

&lt;p&gt;You might be one index + one retry away from delight.&lt;/p&gt;




&lt;h2&gt;
  
  
  📚 Try this yourself
&lt;/h2&gt;

&lt;p&gt;🚀 Quick start: &lt;a href="https://gofr.dev/docs/quick-start" rel="noopener noreferrer"&gt;https://gofr.dev/docs/quick-start&lt;/a&gt;&lt;br&gt;
💻 Source code: &lt;a href="https://github.com/gofr-dev/gofr" rel="noopener noreferrer"&gt;https://github.com/gofr-dev/gofr&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sometimes the best upgrade isn’t changing tech —&lt;br&gt;
It’s unlocking the tech you already have.&lt;/p&gt;

</description>
      <category>database</category>
      <category>go</category>
      <category>performance</category>
      <category>api</category>
    </item>
    <item>
      <title>🚀 The 20-Minute Production API Challenge with GoFr</title>
      <dc:creator>Umang Mundhra</dc:creator>
      <pubDate>Fri, 17 Oct 2025 17:00:16 +0000</pubDate>
      <link>https://dev.to/umang01hash/the-20-minute-production-api-challenge-with-gofr-1k22</link>
      <guid>https://dev.to/umang01hash/the-20-minute-production-api-challenge-with-gofr-1k22</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Most developers spend 4 hours setting up what GoFr does in 20 minutes.&lt;br&gt;
 Let’s prove it.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ⏱️ The Setup Fatigue Every Go Developer Knows
&lt;/h2&gt;

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

&lt;p&gt;Then it begins:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⏱️ &lt;strong&gt;Hour 1:&lt;/strong&gt; Database setup, pooling, and error handling&lt;/li&gt;
&lt;li&gt;⏱️ &lt;strong&gt;Hour 2:&lt;/strong&gt; Logging, context propagation&lt;/li&gt;
&lt;li&gt;⏱️ &lt;strong&gt;Hour 3:&lt;/strong&gt; Metrics and tracing configuration&lt;/li&gt;
&lt;li&gt;⏱️ &lt;strong&gt;Hour 4:&lt;/strong&gt; Health checks and graceful shutdowns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Four hours later… you finally write your first line of actual business logic.&lt;/p&gt;

&lt;p&gt;GoFr changes that.   &lt;em&gt;&lt;strong&gt;It ships with production-grade defaults — observability, migrations, PubSub, metrics — all wired automatically.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Your job? Just write code that matters.&lt;/p&gt;


&lt;h2&gt;
  
  
  🧩 Minute 0–5: Your First Endpoint
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;✅ Health checks  &lt;br&gt;
✅ Metrics &amp;amp; tracing  &lt;br&gt;
✅ Structured logs  &lt;br&gt;
✅ Graceful shutdown&lt;/p&gt;
&lt;h2&gt;
  
  
  No config. No boilerplate. Just business logic.
&lt;/h2&gt;
&lt;h2&gt;
  
  
  🔌 Minute 5–10: Add Database &amp;amp; PubSub
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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(&amp;amp;order); err != nil {
       return nil, err
    }

    msg, _ := json.Marshal(order)
    return "Published", c.GetPublisher().Publish(c, "orders", msg)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In a few lines, you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Parse JSON input&lt;/li&gt;
&lt;li&gt;Serialize and publish events&lt;/li&gt;
&lt;li&gt;Get automatic tracing, retries, and logs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything observable — out of the box.&lt;/p&gt;


&lt;h2&gt;
  
  
  🧱 Minute 10–15: Migrations as Code
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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
  },
 }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Wire it up in &lt;code&gt;main.go&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a.Migrate(migrations.All())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run your app — GoFr automatically applies and tracks migrations.  No separate tools, no manual SQL scripts.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ Minute 15–20: CRUD in One Line
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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(&amp;amp;User{})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Boom.  &lt;/p&gt;

&lt;p&gt;Instant REST endpoints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;POST &lt;code&gt;/users&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;GET &lt;code&gt;/users&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;GET &lt;code&gt;/users/{id}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;PUT &lt;code&gt;/users/{id}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;DELETE &lt;code&gt;/users/{id}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All with SQL generation, validation, logging, and metrics — no extra setup.&lt;/p&gt;




&lt;h2&gt;
  
  
  📊 What You Built in 20 Minutes
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

| Capability          | Traditional Setup Time | With GoFr     |
|---------------------|------------------------|---------------|
| Database &amp;amp; pooling  | 45 min                 | Built-in      |
| Logging &amp;amp; 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 ✅     |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔍 Observability You Didn’t Write
&lt;/h2&gt;

&lt;p&gt;Structured logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Metrics (Prometheus):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;app_http_response&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;app_sql_stats&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;app_pubsub_publish_total_count&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tracing:  Every request is automatically traced through HTTP → SQL → PubSub.  No extra code, no instrumentation needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  💡 Why This Matters
&lt;/h2&gt;

&lt;p&gt;When setup takes hours, iteration slows.  GoFr removes that friction.&lt;/p&gt;

&lt;p&gt;✅ Faster onboarding  &lt;br&gt;
✅ Consistent architecture  &lt;br&gt;
✅ Built-in reliability  &lt;br&gt;
✅ Zero boilerplate&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Production-ready doesn’t have to mean setup-heavy.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🧭 Your Turn:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;go get gofr.dev&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: &lt;/strong&gt; Set a timer for 20 minutes.&lt;br&gt;
&lt;strong&gt;Step 3:&lt;/strong&gt;  Build your first fully observable, database-backed API.&lt;br&gt;
&lt;strong&gt;Step 4: &lt;/strong&gt; Share your result with the community.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://gofr.dev/docs/quick-start/introduction" rel="noopener noreferrer"&gt;Quick Start Guide → &lt;/a&gt; &lt;br&gt;
👉 &lt;a href="https://github.com/gofr-dev/gofr" rel="noopener noreferrer"&gt;Example Repos →&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The best code is the code you don’t have to write.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt; GoFr lets you skip the setup — and start shipping.&lt;/p&gt;

&lt;h2&gt;
  
  
  💬 If You Enjoyed This
&lt;/h2&gt;

&lt;p&gt;Leave a comment with how fast you built yours. &lt;/p&gt;

&lt;p&gt; Tag it with &lt;strong&gt;#GoFrChallenge&lt;/strong&gt; — and let’s see how many developers can beat the 20-minute mark.&lt;/p&gt;

</description>
      <category>go</category>
      <category>api</category>
      <category>productivity</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Open Source in 2025: A Door You Can Walk Through</title>
      <dc:creator>Umang Mundhra</dc:creator>
      <pubDate>Mon, 08 Sep 2025 06:22:51 +0000</pubDate>
      <link>https://dev.to/umang01hash/open-source-in-2025-a-door-you-can-walk-through-4ecc</link>
      <guid>https://dev.to/umang01hash/open-source-in-2025-a-door-you-can-walk-through-4ecc</guid>
      <description>&lt;p&gt;When people hear “open source contribution,” many imagine a massive, complex codebase guarded by experts. It feels like a giant rock — immovable, intimidating, and impossible to climb.&lt;/p&gt;

&lt;p&gt;But here’s the truth: open source isn’t a rock. It’s a door. And once you knock, you’ll realize it’s far more open than you think.&lt;/p&gt;




&lt;h2&gt;
  
  
  The GSOC 2025 Reality Check
&lt;/h2&gt;

&lt;p&gt;This year’s Google Summer of Code (GSoC 2025) paints a fascinating picture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;98,698 developers registered from 172 countries.&lt;/li&gt;
&lt;li&gt;Only 1,280 contributors were selected.&lt;/li&gt;
&lt;li&gt;And here’s the kicker: 43% of accepted contributors had never contributed to open source before.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That means nearly half the selected contributors started from scratch — no previous experience, no big projects behind them. Just curiosity and persistence.&lt;/p&gt;

&lt;p&gt;So if they can do it, what’s stopping you?&lt;/p&gt;




&lt;h2&gt;
  
  
  A Story from GoFr Summer of Code
&lt;/h2&gt;

&lt;p&gt;At &lt;strong&gt;GoFr&lt;/strong&gt; — our open-source Golang framework — we took a leap of faith and organized our &lt;strong&gt;first ever GoFr Summer of Code&lt;/strong&gt; (GoFr SoC) this summer. The response truly amazed us!&lt;/p&gt;

&lt;p&gt;The numbers tell an incredible story:&lt;/p&gt;

&lt;p&gt;✨ &lt;strong&gt;2,454+ engagements and 65,310+ impressions&lt;/strong&gt; from the community&lt;br&gt;
📝 &lt;strong&gt;109 proposals submitted&lt;/strong&gt; by passionate developers&lt;br&gt;
✅ &lt;strong&gt;38 contributors selected&lt;/strong&gt; to work on real problem statements with GoFr&lt;br&gt;
🎉 &lt;strong&gt;8 contributors successfully completed their projects&lt;/strong&gt;, merging their PRs into the GoFr codebase&lt;br&gt;
Over two months, contributors worked on meaningful features like &lt;strong&gt;OnStartHook implementations&lt;/strong&gt; and database integrations including &lt;strong&gt;CouchBase&lt;/strong&gt; and &lt;strong&gt;OracleDB&lt;/strong&gt;. These weren’t trivial — they were real enhancements that strengthened GoFr’s ecosystem.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Example: PR #2052&lt;/strong&gt; — a student contributor successfully integrated OracleDB support after learning the framework’s database adapter patterns in just weeks.&lt;/p&gt;

&lt;p&gt;What made the difference wasn’t fancy degrees or years of experience. It was their willingness to learn — and their smart use of modern development tools.&lt;/p&gt;




&lt;h2&gt;
  
  
  How AI Has Changed the Open Source Game
&lt;/h2&gt;

&lt;p&gt;Contributing to open source used to feel like wandering a maze blindfolded.&lt;/p&gt;

&lt;p&gt;Now, tools like &lt;strong&gt;GitHub Copilot&lt;/strong&gt;, &lt;strong&gt;Cursor&lt;/strong&gt;, and &lt;strong&gt;Windsurf&lt;/strong&gt; can:&lt;/p&gt;

&lt;p&gt;Summarize project structure in plain English&lt;br&gt;
Trace how functions flow across files&lt;br&gt;
Suggest relevant docs/tests for an issue&lt;br&gt;
Help you quickly onboard into unfamiliar codebases&lt;br&gt;
This doesn’t mean AI replaces you. The best contributors use it as an &lt;strong&gt;accelerator for learning, not a shortcut for thinking.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Our GoFr Summer of Code contributors leveraged these tools to understand complex database integration patterns and framework architectures. The AI didn’t write their code — it helped them navigate and comprehend existing patterns so they could contribute authentically.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Your Pathway into Open Source in 2025&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here’s a simple, practical roadmap to start contributing:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Pick Your Tools&lt;/strong&gt;&lt;br&gt;
Choose an AI assistant that fits your workflow — &lt;strong&gt;Copilot, Cursor, Windsurf, or even ChatGPT&lt;/strong&gt;. Use it to clarify confusing code, not to write blind PRs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Find Your Community (Not Just a Repo)&lt;/strong&gt;&lt;br&gt;
Look for projects where maintainers respond, issues are tagged clearly, and contributors are welcomed.&lt;/p&gt;

&lt;p&gt;For Go enthusiasts: GoFr has beginner-friendly issues&lt;br&gt;
For frontend devs: React, Vue, or Astro communities are great starting points&lt;br&gt;
For infra lovers: Kubernetes and CNCF projects always need contributors&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Start Small, Build Trust&lt;/strong&gt;&lt;br&gt;
Every GoFr Summer of Code contributor began with small fixes — typos, docs, missing tests. These “low-hanging fruits” helped them build confidence and trust.&lt;/p&gt;

&lt;p&gt;Think of it as leveling up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Week 1–2:&lt;/strong&gt; Fix docs, add missing tests&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Week 3–4:&lt;/strong&gt; Pick good-first-issues&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Month 2+:&lt;/strong&gt; Implement small features&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Month 3+:&lt;/strong&gt; Propose architectural improvements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Use AI for Clarity, Not Shortcuts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let AI explain a file, or generate a draft test. But never submit something you don’t fully understand. Remember: a PR is valuable because you understood the code and improved it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;Open source is more than code. It’s about community, mentorship, and real-world impact.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For beginners:&lt;/strong&gt; it’s the fastest way to learn beyond classrooms&lt;br&gt;
&lt;strong&gt;For students:&lt;/strong&gt; it builds credibility far greater than college projects&lt;br&gt;
&lt;strong&gt;For professionals:&lt;/strong&gt; it’s a way to give back and sharpen your skills&lt;/p&gt;

&lt;p&gt;And in 2025, with AI lowering the barrier, the opportunities are endless.&lt;/p&gt;




&lt;h2&gt;
  
  
  An Open Invitation
&lt;/h2&gt;

&lt;p&gt;You don’t need to contribute to GoFr — though we’d love to welcome you to our community. The point is to pick a project you care about and take the first step.&lt;/p&gt;

&lt;p&gt;Because those eight students who successfully contributed to GoFr weren’t special. They just started.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Door Is Open
&lt;/h2&gt;

&lt;p&gt;Open source contribution in 2025 isn’t a mountain to climb — it’s a door waiting for you to walk through.&lt;/p&gt;

&lt;p&gt;AI has made the map clearer. Communities are more open than ever. Opportunities are everywhere.&lt;/p&gt;

&lt;p&gt;So the question isn’t whether you’re ready.&lt;br&gt;
The real question is: &lt;strong&gt;which door will you walk through?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;✨ The future of technology is collaborative. And it’s waiting for you.&lt;/p&gt;

&lt;p&gt;GoFr.dev Website: &lt;a href="https://gofr.dev/" rel="noopener noreferrer"&gt;https://gofr.dev/&lt;/a&gt;&lt;br&gt;
GoFr.dev Github: &lt;a href="https://github.com/gofr-dev/gofr" rel="noopener noreferrer"&gt;https://github.com/gofr-dev/gofr&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Effortless Event-Driven Go APIs with GoFr: The Simplest Pub/Sub You’ll Ever Code</title>
      <dc:creator>Umang Mundhra</dc:creator>
      <pubDate>Wed, 14 May 2025 08:42:40 +0000</pubDate>
      <link>https://dev.to/umang01hash/effortless-event-driven-go-apis-with-gofr-the-simplest-pubsub-youll-ever-code-c4</link>
      <guid>https://dev.to/umang01hash/effortless-event-driven-go-apis-with-gofr-the-simplest-pubsub-youll-ever-code-c4</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsx9fod3d1pfj29eztbey.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsx9fod3d1pfj29eztbey.png" alt="Simplest Pub/Sub using GoFr" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Modern software isn’t just fast — it’s instant. Modern applications demand responsiveness, scalability, and the ability to react in real-time to various triggers. From food delivery apps notifying you about your order to stock trading platforms processing millions of transactions, &lt;strong&gt;event-driven architectures (EDA)&lt;/strong&gt; power real-time magic.&lt;/p&gt;

&lt;p&gt;And when it comes to crafting robust backend systems, &lt;strong&gt;Go (Golang)&lt;/strong&gt; has emerged as a frontrunner. Its concurrency model, performance, and strong ecosystem make it an ideal choice for building high-throughput and reliable applications.&lt;/p&gt;

&lt;p&gt;In this article, you’ll learn why event-driven patterns matter, the common pitfalls developers face, and — most importantly — how &lt;strong&gt;GoFr&lt;/strong&gt; makes publishing, subscribing, and monitoring messages from a chore into a 10-minute coffee break.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pub/Sub Puzzle:
&lt;/h2&gt;

&lt;p&gt;Despite Go’s strengths, implementing a truly efficient and developer-friendly event-driven backend isn’t always a walk in the park. Developers often grapple with several challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integration Headaches:&lt;/strong&gt; Connecting and configuring various pub/sub message brokers (like Kafka, RabbitMQ, Google Pub/Sub) within your API can introduce significant complexity. Each often comes with its own set of configurations, client libraries, and nuances.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Producer and Consumer Choreography:&lt;/strong&gt; Setting up producers to reliably publish messages and consumers to subscribe and process them efficiently requires careful consideration of error handling, message formats, and concurrency.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Message Handling Complexity:&lt;/strong&gt; Ensuring messages are properly serialized, deserialized, validated, and processed without data loss or inconsistencies can add substantial overhead to development.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Observability Blind Spots:&lt;/strong&gt; Tracing a message across services without correlation IDs is like finding a needle in a haystack.&lt;br&gt;
These complexities can lead to increased development time, potential for errors, and a steeper learning curve for teams adopting event-driven patterns in Go.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Developers waste time reinventing wheels. GoFr replaces wheels with rockets.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  GoFr to the Rescue: Effortless Pub/Sub Unleashed:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Why do we keep saying “easiest”?&lt;/strong&gt; Because GoFr abstracts away much of the underlying complexity, allowing you to focus on your application’s logic rather than wrestling with intricate pub/sub configurations. Let’s see it in action:&lt;/p&gt;

&lt;p&gt;GoFr abstracts all of that. With just &lt;strong&gt;three method calls&lt;/strong&gt;, you can publish, subscribe, and let GoFr handle the rest:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Publishing in 3 Lines of Code
&lt;/h3&gt;

&lt;p&gt;Want to publish an order status? Here’s all the code you’ll write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func order(ctx *gofr.Context) (any, error) {  
    var data struct { OrderId, Status string }  
    ctx.Bind(&amp;amp;data)  // Auto-parses incoming JSON  

    ctx.GetPublisher().Publish(ctx, "order-logs", data) // Boom. Published.  
    return "Done", nil  
}  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No manual serialization. No connection pooling. Just &lt;code&gt;Publish()&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Subscribing? Even Easier
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.Subscribe("order-status", func(c *gofr.Context) error {  
    var order struct { OrderId, Status string }  
    c.Bind(&amp;amp;order)  // Incoming message auto-decoded  

    c.Logger.Info("Order received: ", order)  
    return nil  
})  

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GoFr auto-decodes messages, logs errors, and even handles retries for failed messages &lt;em&gt;(return an error to replay a message)&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Connect Any Broker in 30 Seconds
&lt;/h3&gt;

&lt;p&gt;GoFr comes ready for Kafka, Google Pub/Sub, and MQTT out of the box — just set environment variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# For Kafka
PUBSUB_BACKEND=KAFKA
PUBSUB_BROKER=localhost:9092
CONSUMER_ID=order-consumer

# For Google Pub/Sub
PUBSUB_BACKEND=GOOGLE
GOOGLE_PROJECT_ID=project-order
GOOGLE_SUBSCRIPTION_NAME=order-consumer

# For MQTT
PUBSUB_BACKEND=MQTT
MQTT_HOST=localhost
MQTT_PORT=1883
MQTT_CLIENT_ID_SUFFIX=test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;🔥 Zero Code Changes: Switch from Kafka to Google Pub/Sub by updating &lt;code&gt;.env&lt;/code&gt; — no Go code changes needed.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Extending to Azure Event Hub, NATS, and More
&lt;/h3&gt;

&lt;p&gt;What about other powerful pub/sub technologies like Azure Event Hub or NATS? GoFr’s extensibility shines here. You can easily integrate them using dedicated GoFr client packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import (
   "time"
   "gofr.dev/pkg/gofr"
   "gofr.dev/pkg/pubsub/nats"
)

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

    app.AddPubSub(nats.New(nats.Config{
        Server: "nats://localhost:4222",
        Stream: nats.StreamConfig{
            Stream:   "mystream",
            Subjects: []string{"orders.*", "shipments.*"},
        },
        MaxWait:     5 * time.Second,
        MaxPullWait: 500 * time.Millisecond,
        Consumer:    "my-consumer",
        CredsFile:   "/path/to/creds.json",
    }))

    // …publish/sub as usual…
    app.Run()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same for Azure Event Hub — just drop in the &lt;code&gt;eventhub&lt;/code&gt; client and configure.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Observability Built-In, Not Bolted-On
&lt;/h3&gt;

&lt;p&gt;Every message in GoFr carries a correlation ID for seamless tracing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DEBU [19:51:38] 82984da1ceb51b75d3e6295d525a2218 KAFKA     48610µs PUB  products {"productId":"1221","price":"Rs. 2000"}

INFO [19:51:38] 82984da1ceb51b75d3e6295d525a2218 201       56115µs POST /publish-product
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This automatic correlation, coupled with GoFr’s default metrics setup, empowers developers to gain deep insights into their application’s performance and easily pinpoint any issues in their event flow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Benefits: Why Teams Choose GoFr for Pub/Sub
&lt;/h2&gt;

&lt;p&gt;Implementing pub/sub with GoFr provides several tangible benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Accelerated development:&lt;/strong&gt; What might take days to set up properly can be accomplished in hours with GoFr.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduced cognitive load:&lt;/strong&gt; Developers can focus on business logic rather than messaging infrastructure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Consistent patterns:&lt;/strong&gt; The unified interface promotes consistent code across services.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Future-proofing:&lt;/strong&gt; The ability to switch messaging backends without code changes protects against vendor lock-in.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Production readiness:&lt;/strong&gt; Built-in observability features mean systems are ready for production monitoring from day one&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting Started with GoFr Pub/Sub
&lt;/h2&gt;

&lt;p&gt;Ready to simplify your event-driven architecture? Here’s how to get started:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Install GoFr: &lt;code&gt;go get gofr.dev&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set up your preferred message broker (Kafka, Google PubSub, MQTT, etc.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Configure your application with the appropriate environment variables.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Follow the publishing and subscribing patterns shown above&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For comprehensive documentation, visit &lt;a href="https://gofr.dev/docs/advanced-guide/using-publisher-subscriber" rel="noopener noreferrer"&gt;GoFr’s official pub/sub guide.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: The Future of Go Pub/Sub Is Simple
&lt;/h2&gt;

&lt;p&gt;GoFr isn’t just a framework — it’s a productivity hack. By abstracting pub/sub complexities, it lets you focus on what matters: &lt;strong&gt;writing business logic that delights users.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With just a handful of methods, you gain powerful broker-agnostic pub/sub, structured logs, metrics, and tracing — all while writing idiomatic Go. Give GoFr a spin today, share your feedback on GitHub, and help us continue making pub/sub in Go the easiest it’s ever been!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🚀 Ready to Stop Wrestling Pub/Sub?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Star ⭐ &lt;a href="https://gofr.dev/" rel="noopener noreferrer"&gt;GoFr&lt;/a&gt; on &lt;a href="https://github.com/gofr-dev/gofr" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; (It helps the project grow!)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Join fellow Developers&lt;/strong&gt; in our &lt;a href="https://discord.com/invite/yEz7UJBk" rel="noopener noreferrer"&gt;Discord&lt;/a&gt; community&lt;/li&gt;
&lt;li&gt;**Build your first event-driven API in 10 minutes **with our &lt;a href="https://gofr.dev/docs/advanced-guide/using-publisher-subscriber" rel="noopener noreferrer"&gt;Quickstart Guide&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Because in the world of real-time systems, the fastest developer wins. 🚀&lt;/p&gt;
&lt;/blockquote&gt;

</description>
    </item>
    <item>
      <title>Is Switching from Gin to GoFr in 2025 Worth It?</title>
      <dc:creator>Umang Mundhra</dc:creator>
      <pubDate>Tue, 08 Apr 2025 06:14:17 +0000</pubDate>
      <link>https://dev.to/umang01hash/is-switching-from-gin-to-gofr-in-2025-worth-it-5ff2</link>
      <guid>https://dev.to/umang01hash/is-switching-from-gin-to-gofr-in-2025-worth-it-5ff2</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5epvhlig68p3po9t0mlf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5epvhlig68p3po9t0mlf.png" alt="GoFr vs Gin in 2025" width="800" height="804"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;In 2025, a single microservice might rely on &lt;strong&gt;12+ dependencies&lt;/strong&gt; - from tracing tools to circuit breakers - just to meet production standards. Frameworks that force developers to write glue code are no longer assets; they're &lt;strong&gt;liabilities.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Gin served us well. For years, it was the go-to framework for lightweight APIs. But as microservices evolved, so did their demands: distributed tracing, multi-protocol communication, and polyglot data layers are now non-negotiable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GoFr&lt;/strong&gt; isn't just another framework - it's a productivity multiplier. Built for the cloud-native era, it replaces weeks of boilerplate with conventions that let developers focus on what matters: business logic, not glue code. Let's explore why 2025 is the year to make the switch.&lt;/p&gt;




&lt;h3&gt;
  
  
  Introduction: The Evolution of Microservices and the Need for Modern Tooling
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;"In 2014, when Gin was born, microservices were a budding concept. Fast forward to 2025: distributed systems dominate, and developers need frameworks that do more than just route requests."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The tech landscape has shifted dramatically. Cloud-native apps now demand observability, resilience, and polyglot data storage. Teams juggle Kubernetes clusters, event-driven architectures, and global user bases. While Gin served as a trusty sidekick for REST APIs, modern microservices require frameworks built for &lt;strong&gt;scale&lt;/strong&gt;, &lt;strong&gt;complexity&lt;/strong&gt;, and &lt;strong&gt;developer agility&lt;/strong&gt;.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Trends Driving Change:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Observability:&lt;/strong&gt; Debugging distributed systems without built-in tracing is like navigating a maze blindfolded. &lt;strong&gt;Observability isn't optional&lt;/strong&gt; - it's the oxygen for distributed systems.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resilience:&lt;/strong&gt; Resilience patterns (retries, timeouts, circuit breakers) are survival tools, not academic concepts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Database Diversity:&lt;/strong&gt; Teams mix SQL, NoSQL, and real-time brokers (Kafka, NATS) to meet dynamic needs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, the question arises: The question isn't &lt;em&gt;"Does Gin work?" - it's "Can your team afford to maintain a framework stuck in 2014?" Can older frameworks like Gin keep up, or is it time to embrace modern alternatives like GoFr?&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Gin's Legacy: A Worthy Warrior of Its Time
&lt;/h3&gt;

&lt;p&gt;Let's give credit where it's due. Gin revolutionized Go web development in the 2010s. Its minimalist design and blazing performance made it the &lt;strong&gt;gold standard&lt;/strong&gt; for APIs like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Simple REST API in Gin  
r := gin.Default()  

r.GET("/status", func(c *gin.Context) {  
    c.JSON(200, gin.H{"status": "ok"})  
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For monoliths or small services, Gin remains a solid choice. But microservices in 2025 aren't just APIs - they're &lt;strong&gt;distributed systems&lt;/strong&gt;. When your service needs to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trace a request across 5+ services,&lt;/li&gt;
&lt;li&gt;Retry failed gRPC calls to a flaky inventory database,&lt;/li&gt;
&lt;li&gt;Authenticate users via OAuth while streaming Kafka events,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…Gin's simplicity becomes a bottleneck. You're not just routing requests anymore - you're orchestrating ecosystems.&lt;/p&gt;




&lt;h3&gt;
  
  
  GoFr: The Opinionated Framework for Modern Microservices
&lt;/h3&gt;

&lt;p&gt;While Gin has earned its stripes over the years as a lightweight, high‑performance router, &lt;strong&gt;&lt;a href="https://gofr.dev/" rel="noopener noreferrer"&gt;GoFr&lt;/a&gt;&lt;/strong&gt; takes microservice development to the next level. Born out of the need for robust, cloud‑native solutions, GoFr is an opinionated framework designed specifically for the modern distributed systems era. It streamlines development by integrating essential features like built‑in observability, resilient inter‑service communication, extensive middleware support, and multi‑database connectivity - all under one roof.&lt;/p&gt;

&lt;p&gt;With features like auto‑injected trace IDs, unified error handling, and built‑in support for various data stores and messaging protocols, GoFr is more than just a framework - it's a full‑stack solution that empowers your team to build, deploy, and scale microservices with confidence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Result?&lt;/strong&gt; Teams ship features 2x faster, debug outages in minutes (not hours), and onboard new hires in days.&lt;/p&gt;

&lt;h4&gt;
  
  
  Features that make GoFr stand out:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Built-In Observability:&lt;/strong&gt; No more stitching together Prometheus, Jaeger, and Zap. GoFr auto-injects trace IDs, logs structured data, and exposes metrics out of the box. Out‑of‑the‑box logging, tracing, and metrics collection mean you won't have to juggle multiple third‑party tools. In today's distributed systems, having native observability is essential for rapid troubleshooting and maintaining service reliability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Robust Middleware and Authentication Support:&lt;/strong&gt; Security isn't an afterthought with GoFr. GoFr comes with built‑in support for a variety of authentication mechanisms - including Basic Auth, API-key, and OAuth - plus a flexible middleware system. This integrated approach ensures that security and request handling are consistent across your microservices, reducing both development overhead and potential integration issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multi‑Database Support &amp;amp; Data Migrations:&lt;/strong&gt; Modern applications often interact with multiple data sources. From SQL and MongoDB to Cassandra and Dgraph, GoFr's extensive database support means you can choose the right data store for your application's needs without worrying about compatibility. GoFr also have built‑in data migration tools to simplify schema updates, ensuring that your services can evolve without painful downtime.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unified Communication Channels:&lt;/strong&gt; Inter‑service communication is at the heart of microservices. GoFr's seamless inter-service HTTP support combined with features like integrated circuit breakers and failure retry mechanisms - provide a resilient, unified approach to managing network calls.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;WebSockets &amp;amp; Pub-Sub Communication Made Easy:&lt;/strong&gt; GoFr simplifies event-driven architectures by supporting brokers like Kafka, EventHub, Google Pub/Sub, NATS, and MQTT. GoFr also supports websocket communication similarly. Its unified handler signature makes integrating these technologies straightforward.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Active Community &amp;amp; Evolving Standards:&lt;/strong&gt; While Gin continues to enjoy popularity, GoFr is rapidly gaining momentum with active development, comprehensive documentation, and growing community support. This dynamic ecosystem means you benefit from regular &lt;br&gt;
updates, innovative features, and a network of developers committed to improving microservice development practices. &lt;em&gt;GoFr's active community ships critical patches 2x faster than legacy frameworks.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other important features like panic recovery and crash handling, graceful shutdown, health-checks , environment based configs etc. make it more featuristic. By integrating many commonly required features into a single framework, GoFr reduces the risk of inconsistencies and lowers the overall maintenance burden. With fewer external dependencies to manage, your deployment processes become simpler, and your codebase remains cleaner over time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh9s0sau25rxwhx2cxp4u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh9s0sau25rxwhx2cxp4u.png" alt="GoFr vs Gin Comparison" width="800" height="765"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;"Spend less time wiring libraries, more time shipping features.".&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Why 2025 Demands a Modern Framework Like GoFr
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Consolidation Over Fragmentation:
&lt;/h4&gt;

&lt;p&gt;Slash Tech Debt: Modern teams are drowning in fragmented tools. A typical Gin microservice requires: a logging library (Zap/Logrus), a tracing tool (OpenTelemetry), a circuit breaker (Hystrix/go-breaker), separate clients for databases (GORM, mongo-go-driver) and brokers (Sarama, NATS).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GoFr's Advantage:&lt;/strong&gt; Replace 5+ dependencies with a single framework. Less dependency management = fewer version conflicts, faster audits, and unified documentation.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Async APIs Are Now Table Stakes:
&lt;/h4&gt;

&lt;p&gt;RESTful endpoints alone can't handle real-time dashboards, WebSocket chats, or event-driven workflows. Gin's HTTP-only model forces developers to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bolt on third-party libraries for WebSockets&lt;/li&gt;
&lt;li&gt;Write custom logic for Kafka/Redis pub-sub&lt;/li&gt;
&lt;li&gt;Maintain separate handlers for async vs. sync&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;GoFr's Edge:&lt;/strong&gt; Natively unify HTTP, gRPC, and event-driven logic in one handler. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Handle HTTP requests AND Kafka events with the same function  
app.GET("/order", handleOrder)  

app.Subscribe("order-updates", handleOrder)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Onboarding Speed Wins Markets:
&lt;/h4&gt;

&lt;p&gt;With engineering talent at a premium, teams can't afford weeks of setup. Gin's minimalist design means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New hires spend days wiring logging, auth, and metrics.&lt;/li&gt;
&lt;li&gt;Every project reinvents the wheel for basic features.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;GoFr's Solution:&lt;/strong&gt; Conventions &amp;gt; Configuration.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Verdict: Gin's Limits vs. GoFr's Horizon
&lt;/h3&gt;

&lt;p&gt;In a rapidly evolving microservice landscape, productivity, consistency, and resilience are paramount. GoFr addresses these needs by offering an opinionated, modern framework that comes packed with integrated tools for observability, security, and inter‑service communication. With comprehensive database support, cloud‑native design, and an active community, GoFr positions itself as a future‑proof alternative to Gin for 2025 and beyond.&lt;/p&gt;

&lt;h4&gt;
  
  
  Why Switch?
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Eliminate Boilerplate:&lt;/strong&gt; GoFr's built-in tools replace weeks of wiring third-party libraries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embrace Modern Patterns:&lt;/strong&gt; Async communication and polyglot persistence are first-class citizens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scale Teams, Not Complexity:&lt;/strong&gt; Conventions reduce cognitive load for new hires.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;"Gin is a framework. GoFr is an ecosystem."&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Call to Action
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Try GoFr:&lt;/strong&gt; &lt;a href="https://github.com/gofr-dev/gofr" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Join Developers Community:&lt;/strong&gt; &lt;a href="https://discord.gg/yEz7UJBk" rel="noopener noreferrer"&gt;Discord&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do checkout&lt;/strong&gt; &lt;strong&gt;&lt;a href="https://gofr.dev/" rel="noopener noreferrer"&gt;GoFr&lt;/a&gt;&lt;/strong&gt; &lt;strong&gt;and it's&lt;/strong&gt; &lt;strong&gt;&lt;a href="https://github.com/gofr-dev/gofr" rel="noopener noreferrer"&gt;Github Repo&lt;/a&gt;&lt;/strong&gt; &lt;strong&gt;and support it by giving it a ⭐.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Final Word:&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;"Frameworks should solve today's problems, not yesterday's. In 2025, GoFr isn't just an alternative - it's the logical evolution for teams building cloud-native systems."&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>GoFr’s Plug-and-Play Model: Simplifying Database Interactions in Go</title>
      <dc:creator>Umang Mundhra</dc:creator>
      <pubDate>Thu, 12 Dec 2024 05:22:31 +0000</pubDate>
      <link>https://dev.to/umang01hash/gofrs-plug-and-play-model-simplifying-database-interactions-in-go-1i94</link>
      <guid>https://dev.to/umang01hash/gofrs-plug-and-play-model-simplifying-database-interactions-in-go-1i94</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9cuge8fa3sv03utykuze.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9cuge8fa3sv03utykuze.png" alt="GoFr's Plug and Play Model to support multiple database" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;In the ever-evolving landscape of software development, adaptability and modularity are essential for building scalable and maintainable applications. Databases play a critical role in modern software, and managing diverse databases efficiently is often a significant challenge. Many frameworks tightly couple database support, leading to issues with flexibility, maintenance, and performance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gofr.dev/" rel="noopener noreferrer"&gt;GoFr&lt;/a&gt; is an open-source micro-service framework written in Go. It is a lightweight and extensible framework for Go that offers a unique solution to this problem with its plug-and-play database model.&lt;/p&gt;

&lt;p&gt;This article delves into how GoFr supports multiple databases seamlessly, enabling developers to integrate their database of choice without altering the core framework. Whether you're working with MongoDB, MySQL, Clickhouse, or any other database, GoFr's approach ensures that you can effortlessly switch, extend, or maintain your database integration without adding unnecessary complexity. Let's explore how this model works and why it's a game-changer for Go developers&lt;/p&gt;




&lt;h2&gt;
  
  
  Challenges with Tightly Coupled Databases
&lt;/h2&gt;

&lt;p&gt;In frameworks where database integrations are tightly coupled, several challenges can arise, making them less flexible and harder to maintain. Below are the key issues developers often face with such an approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Increased Build Size:&lt;/strong&gt; One of the primary issues is the build size. To keep a framework lightweight, it's essential to include only the necessary dependencies in the &lt;code&gt;go.mod&lt;/code&gt; file. When a framework tightly couples support for multiple databases, it often includes all relevant dependencies in the &lt;code&gt;go.mod&lt;/code&gt; file. This bloats the build size, even if only one or two databases are used in an application. The additional dependencies not only increase the binary size but also make dependency management more complex.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduced Modularity and Flexibility:&lt;/strong&gt; Tightly coupled databases reduce flexibility. If a developer wants to switch to a different database or use a custom implementation of a particular database, they must go through the tedious process of refactoring the entire codebase to accommodate the new database. This reduces the framework's adaptability and makes it less appealing for developers who need to work with multiple databases.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Frequent Framework Updates:&lt;/strong&gt; Any changes to the database logic require a new release of the entire framework, even if there are no significant changes in the core code. This creates delays and forces users to update their framework version even if the changes are irrelevant to their application making the framework less agile.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lack of Developer Control:&lt;/strong&gt; Tightly coupled integrations limit the developers' control over the configuration and customization of their database connections. Developers are forced to adapt their applications to the framework's design rather than having the freedom to implement solutions tailored to their specific needs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lastly, tightly coupled databases hinder the separation of concerns. The core framework logic gets intertwined with database-specific code, making it harder to debug, maintain, and extend.&lt;/p&gt;




&lt;h2&gt;
  
  
  GoFr's Plug and Play Approach
&lt;/h2&gt;

&lt;p&gt;To overcome the challenges of tightly coupled databases, GoFr introduces a &lt;strong&gt;plug-and-play model&lt;/strong&gt; that provides seamless integration with multiple databases. This approach leverages Go's powerful interface abstraction to decouple database logic from the core framework, ensuring flexibility, maintainability, and scalability.&lt;/p&gt;

&lt;p&gt;**Using Go's Interfaces: **At the heart of this model are Go's interfaces. By defining an interface with the necessary methods that a database client should implement, GoFr provides a blueprint for integrating any database. This abstraction allows developers to implement their own database logic while adhering to a consistent structure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connector Functions:&lt;/strong&gt; To facilitate the integration, GoFr provides connector functions that allow users to initialize their database client and inject it into the application. These functions handle the setup and configuration of the database client, ensuring that it conforms to the interface requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;For example, the interface for MongoDB might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// MongoProvider is an interface that extends Mongo with additional methods for logging, metrics, and connection management.&lt;/span&gt;
&lt;span class="c"&gt;// Which is used for initializing datasource.&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;MongoProvider&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="n"&gt;Mongo&lt;/span&gt;

 &lt;span class="n"&gt;provider&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Mongo is an interface representing a MongoDB database client with common CRUD operations.&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Mongo&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="c"&gt;// Find executes a query to find documents in a collection based on a filter and stores the results&lt;/span&gt;
 &lt;span class="c"&gt;// into the provided results interface.&lt;/span&gt;
 &lt;span class="n"&gt;Find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;

 &lt;span class="c"&gt;// FindOne executes a query to find a single document in a collection based on a filter and stores the result&lt;/span&gt;
 &lt;span class="c"&gt;// into the provided result interface.&lt;/span&gt;
 &lt;span class="n"&gt;FindOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;

 &lt;span class="c"&gt;// InsertOne inserts a single document into a collection.&lt;/span&gt;
 &lt;span class="c"&gt;// It returns the identifier of the inserted document and an error, if any.&lt;/span&gt;
 &lt;span class="n"&gt;InsertOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

 &lt;span class="c"&gt;// InsertMany inserts multiple documents into a collection.&lt;/span&gt;
 &lt;span class="c"&gt;// It returns the identifiers of the inserted documents and an error, if any.&lt;/span&gt;
 &lt;span class="n"&gt;InsertMany&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;documents&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

 &lt;span class="c"&gt;// DeleteOne deletes a single document from a collection based on a filter.&lt;/span&gt;
 &lt;span class="c"&gt;// It returns the number of documents deleted and an error, if any.&lt;/span&gt;
 &lt;span class="n"&gt;DeleteOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

 &lt;span class="c"&gt;// DeleteMany deletes multiple documents from a collection based on a filter.&lt;/span&gt;
 &lt;span class="c"&gt;// It returns the number of documents deleted and an error, if any.&lt;/span&gt;
 &lt;span class="n"&gt;DeleteMany&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

 &lt;span class="c"&gt;// UpdateByID updates a document in a collection by its ID.&lt;/span&gt;
 &lt;span class="c"&gt;// It returns the number of documents updated and an error if any.&lt;/span&gt;
 &lt;span class="n"&gt;UpdateByID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

 &lt;span class="c"&gt;// UpdateOne updates a single document in a collection based on a filter.&lt;/span&gt;
 &lt;span class="c"&gt;// It returns an error if any.&lt;/span&gt;
 &lt;span class="n"&gt;UpdateOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;

 &lt;span class="c"&gt;// UpdateMany updates multiple documents in a collection based on a filter.&lt;/span&gt;
 &lt;span class="c"&gt;// It returns the number of documents updated and an error if any.&lt;/span&gt;
 &lt;span class="n"&gt;UpdateMany&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

 &lt;span class="c"&gt;// CountDocuments counts the number of documents in a collection based on a filter.&lt;/span&gt;
 &lt;span class="c"&gt;// It returns the count and an error if any.&lt;/span&gt;
 &lt;span class="n"&gt;CountDocuments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

 &lt;span class="c"&gt;// Drop an entire collection from the database.&lt;/span&gt;
 &lt;span class="c"&gt;// It returns an error if any.&lt;/span&gt;
 &lt;span class="n"&gt;Drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;

 &lt;span class="c"&gt;// CreateCollection creates a new collection with specified name and default options.&lt;/span&gt;
 &lt;span class="n"&gt;CreateCollection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;

 &lt;span class="c"&gt;// StartSession starts a session and provide methods to run commands in a transaction.&lt;/span&gt;
 &lt;span class="n"&gt;StartSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

 &lt;span class="n"&gt;HealthChecker&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="c"&gt;// UseLogger sets the logger for the Cassandra client.&lt;/span&gt;
 &lt;span class="n"&gt;UseLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

 &lt;span class="c"&gt;// UseMetrics sets the metrics for the Cassandra client.&lt;/span&gt;
 &lt;span class="n"&gt;UseMetrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metrics&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

 &lt;span class="c"&gt;// UseTracer sets the tracer for the Cassandra client.&lt;/span&gt;
 &lt;span class="n"&gt;UseTracer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tracer&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

 &lt;span class="c"&gt;// Connect establishes a connection to Cassandra and registers metrics using the provided configuration when the client was Created.&lt;/span&gt;
 &lt;span class="n"&gt;Connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the &lt;code&gt;MongoProvider&lt;/code&gt; interface embeds the &lt;code&gt;Mongo&lt;/code&gt; and &lt;code&gt;provider&lt;/code&gt; interfaces. While the &lt;code&gt;Mongo&lt;/code&gt; interface contains all the necessary methods that need to be implemented by the client for database operations, the &lt;code&gt;provider&lt;/code&gt; interface contains methods needed by the framework to successfully connect to the database and use logging, metrics, and traces for observability.&lt;/p&gt;

&lt;p&gt;This is the connector function for Mongo that accepts the implementation of &lt;code&gt;MongoProvider&lt;/code&gt; interfaces defined by GoFr. This function configures the MongoDB client with logging, metrics, and tracing capabilities, and establishes the connection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// AddMongo sets the MongoDB datasource in the app's container.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;App&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;AddMongo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MongoProvider&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseMetrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Metrics&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseTracer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;otel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetTracerProvider&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tracer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"gofr-mongo"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mongo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this is how the user will finally use it in their application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gofr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mongo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mongo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;URI&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"mongodb://localhost:27017"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ConnectionTimeout&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddMongo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/mongo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Insert&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/mongo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Advantages of GoFr's plug &amp;amp; play model:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reduced Build Size:&lt;/strong&gt; By avoiding tightly coupling databases with the core framework, GoFr keeps the framework lightweight. Only the necessary dependencies are included in the go.mod file, resulting in smaller build sizes and improved performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplified Maintenance:&lt;/strong&gt; Maintaining database integrations becomes straightforward with GoFr's plug-and-play model. Since database logic is decoupled from the core framework, updates or changes to database connectors can be made independently, without requiring a new release of the entire framework. This reduces the maintenance burden and accelerates release cycles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility and Modularity:&lt;/strong&gt; The plug-and-play model in GoFr allows developers to easily integrate, switch, or extend their database of choice without altering the core framework. This flexibility ensures that developers are not locked into a single database solution and can adapt to evolving requirements with minimal effort.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved Observability:&lt;/strong&gt; GoFr's connector functions are designed to incorporate logging, metrics, and tracing capabilities for each database integration. This built-in observability ensures that developers have the necessary tools to monitor and troubleshoot their database interactions effectively, leading to more robust and reliable applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customization and Extensibility:&lt;/strong&gt; Developers can easily implement their own database logic by adhering to the defined interfaces in GoFr. This customization allows for tailored database solutions that meet specific project requirements. Additionally, the ability to extend the framework with new databases enhances its versatility and adaptability.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;GoFr's innovative plug-and-play model for database integration offers a powerful solution to the challenges posed by tightly coupled databases. By leveraging Go's interface abstraction, GoFr ensures flexibility, maintainability, and scalability, making it easier for developers to work with multiple databases without altering the core framework. This approach not only keeps the framework lightweight and modular but also simplifies maintenance and enhances overall application performance.&lt;/p&gt;

&lt;p&gt;We invite you to try GoFr in your next project. Experience how its plug-and-play database model can simplify your development process. For more detailed information and examples, check out the following resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://gofr.dev/docs/advanced-guide/injecting-databases-drivers" rel="noopener noreferrer"&gt;GoFr's Documentation on Injecting Databases&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/gofr-dev/gofr" rel="noopener noreferrer"&gt;GoFr's GitHub Repository&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Try out GoFr, and if you find it helpful, don't forget to give it a ⭐ on GitHub. Your feedback and contributions are invaluable to the continued improvement of this framework.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Ultimate Golang Framework for Microservices: GoFr</title>
      <dc:creator>Umang Mundhra</dc:creator>
      <pubDate>Wed, 10 Jul 2024 07:18:26 +0000</pubDate>
      <link>https://dev.to/umang01hash/the-ultimate-golang-framework-for-microservices-gofr-56bj</link>
      <guid>https://dev.to/umang01hash/the-ultimate-golang-framework-for-microservices-gofr-56bj</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fed2qgnqmsorxdul1b14d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fed2qgnqmsorxdul1b14d.png" alt="GoFr: The Ultimate Golang Framework for Microservices"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go is a multiparadigm, statically typed, and compiled programming language designed by Google. Many developers have embraced Go because of its garbage collection, memory safety, and structural typing system. Go web frameworks were created to ease Go web development processes without worrying about setups and focusing more on the functionalities of a project. While building small applications, frameworks may not be necessary, but for production-level software, they are crucial. Frameworks provide additional functionalities and services that can be used by other developers who want to add similar functionalities to their software rather than writing the full-fledged software by themselves.&lt;/p&gt;

&lt;p&gt;Choosing the right framework for your needs can enable faster development cycles and easier maintenance down the road. In this article we will talk about &lt;a href="https://gofr.dev/" rel="noopener noreferrer"&gt;GoFr&lt;/a&gt;, an opinionated Golang framework for accelerated microservice development. And we will discover why it is your ultimate choice when building microservices in Go!&lt;/p&gt;




&lt;h2&gt;
  
  
  GoFr &amp;amp; It's rich set of features:
&lt;/h2&gt;

&lt;p&gt;What really makes a framework good or bad is the ease of development it provides for its user along with the range of features it offers so the user can purely focus on business logic implementation. GoFr has been built to help developers write fast, scalable and efficient API's. The framework offers a rich set of features that help developers in writing production grade microservices with ease. Let's explore some of these features:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Efficient Configuration Management
&lt;/h3&gt;

&lt;p&gt;Environment variables are the best way to set configuration values for your software application as they can be defined at system-level, independently of the software. This is one of the principles of the &lt;a href="https://12factor.net/config" rel="noopener noreferrer"&gt;Twelve-Factor App&lt;/a&gt; methodology and enables applications to be built with portability.&lt;/p&gt;

&lt;p&gt;GoFr has some predefined environment variables for various purposes like changing log levels, connecting to databases, setting application name and version, setting http ports etc. The user just needs to set these in an .env file inside the configs directory of the application and GoFr automatically reads the values from that.&lt;/p&gt;

&lt;p&gt;Here is the full &lt;a href="https://gofr.dev/docs/references/configs" rel="noopener noreferrer"&gt;list of environment variables supported by GoFr&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Seamless Database Interactions
&lt;/h3&gt;

&lt;p&gt;Managing database connections and interactions can become hectic, especially when working with multiple databases. GoFr handles database connections seamlessly using configuration variables. Not only does it manage the connections, but it also provides direct access to database objects using the GoFr context within handlers. This approach simplifies working with multiple databases. GoFr currently supports all SQL Dialects, Redis, MongoDB, Cassandra and ClickHouse databases.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Example of using MySQL and Redis DB inside the handler.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;DBHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gofr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
 &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c"&gt;// querying a SQL db&lt;/span&gt;&lt;br&gt;
&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SQL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryRowContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"select 2+2"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;datasource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrorDB&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Err&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"error from sql db"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;br&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c"&gt;// retrieving value from Redis&lt;/span&gt;&lt;br&gt;
 &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;datasource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrorDB&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Err&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"error from redis db"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;br&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  

&lt;ol&gt;
&lt;li&gt;Implementing Publisher-Subscriber architecture with ease:
&lt;/li&gt;
&lt;/ol&gt;
&lt;/h3&gt;


&lt;p&gt;GoFr simplifies Pub/Sub by offering built-in support for popular clients like Kafka, Google Pub/Sub, and MQTT. This eliminates the need for manual configuration or library management, allowing you to focus on your event-driven architecture. Publishing and subscribing to events are streamlined using the GoFr context. Publishing events can be done inside the handler using the context, and to subscribe to an event, you just need to use GoFr's Subscribe handler. This approach promotes clean code and reduces boilerplate compared to implementing the Pub/Sub pattern from scratch.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Example of using Publisher and Subscriber in a GoFr application:&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;br&gt;
 &lt;span class="s"&gt;"encoding/json"&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="s"&gt;"gofr.dev/pkg/gofr"&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
 &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gofr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/publish-product"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c"&gt;// subscribing to products topic&lt;/span&gt;&lt;br&gt;
 &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"products"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gofr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;productInfo&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
   &lt;span class="n"&gt;ProductId&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;&lt;code&gt;json:"productId"&lt;/code&gt;&lt;/span&gt;&lt;br&gt;
   &lt;span class="n"&gt;Price&lt;/span&gt;     &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;&lt;code&gt;json:"price"&lt;/code&gt;&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;productInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
   &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Received product "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;productInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;br&gt;
 &lt;span class="p"&gt;})&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gofr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
 &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;productInfo&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;ProductId&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;&lt;code&gt;json:"productId"&lt;/code&gt;&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;Price&lt;/span&gt;     &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;&lt;code&gt;json:"price"&lt;/code&gt;&lt;/span&gt;&lt;br&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="n"&gt;productInfo&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c"&gt;// binding the request data to productInfo struct&lt;/span&gt;&lt;br&gt;
 &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;br&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c"&gt;// publishing message to producst topic using gofr context&lt;/span&gt;&lt;br&gt;
 &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetPublisher&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"products"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;br&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Published"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  

&lt;ol&gt;
&lt;li&gt;Out of the Box Observability:
&lt;/li&gt;
&lt;/ol&gt;
&lt;/h3&gt;


&lt;p&gt;Effective monitoring is crucial for maintaining high-performing microservices. GoFr takes the burden off your shoulders by providing built-in observability features. This eliminates the need for manual configuration of tracing, metrics, and logging libraries.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Detailed Logging:&lt;/strong&gt; GoFr offers structured logging with various log levels (INFO, DEBUG, WARN, ERROR, FATAL) to capture application events at different granularities. This empowers you to analyze application flow, identify potential issues, and streamline debugging.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Actionable Metrics:&lt;/strong&gt; GoFr automatically collects and exposes application metrics, allowing you to monitor key performance indicators. With metrics readily available, you can quickly identify bottlenecks and optimize application performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Distributed Tracing:&lt;/strong&gt; GoFr integrates with popular tracing backends like &lt;code&gt;Zipkin&lt;/code&gt; and &lt;code&gt;Jaeger&lt;/code&gt;. Distributed tracing allows you to visualize the entire request lifecycle across your microservices, making it easier to pinpoint the root cause of issues within complex systems.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These observability features help users gain detailed insights into the application's flow and performance, identify and resolve bottlenecks, and ensure smooth operation.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Effortless Interservice HTTP Communication:
&lt;/h3&gt;

&lt;p&gt;In a microservices architecture, efficient and reliable communication between services is crucial. GoFr simplifies this process by providing a dedicated mechanism to initialize and manage interservice HTTP communication. You can easily register downstream services at the application level using the &lt;code&gt;AddHTTPService&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configurational Options for HTTP Services:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;GoFr offers a variety of configuration options to enhance interservice communication:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Authentication:&lt;/strong&gt; Supports APIKeyConfig, BasicAuthConfig, and OAuthConfig for secure authentication.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Default Headers:&lt;/strong&gt; Allows setting default headers for all downstream HTTP service requests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Circuit Breaker:&lt;/strong&gt; Enhance service resilience with built-in circuit breaker functionality. GoFr allows you to configure thresholds and intervals to gracefully handle failures and prevent cascading outages.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Health Checks:&lt;/strong&gt; Proactively monitor the health of your downstream services using GoFr's health check configuration. Define a health endpoint for each service, and GoFr will automatically verify their availability, allowing for early detection of potential issues.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These features ensure that interservice communication is secure, reliable, and easily manageable.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Example of connecting to a HTTP Service and sending a GET request:&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
 &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gofr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddHTTPService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cat-facts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&lt;a href="https://catfact.ninja" rel="noopener noreferrer"&gt;https://catfact.ninja&lt;/a&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
  &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CircuitBreakerConfig&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
   &lt;span class="n"&gt;Threshold&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
   &lt;span class="n"&gt;Interval&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;&lt;br&gt;
  &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HealthConfig&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
   &lt;span class="n"&gt;HealthEndpoint&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"breeds"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;&lt;br&gt;
 &lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/fact"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gofr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
 &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;Fact&lt;/span&gt;   &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;&lt;code&gt;json:"fact"&lt;/code&gt;&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;    &lt;span class="s"&gt;&lt;code&gt;json:"length"&lt;/code&gt;&lt;/span&gt;&lt;br&gt;
 &lt;span class="p"&gt;}{}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;catFacts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetHTTPService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cat-facts"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;catFacts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"fact"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}{&lt;/span&gt;&lt;br&gt;
  &lt;span class="s"&gt;"max_length"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
 &lt;span class="p"&gt;})&lt;/span&gt;&lt;br&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;br&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
 &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;br&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  

&lt;ol&gt;
&lt;li&gt;Flexible Middleware Support for Enhanced Control:
&lt;/li&gt;
&lt;/ol&gt;
&lt;/h3&gt;


&lt;p&gt;Middleware allows you intercepting and manipulating HTTP requests and responses flowing through your application's router. Middlewares can perform tasks such as authentication, authorization, caching etc. before or after the request reaches your application's handler.&lt;/p&gt;

&lt;p&gt;GoFr empowers developers with middleware support, allowing for request/response manipulation and custom logic injection. This provides a powerful mechanism to implement cross-cutting concerns like authentication, authorization, and caching in a modular and reusable way. Middleware functions are registered using the &lt;code&gt;UseMiddleware&lt;/code&gt; method on your GoFr application instance. &lt;/p&gt;

&lt;p&gt;Additionally, GoFr includes built-in CORS (Cross-Origin Resource Sharing) middleware to handle CORS-related headers.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Example of adding a custom middleware to GoFr application:&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;br&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;span class="n"&amp;gt;gofrHTTP&amp;lt;/span&amp;gt; &amp;lt;span class="s"&amp;gt;"gofr.dev/pkg/gofr/http"&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c"&gt;// Define your custom middleware function&lt;/span&gt;&lt;br&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;customMiddleware&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;gofrHTTP&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Middleware&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inner&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandlerFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
            &lt;span class="c"&gt;// Your custom logic here&lt;/span&gt;&lt;br&gt;
            &lt;span class="c"&gt;// For example, logging, authentication, etc.&lt;/span&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        &amp;lt;span class="c"&amp;gt;// Call the next handler in the chain&amp;lt;/span&amp;gt;
        &amp;lt;span class="n"&amp;gt;inner&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;ServeHTTP&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;(&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;w&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;,&amp;lt;/span&amp;gt; &amp;lt;span class="n"&amp;gt;r&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;)&amp;lt;/span&amp;gt;
    &amp;lt;span class="p"&amp;gt;})&amp;lt;/span&amp;gt;
&amp;lt;span class="p"&amp;gt;}&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
    &lt;span class="c"&gt;// Create a new instance of your GoFr application&lt;/span&gt;&lt;br&gt;
    &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gofr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;span class="c"&amp;gt;// Add your custom middleware to the application&amp;lt;/span&amp;gt;
&amp;lt;span class="n"&amp;gt;app&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;UseMiddleware&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;(&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;customMiddleware&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;())&amp;lt;/span&amp;gt;

&amp;lt;span class="c"&amp;gt;// Define your application routes and handlers&amp;lt;/span&amp;gt;
&amp;lt;span class="c"&amp;gt;// ...&amp;lt;/span&amp;gt;

&amp;lt;span class="c"&amp;gt;// Run your GoFr application&amp;lt;/span&amp;gt;
&amp;lt;span class="n"&amp;gt;app&amp;lt;/span&amp;gt;&amp;lt;span class="o"&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class="n"&amp;gt;Run&amp;lt;/span&amp;gt;&amp;lt;span class="p"&amp;gt;()&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  

&lt;ol&gt;
&lt;li&gt;Integrated Authentication Mechanisms:
&lt;/li&gt;
&lt;/ol&gt;
&lt;/h3&gt;


&lt;p&gt;Securing your microservices with robust authentication is crucial. GoFr streamlines this process by providing built-in support for various industry-standard authentication mechanisms. This empowers you to choose the approach that best suits your application's needs without writing complex authentication logic from scratch.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Basic Auth:&lt;/strong&gt; Basic auth is the simplest way to authenticate your APIs. It's built on &lt;a href="https://datatracker.ietf.org/doc/html/rfc7617" rel="noopener noreferrer"&gt;HTTP protocol authentication&lt;/a&gt; scheme. It involves sending the prefix Basic trailed by the Base64-encoded &lt;code&gt;&amp;lt;username&amp;gt;:&amp;lt;password&amp;gt;&lt;/code&gt; within the standard &lt;code&gt;Authorization&lt;/code&gt; header. GoFr offers two ways to implement basic authentication i.e. using pre-defined credentials as well as defining a custom validation function.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;API Keys Auth:&lt;/strong&gt; API Key Authentication is an HTTP authentication scheme where a unique API key is included in the request header for validation against a store of authorized keys. GoFr offers two ways to implement API Keys authentication i.e. Framework Default Validation as well as defining a Custom Validation Function.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;OAuth 2.0:&lt;/strong&gt; &lt;a href="https://www.rfc-editor.org/rfc/rfc6749" rel="noopener noreferrer"&gt;OAuth&lt;/a&gt; 2.0 is the industry-standard protocol for authorization. It focuses on client developer simplicity while providing specific authorization flows for web applications, desktop applications, mobile phones, and living room devices. It involves sending the prefix &lt;code&gt;Bearer&lt;/code&gt; trailed by the encoded token within the standard &lt;code&gt;Authorization&lt;/code&gt; header. GoFr supports authenticating tokens encoded by algorithm &lt;code&gt;RS256/384/512&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Refer to the &lt;a href="https://gofr.dev/docs/advanced-guide/http-authentication" rel="noopener noreferrer"&gt;GoFr's Authentication Documentation&lt;/a&gt; to see the examples of how to use these auth mechanisms and know more about it.&lt;/p&gt;

&lt;h3&gt;
  
  
  ---
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Automatic Swagger UI Rendering:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Providing clear and interactive API documentation is essential for user adoption and efficient development workflows. API specifications can be written in YAML or JSON. The format is easy to learn and readable to both humans and machines. The complete OpenAPI Specification can be found on the official &lt;a href="https://swagger.io/" rel="noopener noreferrer"&gt;Swagger website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;GoFr supports automatic rendering of OpenAPI (also known as Swagger) documentation. This feature allows you to easily provide interactive API documentation for your users. To allow GoFr to render your OpenAPI documentation, simply place your &lt;code&gt;openapi.json&lt;/code&gt; file inside the &lt;code&gt;static&lt;/code&gt; directory of your project. GoFr will automatically render the Swagger documentation at the &lt;code&gt;/.well-known/swagger&lt;/code&gt; endpoint.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Throughout this article, we've explored the rich features of GoFr, an opinionated Golang framework specifically designed to accelerate microservice development. We've seen how GoFr simplifies common tasks like configuration management, database interactions, Pub/Sub integration, automatic observability, interservice communication, middleware usage, and authentication. Additionally, GoFr offers built-in support for data migrations, web sockets, cron jobs, and remote log level changes, further streamlining your development process.&lt;/p&gt;

&lt;p&gt;We benchmarked GoFr against other popular Go frameworks such as Gin, Chi, Echo, and Fiber, and found that GoFr performed optimally, even with its extensive feature set. This means you can leverage all its powerful functionalities without compromising on performance.&lt;/p&gt;

&lt;p&gt;We encourage you to explore GoFr for yourself. The framework's comprehensive documentation, tutorials, and active community are valuable resources to guide you on your journey. With GoFr, you can focus on building robust, scalable, and efficiently managed microservices, freeing you to dedicate more time to your application's core functionalities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get started with GoFr today!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here are some helpful resources:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;GoFr Website: &lt;a href="https://gofr.dev" rel="noopener noreferrer"&gt;https://gofr.dev&lt;/a&gt;&lt;br&gt;
GoFr GitHub Repository: &lt;a href="https://github.com/gofr-dev/gofr" rel="noopener noreferrer"&gt;https://github.com/gofr-dev/gofr&lt;/a&gt;&lt;br&gt;
GoFr Discord Server: &lt;a href="https://discord.gg/zyJkVhps" rel="noopener noreferrer"&gt;https://discord.gg/zyJkVhps&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>go</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Understanding and Utilizing Context in Go and GoFr</title>
      <dc:creator>Umang Mundhra</dc:creator>
      <pubDate>Wed, 03 Jul 2024 06:52:46 +0000</pubDate>
      <link>https://dev.to/umang01hash/understanding-and-utilizing-context-in-go-and-gofr-4fld</link>
      <guid>https://dev.to/umang01hash/understanding-and-utilizing-context-in-go-and-gofr-4fld</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz2sywrnwl7hyenszde0n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz2sywrnwl7hyenszde0n.png" alt="Context in go" width="800" height="613"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Context?
&lt;/h2&gt;

&lt;p&gt;In Go, the context package is a fundamental tool designed to manage and share request-scoped data, cancellation signals, and timeouts or deadlines across different layers of an application.&lt;br&gt;
The &lt;code&gt;context.Context&lt;/code&gt; type provides a way to carry deadlines, cancellation signals, and other request-scoped values in a chainable, hierarchical manner. It is designed to be immutable, which means that each new derived context carries the properties of its parent context while adding new values or behaviours.&lt;br&gt;
Imagine a context as a special carrier bag that holds all the necessary information and instructions for a specific task. This bag can be passed from function to function, ensuring everyone involved has the same context (information) and can act accordingly. It can also contain a self-destruct button (cancellation signal) to stop the operation if needed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why do we need Context?
&lt;/h2&gt;

&lt;p&gt;Before the introduction of Context in Go, managing request-scoped data and cancellation signals was a cumbersome task. Developers had to rely on ad-hoc solutions, such as passing around custom structs or using global variables, to share data and signals between functions and goroutines. However, these approaches were error-prone, hard to maintain, and often led to tight coupling between components.&lt;br&gt;
The need for a Context arises from the fact that many operations in a program are asynchronous, concurrent, or dependent on external systems. In such cases, it's essential to have a way to propagate cancellation signals, deadlines, and request-scoped data across multiple functions and goroutines.&lt;/p&gt;

&lt;p&gt;Let's consider a few scenarios to illustrate the need for a Context:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Restaurant Analogy
&lt;/h3&gt;

&lt;p&gt;Imagine you're the person taking orders in a bustling restaurant. When an order arrives, you assign it to one of your skilled cooks. But what if the customer suddenly decides to leave? Without hesitation, you'd inform the chef to stop processing that order to avoid wasting ingredients. This scenario mirrors how context works in Go.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cancellation Propagation: In the restaurant analogy, the customer leaving corresponds to a cancellation signal. Similarly, in Go, context allows graceful propagation of cancellation signals. When a parent operation (e.g., an HTTP request handler) cancels, all related child operations (e.g., database queries or API calls) terminate promptly. This prevents resource leaks and ensures efficient cleanup.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Handling Slow APIs and Timeouts
&lt;/h3&gt;

&lt;p&gt;Suppose your application makes web requests to external APIs or runs system commands. In production-grade systems, it's essential to set timeouts. Here's why:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;API Dependency: Imagine your service relies on an external API. If that API is running slowly or becomes unresponsive, you wouldn't want your system to back up with pending requests. A timeout ensures that if the API call exceeds a specified duration, the associated context cancels, allowing your application to gracefully handle the situation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Performance Degradation: Without timeouts, slow external &lt;br&gt;
dependencies can lead to a cascading effect. Backlogged requests increase load, degrade performance, and impact overall system responsiveness. By using context with deadlines, you can prevent this issue.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;







&lt;h2&gt;
  
  
  Uses of Context:
&lt;/h2&gt;

&lt;p&gt;The context package in Go is versatile and used in various scenarios to manage request-scoped data, cancellation signals, and timeouts.&lt;/p&gt;

&lt;p&gt;Here are some common real-world use cases:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Propagating Trace IDs Across Distributed Services&lt;/strong&gt;&lt;br&gt;
In a microservices architecture, tracing requests across different services is crucial for monitoring and debugging. The context package allows you to propagate trace IDs and other metadata across service boundaries, ensuring consistent logging and tracing information throughout the request's lifecycle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Passing Authentication Tokens&lt;/strong&gt;&lt;br&gt;
In many applications, authentication tokens or user information needs to be passed through different layers of the application. The context package provides a clean way to handle this, ensuring that authentication information is available where needed without polluting function signatures with additional parameters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. WebSocket and Streaming APIs&lt;/strong&gt;&lt;br&gt;
In WebSocket and streaming APIs, Context is used to manage the lifetime of the connection and propagate request-scoped data, such as the user ID and session information. This allows you to implement features like authentication, rate limiting, and session management efficiently.&lt;/p&gt;




&lt;h2&gt;
  
  
  Different Types of Context in Go:
&lt;/h2&gt;

&lt;p&gt;The context package in Go offers several ways to create and manipulate context objects. Here's a breakdown of the commonly used types:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Background Context/TODO Context
&lt;/h3&gt;

&lt;p&gt;This is the most basic context and serves as an empty starting point. It doesn't carry any cancellation signal or deadline. Use it when no specific context is required.&lt;br&gt;
The only time TODO is used instead of Background is when the implementation is unclear, or the context is not yet known.&lt;/p&gt;

&lt;p&gt;Typically used in main functions, initialization, and tests.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ctx := context.Background()&lt;br&gt;
ctx2 := context.TODO()&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. context.WithCancel
&lt;/h3&gt;

&lt;p&gt;Creates a new context derived from a parent context., WithCancel method returns a copy of the parent context along with a cancel function; invoking the cancel function releases resources connected with the context and should be called as soon as operations in the Context type are finally completed.&lt;/p&gt;

&lt;p&gt;Used to cancel operations in a goroutine when certain conditions are met.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;parentCtx := context.Background()&lt;br&gt;
ctx, cancel := context.WithCancel(parentCtx)&lt;br&gt;
defer cancel() // Clean up resources&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. context.WithDeadline
&lt;/h3&gt;

&lt;p&gt;Similar to setting a deadline for oneself, you can set a deadline for context. Go will automatically cancel the context for you if the time limit you specified for it to finish is reached. It creates a new context derived from a parent context with a specific deadline.&lt;/p&gt;

&lt;p&gt;Useful when you have a specific deadline for completing an operation.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;parentCtx := context.Background()&lt;br&gt;
deadline := time.Now().Add(10 * time.Second)&lt;br&gt;
ctx, cancel := context.WithDeadline(parentCtx, deadline)&lt;br&gt;
defer cancel() // Clean up resources&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. context.WithValue
&lt;/h3&gt;

&lt;p&gt;Creates a new context derived from a parent context with an associated key-value pair. This allows you to store and retrieve request-specific information within the context. WithValue accepts a parent context and returns a context copy. As a result, rather than overwriting the value, it creates a new duplicate with a new key-value pair.&lt;/p&gt;

&lt;p&gt;Useful for passing request-scoped data through the context, such as authentication tokens or trace IDs.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;parentCtx := context.Background()&lt;br&gt;
userIDKey := "auth-token"&lt;br&gt;
ctx := context.WithValue(parentCtx, userIDKey, "abc123")&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. context.WithTimeout
&lt;/h3&gt;

&lt;p&gt;Creates a context with an associated timeout. The context cancels automatically after the specified duration. WithTimeout, allows a program to continue where it might otherwise hang, giving the end user a better experience. It accepts a brief period as a parameter, along with the parent context, and terminates the function if it runs beyond the timeout period.&lt;/p&gt;

&lt;p&gt;Useful for setting deadlines on operations.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;parentCtx := context.Background()&lt;br&gt;
ctx, cancel := context.WithTimeout(parentCtx, 5*time.Second)&lt;br&gt;
defer cancel() // Clean up resources&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj45t892ziiboov9dnhxk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj45t892ziiboov9dnhxk.png" alt="Different types of context in Golang" width="800" height="334"&gt;&lt;/a&gt;&lt;/p&gt;







&lt;h2&gt;
  
  
  GoFr Context: Supercharged Context for Go Applications
&lt;/h2&gt;

&lt;p&gt;Now that we've explored the power of context in Go, let's delve into how GoFr takes it a step further with GoFr Context.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gofr.dev"&gt;GoFr&lt;/a&gt; is an opinionated microservices development framework built on top of Go. It aims to streamline the development process by providing a structured approach to building robust and scalable microservices.&lt;/p&gt;

&lt;p&gt;GoFr Context beautifully extends the functionality of the standard Go context package by creating a wrapper around it. This wrapper provides a rich set of pre-configured dependencies directly accessible through the context object. This fully loaded context enables developers to seamlessly access logging, database connections, underlying services, traces, and metrics - all from a single context object.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;MyHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gofr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// Logging&lt;/span&gt;
  &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Processing request..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c"&gt;// Database access&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
  &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SQL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryRowContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"select 2+2"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;datasource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrorDB&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Err&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"error from sql db"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c"&gt;// Accessing another service&lt;/span&gt;
  &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetHTTPService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"anotherService"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"book"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c"&gt;// Creating a tracing span&lt;/span&gt;
  &lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Trace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"some-sample-work"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;End&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="c"&gt;// ... perform some work&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, notice how we can access functionalities like logging (c.Info), database interaction (c.SQL), service calls (c.GetHTTPService), and tracing (c.Trace) directly through the GoFr Context object (c).&lt;/p&gt;

&lt;p&gt;The GoFr context is available in all HTTP handlers, greatly improving the development experience by providing a centralized way to manage different aspects of the application. This integration ensures that developers can focus on business logic while leveraging GoFr's capabilities for effective context management.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;When it comes to program design, the Golang context package is an extremely useful tool. Context in Go serves as a powerful tool for managing request-scoped data, cancellation signals, and deadlines. Whether you're building microservices, APIs, or web applications, context ensures clean resource handling and consistent behaviour.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do checkout &lt;a href="https://gofr.dev"&gt;GoFr&lt;/a&gt; and it's &lt;a href="https://github.com/gofr-dev/gofr"&gt;Github Repo&lt;/a&gt; and support it by giving it a ⭐.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>programming</category>
      <category>go</category>
      <category>webdev</category>
      <category>learning</category>
    </item>
    <item>
      <title>WebSockets in Go and GoFr</title>
      <dc:creator>Umang Mundhra</dc:creator>
      <pubDate>Fri, 28 Jun 2024 06:26:59 +0000</pubDate>
      <link>https://dev.to/umang01hash/websockets-in-go-and-gofr-3lk5</link>
      <guid>https://dev.to/umang01hash/websockets-in-go-and-gofr-3lk5</guid>
      <description>&lt;h2&gt;
  
  
  The Evolution of Real-Time Communication: A Brief History
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjlkfvim72f4tl058nq37.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjlkfvim72f4tl058nq37.png" alt="WebSockets in Go and GoFr" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the early days of web development, achieving real-time communication between clients and servers was a challenge. Developers had to rely on methods like HTTP polling, which often caused blocks on the server, leading to delays and frustrations for both developers and users. This method involved repeatedly asking the server if there were any updates, which was inefficient and resource intensive. Then came HTTP long polling and AJAX which improved the situation but still had limitations, especially in building truly real-time applications. The real breakthrough came in 2008 with the introduction of WebSockets. This innovative technology provided an effective and straightforward solution for real-time communication. WebSockets revolutionized the way we build real-time apps, making it easier and more efficient to create dynamic, interactive web applications.&lt;/p&gt;




&lt;h2&gt;
  
  
  What are WebSockets?
&lt;/h2&gt;

&lt;p&gt;WebSocket is a computer communications protocol that provides full-duplex communication channels over a single TCP connection. Unlike HTTP polling, which uses half-duplex communication, WebSocket allows both the server and the client to transmit and receive data simultaneously without being blocked. This reduces overhead and provides a more efficient way to maintain a continuous connection between the client and server. Data can be transferred from the server without a prior request from the client, allowing messages to be passed back and forth and keeping the connection open until the client or server kills it. Thus, a two-way real-time data transfer can take place between the client and the server. WebSocket communications are usually done via TCP port number &lt;code&gt;443&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;WebSockets can sustain a connection for a longer period than most other methods, enabling real-time data transfer and keeping the connection open until either the client or server terminates it. Detailed information about the WebSocket protocol can be found in the Internet Engineering Task Force (IETF) RFC 6455 specification.&lt;/p&gt;

&lt;h3&gt;
  
  
  WebSocket Use-Cases and Examples:
&lt;/h3&gt;

&lt;p&gt;WebSockets enjoy widespread support across platforms like Android, iOS, web browsers, and desktop applications. This versatility makes them a valuable tool for building real-time features across devices. Here are some real-world use case examples for websockets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;WhatsApp Web: Connects to your phone via WebSockets, enabling instant messaging, status updates, and real-time interactions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GitHub Pull Requests: WebSockets keep the conversation open, allowing real-time updates on comments and changes without page refreshes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Real-Time Tracking Applications: Ride-sharing and delivery apps leverage WebSockets for real-time location updates on drivers or deliveries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Stock Tickers and Financial Dashboards: WebSockets facilitate displaying live stock prices and real-time updates on financial dashboards.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Audio/Video Chat (WebRTC): WebSockets play a role in enabling real-time audio and video communication through WebRTC technology.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  WebSockets vs. HTTP: Understanding the Contrastst
&lt;/h2&gt;

&lt;p&gt;Both HTTP and WebSockets are communication protocols that facilitate data exchange between a client and a server. However, they serve distinct purposes and operate in fundamentally different ways.&lt;br&gt;
HTTP (Hypertext Transfer Protocol) follows a well-established request-response cycle. The client initiates a request, the server processes it, and sends a response back to the client. HTTP connections are short-lived. Each request establishes a connection, the server sends a response, and the connection closes. Each request from a client to the server is independent of any previous requests. This statelessness simplifies the design of web servers but can make certain types of communication inefficient. HTTP messages consist of headers and a body. The headers contain metadata about the message (such as content type and length), while the body contains the actual data being transferred.&lt;/p&gt;

&lt;p&gt;WebSockets establish a persistent, two-way connection between client and server. Both parties can send and receive data simultaneously, enabling real-time data flow. Unlike HTTP's short-lived connections, WebSockets remain open until either client or server terminates them. This persistent connection facilitates efficient real-time communication. Data can be sent from server to client without prior client requests, enabling immediate updates and interactions.&lt;br&gt;
In essence, HTTP excels at reliable request-response communication for static content retrieval. WebSockets, on the other hand, shine in real-time scenarios where continuous two-way data exchange is crucial.&lt;/p&gt;


&lt;h2&gt;
  
  
  How WebSockets Work: Behind the Scenes of Real-Time Communication
&lt;/h2&gt;

&lt;p&gt;WebSockets start as a standard HTTP request and response, but then transition into a persistent, full-duplex communication channel. Here's how this process unfolds:&lt;/p&gt;
&lt;h3&gt;
  
  
  1. The WebSocket Connection Open Handshake
&lt;/h3&gt;

&lt;p&gt;WebSocket URIs use the scheme ws: (or wss: for a secure WebSocket). The structure of the URI is similar to an HTTP URI, consisting of a host, port, path, and any query parameters. The connection begins with the client initiating an HTTP GET request with specific headers, including:&lt;br&gt;
Upgrade: This header is set to websocket.&lt;br&gt;
Sec-WebSocket-Key: This header contains a randomly generated base64 encoded key.&lt;/p&gt;

&lt;p&gt;The server responds to this request. If it is able to upgrade the connection, it sends back a response with an HTTP 101 Switching Protocols status code, indicating that it is switching to the WebSocket protocol as requested. This response includes headers such as:&lt;br&gt;
Upgrade: Confirming the upgrade to websocket.&lt;br&gt;
Sec-WebSocket-Accept: A base64 encoded string, which is the server's response to the client's Sec-WebSocket-Key.&lt;/p&gt;

&lt;p&gt;Once this handshake is successfully completed, the connection is upgraded, and both client and server switch to the WebSocket protocol.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. The WebSocket Protocol
&lt;/h3&gt;

&lt;p&gt;WebSocket is a framed protocol, which means that data is sent in discrete chunks called frames. Each frame consists of a header and a payload. The header contains information about the frame, including:&lt;br&gt;
Opcode: This field indicates the type of frame (e.g., text, binary, control).&lt;br&gt;
Payload Length: This field specifies the size of the payload.&lt;br&gt;
Fragmentation Information: This indicates whether the frame is part of a larger message.&lt;/p&gt;

&lt;p&gt;The frames are categorized by their opcode into types such as text frames, binary frames, and control frames (for connection management). This structure allows both the client and the server to interpret and process the data efficiently.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Closing the connection
&lt;/h3&gt;

&lt;p&gt;To close a WebSocket connection, a closing frame is sent (opcode 0x08). In addition to the opcode, the close frame may contain a body that indicates the reason for closing. If either side of a connection receives a close frame, it must send a close frame in response, and no more data should be sent over the connection. Either party can initiate closing the connection by sending a Close control frame with a specific status code (e.g., 1000 for normal closure). Once the close frame has been received by both parties, the TCP connection is torn down. The server always initiates closing the TCP connection.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9en5nm9fth480eecgy0g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9en5nm9fth480eecgy0g.png" alt="Working of websockets" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Using WebSockets in Go and GoFr:
&lt;/h2&gt;
&lt;h3&gt;
  
  
  What is GoFr?
&lt;/h3&gt;

&lt;p&gt;GoFr is a comprehensive Golang framework designed to simplify web application development by providing a rich set of features, including built-in support for WebSockets. This makes it easy to build real-time applications with minimal setup and configuration.&lt;/p&gt;
&lt;h3&gt;
  
  
  Getting Started with GoFr WebSockets:
&lt;/h3&gt;

&lt;p&gt;Using GoFr WebSockets is straightforward. Here's the basic flow:&lt;br&gt;
Define a WebSocket Handler: Create a function to handle incoming WebSocket connections. This function will receive messages from the client and can send responses back.&lt;/p&gt;

&lt;p&gt;Register the Handler with GoFr: Use the app.WebSocket method to associate your handler function with a specific endpoint (URL path) on your GoFr application.&lt;/p&gt;

&lt;p&gt;That's it! GoFr takes care of the underlying WebSocket handshake and message framing, allowing you to focus on your application logic.&lt;br&gt;
Let's Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="s"&gt;"fmt"&lt;/span&gt;

 &lt;span class="s"&gt;"gofr.dev/pkg/gofr"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="n"&gt;Content&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"content"`&lt;/span&gt;
 &lt;span class="n"&gt;User&lt;/span&gt;    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"user"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gofr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

 &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/chat"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChatHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

 &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;ChatHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gofr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="c"&gt;// Read the incoming message from the client&lt;/span&gt;
 &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt;
 &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;

 &lt;span class="c"&gt;// Process the message (e.g., broadcast to all connected clients, save it to a database, etc.)&lt;/span&gt;
 &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Infof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Received message from %s: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

 &lt;span class="c"&gt;// You can send data back to the client here (optional)&lt;/span&gt;

 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, We define a Message struct to represent chat messages. The ChatHandler function reads the incoming message using ctx.Bind. GoFr automatically detects the message format (JSON in this case) and unmarshals it into the Message struct. You can process the received message (e.g., broadcast it to all connected clients). Sending data back to the client is also possible within the handler function.&lt;/p&gt;

&lt;p&gt;When you run the above code and try to send a message to the server using Postman:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8bllbxknxeq6lz8vb6eg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8bllbxknxeq6lz8vb6eg.png" alt="Sending message to server using WebSocket" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You get these logs at the console where GoFr server is running:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxa5li7q4ts0d434j0eb4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxa5li7q4ts0d434j0eb4.png" alt="Terminal logs showing successful message receival" width="800" height="159"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, we delved into the evolution of real-time communication from the days of HTTP polling to the modern era of WebSockets. We explored the fundamental differences between HTTP and WebSocket protocols, emphasizing how WebSockets provide a robust solution for real-time, bidirectional communication.&lt;br&gt;
WebSockets have become an essential tool for building dynamic and responsive applications, from chat applications and real-time notifications to live updates and beyond. With GoFr, you have the tools to leverage this technology efficiently, ensuring your applications are both performant and maintainable.&lt;br&gt;
We encourage you to explore GoFr and its WebSocket capabilities further, as it can significantly enhance your development experience and the performance of your real-time applications.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do checkout GoFr and it's Github Repo and support it by giving it a ⭐.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Example Code Link: &lt;a href="https://github.com/Umang01-hash/Medium-Articles/tree/main/WebSockets"&gt;https://github.com/Umang01-hash/Medium-Articles/tree/main/WebSockets&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you for reading, Happy coding,!&lt;/p&gt;

</description>
      <category>backend</category>
      <category>webdev</category>
      <category>programming</category>
      <category>go</category>
    </item>
    <item>
      <title>Let's Explore GoFr</title>
      <dc:creator>Umang Mundhra</dc:creator>
      <pubDate>Tue, 07 Nov 2023 10:01:32 +0000</pubDate>
      <link>https://dev.to/umang01hash/lets-explore-gofr-1c3j</link>
      <guid>https://dev.to/umang01hash/lets-explore-gofr-1c3j</guid>
      <description>&lt;p&gt;Hey Guys!&lt;br&gt;
Hope you all are doing great.I am happy to share will you all our newly opensourced Golang framework GoFr (&lt;a href="https://gofr.dev/"&gt;https://gofr.dev/&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;🚀 Introducing &lt;strong&gt;GoFr&lt;/strong&gt; - An Opinionated Go Framework For accelerated microservice development! 🔥&lt;/p&gt;

&lt;p&gt;🔗 Get started with &lt;strong&gt;GoFr&lt;/strong&gt; now: &lt;a href="https://github.com/gofr-dev/gofrJoin"&gt;https://github.com/gofr-dev/gofrJoin&lt;/a&gt; our Go community and supercharge your Go projects with GoFr! 🚀&lt;/p&gt;

&lt;p&gt;I would request you all to please use/explore our new framework and support the new forming GoFr community.🙏🏻&lt;/p&gt;

&lt;p&gt;Consider giving it a 🌟 if you like the framework.🙂&lt;/p&gt;

</description>
      <category>go</category>
      <category>opensource</category>
      <category>backenddevelopment</category>
    </item>
  </channel>
</rss>
