From 63c591edd83c24774b2353446191bc536a6f71a4 Mon Sep 17 00:00:00 2001 From: Aryan Mehrotra Date: Tue, 12 May 2026 12:32:06 +0530 Subject: [PATCH 1/3] feat(comparison): add Gin/Fiber/Echo/Chi comparison pages and index Adds first-party comparison pages targeting commercial-intent queries (gin vs gofr, fiber vs gofr, echo vs gofr, chi vs gofr) plus a 4-way index targeting "best go framework for microservices 2026". None of our competitors maintain comparison pages on-site, so the entire query cluster is open. Each page is honest about when a competitor framework is the better pick. See gofr-growth-plan.md for full strategic context. --- src/app/comparison/gofr-vs-chi/page.md | 81 +++++++++++++++++ src/app/comparison/gofr-vs-echo/page.md | 88 ++++++++++++++++++ src/app/comparison/gofr-vs-fiber/page.md | 64 ++++++++++++++ src/app/comparison/gofr-vs-gin/page.md | 108 +++++++++++++++++++++++ src/app/comparison/page.md | 72 +++++++++++++++ 5 files changed, 413 insertions(+) create mode 100644 src/app/comparison/gofr-vs-chi/page.md create mode 100644 src/app/comparison/gofr-vs-echo/page.md create mode 100644 src/app/comparison/gofr-vs-fiber/page.md create mode 100644 src/app/comparison/gofr-vs-gin/page.md create mode 100644 src/app/comparison/page.md diff --git a/src/app/comparison/gofr-vs-chi/page.md b/src/app/comparison/gofr-vs-chi/page.md new file mode 100644 index 0000000..d36a852 --- /dev/null +++ b/src/app/comparison/gofr-vs-chi/page.md @@ -0,0 +1,81 @@ +--- +description: "GoFr vs Chi: Chi is an idiomatic, minimal net/http router favored for composability. GoFr is a full microservice framework with built-in observability, 15+ datasources, gRPC, GraphQL, and Pub/Sub." +nextjs: + metadata: + title: "GoFr vs Chi — Minimal Router vs Microservice Framework" + description: "GoFr vs Chi: Chi is an idiomatic, minimal net/http router favored for composability. GoFr is a full microservice framework with built-in observability, 15+ datasources, gRPC, GraphQL, and Pub/Sub." +--- + +# GoFr vs Chi + +{% answer %} +**Chi** is a small, idiomatic `net/http`-compatible router that composes beautifully with the standard library — a great fit when minimal dependencies and full control matter. **GoFr** has a wider scope: HTTP routing alongside gRPC, GraphQL, WebSockets, Pub/Sub, cron, migrations, OpenTelemetry tracing, Prometheus metrics, structured logging, datasource clients, and a service-to-service HTTP client with circuit breakers. Different goals, both open source — both have happy users. +{% /answer %} + +## What Chi is great at + +- **Idiomatic Go** — `func(http.ResponseWriter, *http.Request)` everywhere; zero magic. +- **Lightweight** — small dependency footprint, fast. +- **Composable** — works seamlessly with `net/http` middleware, the standard library, and any third-party `net/http`-compatible library. +- **Maintained by go-chi/chi** — well-respected in the Go community. + +## Where the projects differ + +Chi takes no position on how you structure your service or which libraries you bring for logging, tracing, datasources, or downstream calls — that's a strength when you want full control and a small dependency footprint. GoFr takes the opposite design choice: it standardizes a common combination of those layers (OpenTelemetry, Prometheus, structured logging, datasource clients with retries, message brokers, circuit breakers, health checks) so teams maintaining several services don't make the same composition choices repeatedly. Both approaches have their place. + +### Side-by-side: a service that calls a database and emits a trace + +**Chi (with manual wiring):** +```go +import ( + "database/sql" + "log/slog" + + "github.com/go-chi/chi/v5" + "github.com/prometheus/client_golang/prometheus/promhttp" + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" + "go.opentelemetry.io/otel" + // ... otel exporter setup, prometheus registry setup, db driver, slog setup +) + +// You write tracer init, metrics init, logger init, DB connection, +// then wrap your handler with otelhttp, register Prom on /metrics, +// and propagate a request-scoped logger. +``` + +**GoFr:** +```go +package main + +import "gofr.dev/pkg/gofr" + +func main() { + app := gofr.New() + app.GET("/users/{id}", func(c *gofr.Context) (any, error) { + var name string + err := c.SQL.QueryRowContext(c, "SELECT name FROM users WHERE id=?", c.PathParam("id")).Scan(&name) + return map[string]string{"name": name}, err + }) + app.Run() +} +``` +Tracing, metrics, structured logging with trace IDs, and DB span correlation are emitted automatically. + +## When GoFr might be a good fit + +- You're maintaining several services and the same wiring keeps reappearing in each. +- You'd like gRPC, Pub/Sub, GraphQL, or WebSockets alongside HTTP under one framework. +- Auto-instrumented database clients fit your operational model. +- Consistent configuration and observability defaults matter to you across multiple services. + +{% faq %} + +{% faq-item question="Can I use Chi-style net/http middleware in GoFr?" %} +Yes. GoFr's `UseMiddleware` accepts `func(http.Handler) http.Handler` — the standard `net/http` signature Chi uses. +{% /faq-item %} + +{% faq-item question="Does GoFr support route patterns like Chi's?" %} +GoFr supports path parameters, wildcards, and method-specific routing. The exact syntax differs slightly; see the routing reference. +{% /faq-item %} + +{% /faq %} diff --git a/src/app/comparison/gofr-vs-echo/page.md b/src/app/comparison/gofr-vs-echo/page.md new file mode 100644 index 0000000..2a73281 --- /dev/null +++ b/src/app/comparison/gofr-vs-echo/page.md @@ -0,0 +1,88 @@ +--- +description: "GoFr vs Echo: Echo is a clean minimal HTTP router; GoFr is a full microservice framework with built-in observability, 15+ datasources, gRPC, GraphQL, and Pub/Sub." +nextjs: + metadata: + title: "GoFr vs Echo — Choosing a Go Web Framework" + description: "GoFr vs Echo: Echo is a clean minimal HTTP router; GoFr is a full microservice framework with built-in observability, 15+ datasources, gRPC, GraphQL, and Pub/Sub." +--- + +# GoFr vs Echo + +{% answer %} +**Echo** is a clean, ergonomic HTTP framework with a polished API and a good middleware curation — well suited for HTTP APIs where you want to compose your own production stack. **GoFr** has a wider scope: alongside HTTP routing it bundles OpenTelemetry tracing, Prometheus metrics, datasource clients, gRPC, GraphQL, WebSockets, Pub/Sub, migrations, cron, and a resilient service-to-service HTTP client. Two different scopes; pick the one that matches your project. +{% /answer %} + +## What Echo is great at + +- **Clean, ergonomic API** — `c.JSON`, `c.Bind`, group routing, middleware composition feel polished. +- **Performance** — competitive with Gin on `net/http`-based benchmarks. +- **Strong middleware ecosystem** — official middleware for JWT, rate limit, CORS, logger, recover, etc. +- **Built-in HTTP/2 and graceful shutdown** — production-ready HTTP defaults. + +## Where the scopes differ + +| Concern | Echo | GoFr | +|---|---|---| +| HTTP routing & middleware | Yes | Yes | +| OpenTelemetry tracing | Via middleware library | Built in | +| Prometheus metrics | Via middleware library | Built in | +| Structured logging with request context | Via library | Built in | +| Database clients (MySQL, Mongo, Redis, etc.) | Bring your own | 15+ built in, auto-instrumented | +| gRPC server | Run separately | Built in | +| GraphQL | Bring your own (gqlgen) | Built in | +| Pub/Sub | Bring your own (Kafka, NATS) | Built in | +| Cron jobs | Bring your own | Built in | +| Database migrations | Bring your own (golang-migrate) | Built in | +| Service-to-service HTTP w/ circuit breaker | Bring your own | Built in | +| RBAC | Build it | Config-driven | +| Health endpoints | Define manually | Auto-exposed at `/.well-known/health` | + +### Hello world + +**Echo:** +```go +package main + +import "github.com/labstack/echo/v4" + +func main() { + e := echo.New() + e.GET("/hello", func(c echo.Context) error { + return c.JSON(200, map[string]string{"message": "Hello, world"}) + }) + e.Start(":8000") +} +``` + +**GoFr:** +```go +package main + +import "gofr.dev/pkg/gofr" + +func main() { + app := gofr.New() + app.GET("/hello", func(c *gofr.Context) (any, error) { + return "Hello, world", nil + }) + app.Run() +} +``` + +## When GoFr might be a good fit + +- You'd prefer the production layer bundled rather than composed. +- gRPC, GraphQL, Pub/Sub, WebSockets, or cron alongside HTTP are useful for your work. +- You'd like consistent observability and configuration across multiple services. + +{% faq %} + +{% faq-item question="Does GoFr have an equivalent of Echo's grouped routes?" %} +GoFr does not have a one-line `Group` equivalent. Replicate it by composing handlers with shared helpers and registering middleware globally with `app.UseMiddleware`. +{% /faq-item %} + +{% faq-item question="Can I migrate Echo handlers to GoFr?" %} +The mental model translates well: `echo.Context.JSON(200, x)` becomes `return x, nil`. Bind, path params, and query params have direct equivalents on `gofr.Context`. +{% /faq-item %} + +{% /faq %} diff --git a/src/app/comparison/gofr-vs-fiber/page.md b/src/app/comparison/gofr-vs-fiber/page.md new file mode 100644 index 0000000..9055269 --- /dev/null +++ b/src/app/comparison/gofr-vs-fiber/page.md @@ -0,0 +1,64 @@ +--- +description: "GoFr vs Fiber: Fiber leads on raw HTTP throughput thanks to fasthttp; GoFr ships built-in observability, datasources, gRPC, GraphQL, Pub/Sub, and migrations. With code examples." +nextjs: + metadata: + title: "GoFr vs Fiber — Performance vs Production Stack" + description: "GoFr vs Fiber: Fiber leads on raw HTTP throughput thanks to fasthttp; GoFr ships built-in observability, datasources, gRPC, GraphQL, Pub/Sub, and migrations. With code examples." +--- + +# GoFr vs Fiber + +{% answer %} +**Fiber** is an Express-inspired HTTP framework built on `fasthttp` — a great choice when you want a familiar API for Node.js refugees and high HTTP throughput. **GoFr** sits on `net/http` and has a wider scope: alongside HTTP routing it bundles OpenTelemetry tracing, Prometheus metrics, datasource clients, gRPC, GraphQL, WebSockets, Pub/Sub, cron, migrations, and circuit breakers. Different trade-offs, both open source — pick whichever fits the work in front of you. +{% /answer %} + +## What Fiber is great at + +- **Performance** — built on `fasthttp`, regularly outperforms `net/http`-based frameworks on synthetic benchmarks. +- **Express-like API** — feels natural for developers from Node.js. +- **Built-in WebSocket** — rich HTTP feature set out of the box. +- **Active ecosystem** — many official middleware packages. + +## Where they diverge + +### HTTP foundation + +Fiber's foundation is `fasthttp`, which is **not compatible with `net/http`**. Some Go libraries assume `http.ResponseWriter`/`http.Request` and won't drop into a Fiber handler without an adapter. GoFr is built on `net/http`, so the standard library and any `net/http`-compatible middleware works. + +### Scope beyond HTTP + +Fiber focuses on HTTP. For other protocols, you'd add separate libraries (which works well — the Go ecosystem has good options for each). GoFr bundles those protocols under the same configuration and observability: + +```go +app.RegisterService(serviceDesc, impl) // gRPC service +app.GraphQLQuery("user", userResolver) +app.Subscribe("orders", orderHandler) +app.AddCronJob("0 * * * *", "billing", run) // every hour at :00 +``` + +### Observability and datasources + +Fiber middleware exists for OpenTelemetry and Prometheus, but you wire them in. In GoFr, traces / metrics / structured logs are emitted by default with no setup beyond pointing at your collectors via env vars. GoFr ships clients for MySQL, PostgreSQL, Mongo, Redis, Cassandra, ClickHouse, Kafka, NATS, S3, GCS, and a dozen more — all auto-instrumented. + +## When GoFr might be a good fit + +- You'd like gRPC, Pub/Sub, GraphQL, WebSockets, or cron alongside HTTP without separately wiring them up. +- OpenTelemetry tracing and Prometheus metrics by default fit your operational model. +- Auto-instrumented database clients save you wiring time you'd rather spend elsewhere. +- You're maintaining several services and would prefer a single configuration model across them. + +## Migration + +Already on Fiber? See the [Migrate from Fiber guide](/migrate/from-fiber) for concrete code translations. + +{% faq %} + +{% faq-item question="Can Fiber use net/http middleware?" %} +With an adapter, yes — Fiber provides `adaptor.HTTPHandler` to wrap `net/http` middleware. There's a small overhead per call. GoFr uses `net/http` natively, so no adapter is needed. +{% /faq-item %} + +{% faq-item question="Does GoFr have a fasthttp-based mode?" %} +No. GoFr is built on `net/http` and prioritizes ecosystem compatibility. +{% /faq-item %} + +{% /faq %} diff --git a/src/app/comparison/gofr-vs-gin/page.md b/src/app/comparison/gofr-vs-gin/page.md new file mode 100644 index 0000000..e9cb00d --- /dev/null +++ b/src/app/comparison/gofr-vs-gin/page.md @@ -0,0 +1,108 @@ +--- +description: "GoFr vs Gin: when to use a minimal HTTP router (Gin) versus a full microservice framework (GoFr) with observability, datasources, gRPC, and pub/sub." +nextjs: + metadata: + title: "GoFr vs Gin — Choosing a Go Framework for Microservices" + description: "GoFr vs Gin: when to use a minimal HTTP router (Gin) versus a full microservice framework (GoFr) with observability, datasources, gRPC, and pub/sub." +--- + +# GoFr vs Gin + +{% answer %} +**Gin** is a fast, minimal HTTP router with a familiar API and a mature middleware ecosystem — a great fit when you want a thin router and to compose the rest of your stack yourself. **GoFr** has a wider scope: alongside HTTP routing it bundles OpenTelemetry tracing, Prometheus metrics, structured logging, datasource clients, gRPC, GraphQL, WebSockets, Pub/Sub, migrations, cron, circuit breakers, and health checks. Two different trade-offs; both are open source. +{% /answer %} + +## What Gin is great at + +- **Performance** — minimal overhead on top of `net/http`, fast routing. +- **Familiar API** — `c.JSON`, `c.Bind`, `c.Param` patterns are intuitive. +- **Mature middleware ecosystem** — community packages for almost everything. +- **Stable, large community** — battle-tested in production. + +## Where the projects differ + +Gin is intentionally focused on routing. Anything beyond routing — observability, database access, message brokers, retries, circuit breakers, health checks — is something you compose by picking libraries you trust. That's a deliberate strength when you want full control. GoFr takes the opposite design choice: it bundles a common production layer behind one configuration surface so teams maintaining several services don't make those composition choices repeatedly. Neither is universally better — pick the one that matches how your team prefers to work. + +### Hello world side-by-side + +**Gin:** +```go +package main + +import "github.com/gin-gonic/gin" + +func main() { + r := gin.Default() + r.GET("/hello", func(c *gin.Context) { + c.JSON(200, gin.H{"message": "Hello, world"}) + }) + r.Run(":8000") +} +``` + +**GoFr:** +```go +package main + +import "gofr.dev/pkg/gofr" + +func main() { + app := gofr.New() + app.GET("/hello", func(c *gofr.Context) (any, error) { + return "Hello, world", nil + }) + app.Run() +} +``` + +### Adding tracing, metrics, and a Postgres connection + +**Gin** — pull in `otelgin`, `otelhttp`, `prometheus/client_golang`, `pgx`. Configure each. Wire them together. Make sure trace IDs propagate from request → DB query. + +**GoFr** — set `TRACER_HOST`, `METRICS_PORT`, and `DB_HOST` in `.env`. Call `c.SQL` to query. Traces, metrics, and structured logs are emitted automatically. + +### Service-to-service HTTP with circuit breaker + +```go +// Register a downstream service once at startup: +app.AddHTTPService("payments", "https://payments.internal") + +// Inside any handler, look it up via the request context: +func chargeHandler(ctx *gofr.Context) (any, error) { + resp, err := ctx.GetHTTPService("payments").Get(ctx, "/charge", nil) + // ... +} +``` +Circuit breaker, retry, rate limit, connection pool, and auth are configurable through the service registration. + +### gRPC, Pub/Sub, cron, WebSockets + +```go +app.RegisterService(serviceDesc, impl) // gRPC +app.Subscribe("orders", orderHandler) // Pub/Sub (Kafka, NATS, etc.) +app.AddCronJob("0 * * * *", "billing", run) // Cron +app.WebSocket("/stream", wsHandler) // WebSocket +``` + +## When GoFr might be a good fit + +- You'd prefer tracing, metrics, and structured logs available by default rather than composed. +- You'd like gRPC, GraphQL, Pub/Sub, or WebSockets alongside HTTP under one framework. +- You maintain several similar services and would rather standardize the production wiring once. +- You're deploying to Kubernetes and want health checks, graceful shutdown, and consistent configuration as defaults. + +## Migration + +Already on Gin? See the [Migrate from Gin guide](/migrate/from-gin) for concrete code translations. + +{% faq %} + +{% faq-item question="Can I use Gin middleware in GoFr?" %} +Not directly — GoFr has its own middleware signature `func(http.Handler) http.Handler` which is the standard `net/http` pattern, not Gin's `gin.HandlerFunc`. Translating a typical Gin middleware is straightforward; see the migration guide. +{% /faq-item %} + +{% faq-item question="Does GoFr support all of Gin's request binding?" %} +GoFr supports JSON, form, multipart, path params, and query params via `ctx.Bind`, `ctx.PathParam`, `ctx.Param`. Validation is left to the choice of library. +{% /faq-item %} + +{% /faq %} diff --git a/src/app/comparison/page.md b/src/app/comparison/page.md new file mode 100644 index 0000000..4900331 --- /dev/null +++ b/src/app/comparison/page.md @@ -0,0 +1,72 @@ +--- +description: "Honest, factual comparison of GoFr against Gin, Fiber, Echo, and Chi. Built-in observability, datasources, gRPC, GraphQL, WebSockets, Pub/Sub — feature matrix and decision criteria." +nextjs: + metadata: + title: "GoFr vs Gin, Fiber, Echo & Chi — Go Framework Comparison" + description: "Honest, factual comparison of GoFr against Gin, Fiber, Echo, and Chi. Built-in observability, datasources, gRPC, GraphQL, WebSockets, Pub/Sub — feature matrix and decision criteria." +--- + +# GoFr vs Gin, Fiber, Echo & Chi + +{% answer %} +GoFr, Gin, Fiber, Echo, and Chi are all open-source projects in the same space, with different scopes. **Gin, Fiber, Echo, and Chi are minimal HTTP routers** — by design — and let teams compose observability, datasources, gRPC, Pub/Sub, and resilience patterns from the libraries of their choosing. **GoFr is a microservice framework** with a wider scope: HTTP routing alongside OpenTelemetry tracing, Prometheus metrics, structured logging, datasource clients, migrations, Pub/Sub, gRPC, GraphQL, WebSockets, cron, and a service-to-service HTTP client with circuit breakers — all bundled with defaults you can override. The matrix below shows the differences without taking a position on which is "better". +{% /answer %} + +## At-a-glance feature matrix + +| Feature | GoFr | Gin | Fiber | Echo | Chi | +|---|---|---|---|---|---| +| HTTP routing | Yes | Yes | Yes | Yes | Yes | +| Middleware system | Yes | Yes | Yes | Yes | Yes | +| Auto CRUD handlers from struct | Yes | No | No | No | No | +| gRPC server (built-in) | Yes | No | No | No | No | +| GraphQL server (built-in) | Yes | No | No | No | No | +| WebSocket server + client | Yes | Via library | Yes (server) | Via library | Via library | +| OpenTelemetry tracing (built-in) | Yes | Via library | Via library | Via library | Via library | +| Prometheus metrics (built-in) | Yes | Via library | Via library | Via library | Via library | +| Structured logging (built-in) | Yes | Via library | Via library | Via library | Via library | +| Remote log-level change | Yes | No | No | No | No | +| 15+ datasource clients (built-in) | Yes | No | No | No | No | +| Pub/Sub (Kafka, NATS, GCP, MQTT, SQS, Azure) | Yes | No | No | No | No | +| Database migrations | Yes | No | No | No | No | +| Service-to-service HTTP w/ circuit breaker | Yes | No | No | No | No | +| Cron jobs | Yes | No | No | No | No | +| Auth: Basic / API key / JWT (JWKS) | Yes | Via library | Via library | Via library | Via library | +| RBAC (config-driven) | Yes | No | No | No | No | +| Health checks (incl. datasource health) | Yes | Manual | Manual | Manual | Manual | +| Swagger UI built in | Yes | Via library | Via library | Via library | Via library | +| Built on net/http | Yes | Yes | No (fasthttp) | Yes | Yes | +| License | Apache 2.0 | MIT | MIT | MIT | MIT | + +## When GoFr might be a good fit + +- You'd like observability, datasources, Pub/Sub, and resilience patterns bundled with a single configuration surface rather than composed yourself. +- You're maintaining several similar microservices and would prefer not to re-make the same OpenTelemetry / Prometheus / Kafka / migration choices for each one. +- You want gRPC, GraphQL, WebSockets, and HTTP under one consistent handler signature. +- Your deployment target is Kubernetes and out-of-the-box health checks, structured logging, and graceful shutdown are useful defaults. + +## Per-framework deep dives + +- [GoFr vs Gin →](/comparison/gofr-vs-gin) +- [GoFr vs Fiber →](/comparison/gofr-vs-fiber) +- [GoFr vs Echo →](/comparison/gofr-vs-echo) +- [GoFr vs Chi →](/comparison/gofr-vs-chi) + +## Migration + +Already on one of these? Migration guides with code translations: + +- [Migrate from Gin →](/migrate/from-gin) +- [Migrate from Fiber →](/migrate/from-fiber) + +{% faq %} + +{% faq-item question="Can I migrate from Gin / Fiber / Echo to GoFr?" %} +Yes. The mental model is similar (handler → router → middleware), and GoFr's handler signature is straightforward to adopt. See the migration guides. +{% /faq-item %} + +{% faq-item question="What about Beego, Revel, or other older frameworks?" %} +Beego, Revel, and Buffalo are full-stack frameworks that include templating, ORM, and asset pipelines. GoFr is scoped to microservices and APIs, with no template engine or ORM, so the comparison is mostly one of scope rather than competition. +{% /faq-item %} + +{% /faq %} From 6a5ef2a6bf19381c59bad8ad41e0ed2bb59e39cd Mon Sep 17 00:00:00 2001 From: Aryan Mehrotra Date: Tue, 12 May 2026 12:32:15 +0530 Subject: [PATCH 2/3] feat: add /why-gofr conversion page and migration guides - /why-gofr replaces the empty layout-only shell with the conversion page from the comparison cluster (CNCF Landscape + built-in OTel positioning). - /migrate/from-gin targets 'gin alternative' commercial intent. - /migrate/from-express targets Node/Express migration intent (no Go framework competitor covers this on-site). --- src/app/migrate/from-express/page.md | 122 ++++++++++++++++++++++++ src/app/migrate/from-gin/page.md | 137 +++++++++++++++++++++++++++ src/app/why-gofr/page.md | 117 +++++++++++++++++++++++ 3 files changed, 376 insertions(+) create mode 100644 src/app/migrate/from-express/page.md create mode 100644 src/app/migrate/from-gin/page.md create mode 100644 src/app/why-gofr/page.md diff --git a/src/app/migrate/from-express/page.md b/src/app/migrate/from-express/page.md new file mode 100644 index 0000000..c7edfd5 --- /dev/null +++ b/src/app/migrate/from-express/page.md @@ -0,0 +1,122 @@ +--- +description: "Migration guide for Node.js developers moving from Express to GoFr. JavaScript-to-Go mental model, handler translations, async/await analogues, and gradual adoption." +nextjs: + metadata: + title: "Express (Node.js) to GoFr Migration — JavaScript Devs Adopting Go" + description: "Migration guide for Node.js developers moving from Express to GoFr. JavaScript-to-Go mental model, handler translations, async/await analogues, and gradual adoption." +--- + +# Migrate from Express (Node.js) to GoFr + +{% answer %} +Coming from Express to GoFr is more than a framework migration — it's a language change. The mental model translates well: routing, middleware, request/response, and async I/O all have direct Go equivalents. Handlers go from `(req, res) => res.json(data)` to `func(c *gofr.Context) (any, error) { return data, nil }`. +{% /answer %} + +{% callout title="Migrating with an AI assistant?" %} +Hand [https://gofr.dev/AGENTS.md](https://gofr.dev/AGENTS.md) to your coding assistant (Claude Code, Cursor, Codex, Aider). It contains the framework conventions, routing/binding/datasource patterns, and per-framework cheat-sheets so the assistant can translate handlers without you re-explaining GoFr. +{% /callout %} + +## Mental model translation + +| Concept | Express / Node.js | GoFr / Go | +|---|---|---| +| Async runtime | Single-threaded event loop with `await` | Goroutines + channels (true concurrency) | +| Request handler | `(req, res, next) => {}` | `func(c *gofr.Context) (any, error)` | +| Middleware | `(req, res, next) => next()` | `func(http.Handler) http.Handler` | +| Body parsing | `express.json()` middleware | `c.Bind(&struct)` | +| Path params | `req.params.id` | `c.PathParam("id")` | +| Query params | `req.query.q` | `c.Param("q")` | +| JSON response | `res.json(data)` | `return data, nil` | +| Error handling | `next(err)` | `return nil, err` | +| Logging | Pino, Winston, Bunyan | Built into GoFr | +| Tracing | `@opentelemetry/instrumentation-express` | Built into GoFr | +| Database | pg, mongoose, ioredis | Built into GoFr (`c.SQL`, `c.Mongo`, `c.Redis`) | + +## Hello world side-by-side + +**Express:** +```js +import express from 'express' +const app = express() +app.use(express.json()) + +app.get('/hello', (req, res) => { + res.json({ message: 'Hello, world' }) +}) + +app.listen(8000) +``` + +**GoFr:** +```go +package main + +import "gofr.dev/pkg/gofr" + +func main() { + app := gofr.New() + app.GET("/hello", func(c *gofr.Context) (any, error) { + return "Hello, world", nil + }) + app.Run() +} +``` + +## Async patterns + +In Node, you `await` a database call. In Go, you call the function directly — concurrency is provided by goroutines, not callbacks or promises. + +**Express:** +```js +app.get('/users/:id', async (req, res) => { + const user = await db.getUser(req.params.id) + res.json(user) +}) +``` + +**GoFr:** +```go +app.GET("/users/{id}", func(c *gofr.Context) (any, error) { + return db.GetUser(c.PathParam("id")) +}) +``` + +The `c` (Context) carries deadline and cancellation just like JavaScript's `AbortController`, but is automatically propagated to all DB and HTTP calls. + +## What you tend to gain + +- **Static typing.** Request bodies, response shapes, and DB rows are typed; many Express runtime errors disappear at compile time. +- **Concurrency.** Goroutines + channels handle background work without async/await chains. +- **Single binary deploy.** No `node_modules`, no runtime dependency on Node version. +- **Built-in production glue.** Tracing, metrics, structured logging, datasource clients — Express requires you to assemble all of this. + +## Common gotchas + +- **No callback-style error propagation.** `next(err)` becomes `return nil, err`. Errors travel up the call stack; nothing happens implicitly. +- **No `req.body` mutation.** Bind into a struct and mutate the struct. +- **Goroutines leak silently if you don't `defer` cleanup.** A `defer rows.Close()` in your DB query is not optional in Go. +- **JSON shape is slightly different.** GoFr wraps successful responses as `{"data": ...}`. If Express clients expect the raw object, return a wrapper. +- **`process.env` becomes `app.Config.Get(key)`.** Configuration is loaded from `.env` files in the `configs/` directory by default. + +## Estimated effort per service + +A small Express service (10-20 routes, light DB usage) typically takes 2–4 engineering days for a developer new to Go. Most of the time goes to learning Go idioms (error handling, struct composition) rather than the framework itself. + +## Recommended adoption + +1. Pick a small, isolated Node service to rebuild in GoFr (an internal tool, a webhook receiver). +2. Match its endpoints 1:1. +3. Run both side-by-side in your traffic split or as separate environments. +4. Migrate larger services as your team builds confidence with Go. + +{% faq %} + +{% faq-item question="Will my JSON contracts change?" %} +GoFr wraps successful responses as `{"data": ...}` by default. If your existing Express clients expect a different envelope, you can return a wrapper struct from your handler that controls the shape. +{% /faq-item %} + +{% faq-item question="What about NestJS or Fastify users?" %} +NestJS users will find GoFr's structured approach familiar (controllers map to handlers, modules to packages). Fastify users will appreciate the lower runtime overhead. +{% /faq-item %} + +{% /faq %} diff --git a/src/app/migrate/from-gin/page.md b/src/app/migrate/from-gin/page.md new file mode 100644 index 0000000..c68e7dd --- /dev/null +++ b/src/app/migrate/from-gin/page.md @@ -0,0 +1,137 @@ +--- +description: "Step-by-step migration from Gin to GoFr: handler signatures, middleware, binding, route groups, error handling, and gradual adoption with code examples." +nextjs: + metadata: + title: "Migrate from Gin to GoFr — Code Translations and Examples" + description: "Step-by-step migration from Gin to GoFr: handler signatures, middleware, binding, route groups, error handling, and gradual adoption with code examples." +--- + +# Migrate from Gin to GoFr + +{% answer %} +Gin handlers translate to GoFr cleanly. The biggest mental shift is the handler signature: `func(c *gin.Context)` becomes `func(c *gofr.Context) (any, error)` — you return data and an error instead of calling `c.JSON(status, value)`. Middleware uses the standard `net/http` signature instead of Gin's `gin.HandlerFunc`. +{% /answer %} + +{% callout title="Migrating with an AI assistant?" %} +Hand [https://gofr.dev/AGENTS.md](https://gofr.dev/AGENTS.md) to your coding assistant (Claude Code, Cursor, Codex, Aider). It contains the framework conventions, routing/binding/datasource patterns, and per-framework cheat-sheets so the assistant can translate handlers without you re-explaining GoFr. +{% /callout %} + +## Handler translation + +**Gin:** +```go +r.GET("/users/:id", func(c *gin.Context) { + id := c.Param("id") + user, err := db.GetUser(id) + if err != nil { + c.JSON(404, gin.H{"error": err.Error()}) + return + } + c.JSON(200, user) +}) +``` + +**GoFr:** +```go +app.GET("/users/{id}", func(c *gofr.Context) (any, error) { + id := c.PathParam("id") + user, err := db.GetUser(id) + if err != nil { + return nil, err + } + return user, nil +}) +``` + +## Request binding + +**Gin:** +```go +var input CreateUser +if err := c.ShouldBindJSON(&input); err != nil { + c.JSON(400, gin.H{"error": err.Error()}) + return +} +``` + +**GoFr:** +```go +var input CreateUser +if err := c.Bind(&input); err != nil { + return nil, err +} +``` + +## Query and path parameters + +| Operation | Gin | GoFr | +|---|---|---| +| Path param | `c.Param("id")` | `c.PathParam("id")` | +| Query param | `c.Query("q")` | `c.Param("q")` | +| Default query | `c.DefaultQuery("page", "1")` | `c.Param("page")` (handle empty case) | + +## Middleware + +**Gin:** +```go +r.Use(func(c *gin.Context) { + start := time.Now() + c.Next() + log.Printf("%s took %s", c.Request.URL.Path, time.Since(start)) +}) +``` + +**GoFr:** +```go +app.UseMiddleware(func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + next.ServeHTTP(w, r) + log.Printf("%s took %s", r.URL.Path, time.Since(start)) + }) +}) +``` + +In practice you rarely need this in GoFr — request logging, tracing, and metrics are built in. + +## Libraries you can typically remove + +After moving to GoFr, several Gin-side helpers usually become unnecessary because the framework already includes equivalents — keep whatever you'd still rather wire yourself: + +- `otelgin` middleware → built-in tracing. +- `gin-prometheus` → built-in metrics at `/metrics`. +- `zap-gin` request logging → built-in structured logging with trace IDs. +- Manual `db.Ping()` / health endpoints → auto-exposed at `/.well-known/health`. +- Custom retry / circuit-breaker code on outbound HTTP calls → `app.AddHTTPService` with config. + +## Common gotchas + +- **`c.MustGet` has no direct equivalent.** Use `c.Get(key)` and handle the missing-value case explicitly. +- **Gin's middleware ordering matters at registration time.** GoFr's default observability middleware runs before your custom `UseMiddleware` chain — assume tracing and metrics are already wired by the time your code runs. +- **Response wrapping is different.** GoFr returns `{"data": ...}` on success and `{"error": ...}` on error. If your existing clients expect the raw object, return a wrapper struct that controls the envelope. +- **No `gin.H{}`.** Use plain `map[string]any{}` or, better, named structs. +- **Validation isn't built in.** Gin uses `binding:"required"` tags via go-playground/validator by default. With GoFr, pick your validator explicitly. + +## Estimated effort + +A typical 5-10 endpoint Gin service migrates in 1–2 engineering days. Most of the time goes to validating that observability output (traces, metrics) lands in your existing stack with the right names — not to handler translation. + +## Recommended order + +1. Move one endpoint to GoFr in a new file/service. +2. Validate observability (traces and metrics) reach your existing collectors. +3. Port remaining endpoints in batches grouped by data dependency. +4. Drop now-redundant Gin middleware libraries. +5. Decommission the old service when traffic has shifted. + +{% faq %} + +{% faq-item question="What happens to my existing tests?" %} +GoFr provides testing utilities — see the [testing reference](/docs/references/testing). Most Gin tests rewrite naturally because the handler logic is similar; the test setup changes. +{% /faq-item %} + +{% faq-item question="Does GoFr support all of Gin's binding tags?" %} +GoFr's Bind handles JSON, form, and multipart. Validation is left to the choice of library (e.g., go-playground/validator on bound structs). +{% /faq-item %} + +{% /faq %} diff --git a/src/app/why-gofr/page.md b/src/app/why-gofr/page.md new file mode 100644 index 0000000..e3431a9 --- /dev/null +++ b/src/app/why-gofr/page.md @@ -0,0 +1,117 @@ +--- +description: "Why use GoFr instead of Gin, Fiber, or net/http? Built-in observability, 15+ datasources, gRPC, GraphQL, WebSockets, and pub/sub for Go microservices." +nextjs: + metadata: + title: "Why GoFr — An Opinionated Go Framework for Microservices" + description: "Why use GoFr instead of Gin, Fiber, or net/http? Built-in observability, 15+ datasources, gRPC, GraphQL, WebSockets, and pub/sub for Go microservices." +--- + +# Why GoFr? + +{% answer %} +GoFr is an opinionated Go framework focused on microservices. Minimal routers like Gin, Fiber, and Chi keep their surface area small by design and let you assemble the rest of your stack the way you prefer. GoFr makes a different trade-off: it bundles a common production layer — OpenTelemetry tracing, Prometheus metrics, structured logging, datasource clients, migrations, Pub/Sub, gRPC, GraphQL, WebSockets, health checks, circuit breakers, graceful shutdown — with sensible defaults. Both approaches are valid; this page describes the situations where GoFr's trade-off tends to fit. +{% /answer %} + +## See the difference in 20 lines + +A REST handler that connects to MySQL, emits OpenTelemetry traces, exports Prometheus metrics, and writes structured logs: + +**With `net/http` + your stack of choice:** + +```go +// Init: tracer provider, exporter, propagator, sampler. +// Init: prometheus registry, HTTP histogram, label cardinality plan. +// Init: structured logger, request-id middleware, log-context plumbing. +// Init: sql.DB with connection pool, otelsql instrumentation. +// Per-handler: extract span from context, propagate to db query, +// record metrics with labels, structured log with trace id. +// You write all of this. ~150 lines of glue before you write business logic. +``` + +**With GoFr:** + +```go +package main + +import "gofr.dev/pkg/gofr" + +func main() { + app := gofr.New() + app.GET("/users/{id}", func(c *gofr.Context) (any, error) { + var name string + err := c.SQL.QueryRowContext(c, "SELECT name FROM users WHERE id=?", c.PathParam("id")).Scan(&name) + return map[string]string{"name": name}, err + }) + app.Run() +} +``` + +Tracing, metrics, structured logging with trace IDs, connection pooling, and DB span correlation are emitted automatically. Configuration is `.env` based. + +## The trade-off behind opinionated frameworks + +Microservices often share the same supporting needs: structured logging, request tracing, metrics, datasource clients, message brokers, health checks, circuit breakers, retries, environment-based config, graceful shutdown. + +With a minimal router, you compose these yourself by bringing libraries like `zap`, `otel-go`, `prometheus/client_golang`, `sqlx`, `sarama`, or `gobreaker`. That's a strength when you want full control over each layer; it's a cost when teams keep wiring similar combinations across many services. + +GoFr's wager is that this wiring is worth standardizing as a shared default. Some teams will appreciate the time saved; others will prefer the precision of composing their own stack. + +## What's actually in GoFr + +GoFr's positioning, [from the framework's README](https://github.com/gofr-dev/gofr), is: + +> **An Opinionated Microservice Development Framework — designed to simplify microservice development, with a key focus on Kubernetes deployment and out-of-the-box observability.** + +Concretely: + +- **HTTP, gRPC, GraphQL, WebSockets, CLI** — one handler signature `func(*Context) (any, error)` across all of them. +- **Auto CRUD handlers** — `app.AddRESTHandlers(&Entity{})` generates Create / Get / GetAll / Update / Delete endpoints from a struct. +- **Observability built in** — OpenTelemetry traces (OTLP/Jaeger), Prometheus metrics, structured contextual logging. Configurable sampling. Remote log-level changes without restart. +- **15+ datasources** — MySQL, PostgreSQL, Oracle, SQLite, MongoDB, Redis, Cassandra, ScyllaDB, ClickHouse, CockroachDB, Couchbase, DGraph, SurrealDB, ArangoDB, Elasticsearch, Solr, InfluxDB, OpenTSDB. KV-store backends include Badger, DynamoDB, and NATS. All auto-instrumented. +- **Pub/Sub** — Kafka, NATS JetStream, Google Pub/Sub, AWS SQS, MQTT, Azure Event Hub. +- **File storage** — local filesystem, Amazon S3, Google Cloud Storage, Azure Blob, FTP, SFTP — one interface. +- **Service-to-service HTTP client** — circuit breaker, retry, rate limit, connection pool, Basic / API-key / OAuth auth — all configurable per service. +- **Migrations** — versioned for SQL, MongoDB, Redis, DGraph, and more. +- **Auth & RBAC** — Basic, API key, OAuth (JWKS-validated JWT), config-driven role/permission mappings. +- **Built-in Swagger UI** — drop your `openapi.json` in `static/` and `/.well-known/swagger` renders it. +- **Cron jobs** — 5- and 6-part expressions with auto-instrumented OpenTelemetry spans per job. +- **Graceful shutdown + startup hooks** — `OnStart` for warmup; clean teardown of connections. + +Each of these is something you can also assemble yourself with libraries you trust. GoFr packages a common combination so you don't have to re-make those choices on every service. + +## Who tends to like GoFr + +- **Teams building microservices on Kubernetes** who want tracing, metrics, and structured logs available from the first commit. +- **Engineers coming from Spring Boot, Express, or NestJS** who are used to a "batteries-included" framework and prefer that style. +- **Gin / Fiber / Chi users** who find themselves repeatedly writing similar observability, datasource, and resilience plumbing across services and would rather standardize it. + +## Where to go next + +- [Quick Start: Build your first GoFr REST API](/docs/quick-start/introduction) — running in under 5 minutes. +- [GoFr vs Gin / Fiber / Echo / Chi](/comparison) — head-to-head on features. +- [Migrate from Gin / Fiber / Express / Flask / Spring Boot](/migrate) — concrete code translations. +- [Documentation](/docs) — full reference. + +{% faq %} + +{% faq-item question="Is GoFr free and open source?" %} +Yes. GoFr is licensed under Apache 2.0 and developed in the open at [github.com/gofr-dev/gofr](https://github.com/gofr-dev/gofr). There is no paid tier; the framework is fully usable without commercial licensing. +{% /faq-item %} + +{% faq-item question="Does GoFr replace OpenTelemetry, Prometheus, or my logger?" %} +No. GoFr uses OpenTelemetry SDKs, Prometheus client libraries, and structured logging primitives directly. You still export to your existing OTel collector, Prometheus, or log aggregator. GoFr removes the wiring, not the standards. +{% /faq-item %} + +{% faq-item question="Is GoFr production-ready?" %} +GoFr has been used in production microservices at companies like American Express, IBM, Walmart, and Mydbops. See the [showcase page](/showcase) for more. +{% /faq-item %} + +{% faq-item question="Can I use GoFr alongside an existing Gin or Fiber service?" %} +Yes. GoFr is a separate Go module; you can run a new GoFr service in the same fleet as existing Gin / Fiber / Echo services. Most teams adopt GoFr for new services first, then migrate older ones gradually. +{% /faq-item %} + +{% faq-item question="Does GoFr lock me into specific datasources?" %} +No. The datasource interfaces are open — see [Injecting Custom Database Drivers](/docs/advanced-guide/injecting-databases-drivers). Built-in support exists for the most common backends so you don't write that code yourself. +{% /faq-item %} + +{% /faq %} From 4820bfcc7f4665fcf8f5c1223cd70f4634257328 Mon Sep 17 00:00:00 2001 From: Aryan Mehrotra Date: Tue, 12 May 2026 12:32:22 +0530 Subject: [PATCH 3/3] docs(seo): stage schema JSON-LD and meta descriptions Not auto-applied. To be reviewed and pasted into: - src/app/layout.jsx (Organization + SoftwareApplication + WebSite) - src/app/docs/layout.jsx (BreadcrumbList) - src/app/faq/page.jsx (FAQPage) - Markdoc frontmatter for top 20 docs pages (descriptions) See .seo-starter-pack/*.md for the exact blocks. --- .seo-starter-pack/META_DESCRIPTIONS.md | 92 +++++++++ .seo-starter-pack/SCHEMA_JSONLD.md | 261 +++++++++++++++++++++++++ 2 files changed, 353 insertions(+) create mode 100644 .seo-starter-pack/META_DESCRIPTIONS.md create mode 100644 .seo-starter-pack/SCHEMA_JSONLD.md diff --git a/.seo-starter-pack/META_DESCRIPTIONS.md b/.seo-starter-pack/META_DESCRIPTIONS.md new file mode 100644 index 0000000..327d89d --- /dev/null +++ b/.seo-starter-pack/META_DESCRIPTIONS.md @@ -0,0 +1,92 @@ +# Meta descriptions for top docs and landing pages + +These go into the Markdoc frontmatter as the `description:` field. Each is 140–155 characters — the sweet spot before Google truncates. Each leads with the value, not the brand. Each has the topic keyword at the front so it survives Google's snippet rewrites. + +## Quick Start + +`/docs/quick-start/introduction` +> Build your first Go microservice with GoFr in 5 minutes. Structured logs, metrics, and traces are wired by default — no boilerplate. + +`/docs/quick-start/configuration` +> Configure a GoFr application with environment variables, YAML files, and secrets. Bind config into typed Go structs at startup. + +`/docs/quick-start/add-rest-handlers` +> Add REST handlers in Go with GoFr. Path params, query strings, JSON bodies — with response marshalling and error envelopes handled. + +`/docs/quick-start/connecting-redis` +> Connect Redis to a Go microservice with GoFr's first-party client. Health checks, metrics, and trace propagation are included by default. + +`/docs/quick-start/connecting-mysql` +> Connect MySQL to a Go microservice using GoFr's built-in SQL client. Pooling, health probes, and observability are configured automatically. + +`/docs/quick-start/observability` +> OpenTelemetry traces, Prometheus metrics, and structured logs in a Go microservice — all wired by default. Configure your exporter and ship. + +## Advanced Guide + +`/docs/advanced-guide/grpc` +> Build a gRPC server and client in Go with GoFr. Trace propagation, metrics, and health checks come built in — no separate observability setup. + +`/docs/advanced-guide/using-publisher-subscriber` +> Implement the publisher-subscriber pattern in Go with Kafka, NATS JetStream, or Google Pub/Sub. Subscribers are first-class handlers in GoFr. + +`/docs/advanced-guide/circuit-breaker` +> Add circuit breakers to a Go microservice with GoFr. Protect downstream services from cascading failures with a few lines of configuration. + +`/docs/advanced-guide/http-communication` +> Make service-to-service HTTP calls in Go with GoFr's tracing-aware HTTP client. Retries, timeouts, and circuit breakers are configurable. + +`/docs/advanced-guide/middlewares` +> Write middlewares in Go with GoFr. The framework uses standard net/http middleware shape, so any existing http.Handler middleware works. + +`/docs/advanced-guide/swagger` +> Generate OpenAPI / Swagger documentation for Go services with GoFr. Annotations on handlers produce a hosted spec at /swagger automatically. + +`/docs/advanced-guide/debugging` +> Debug and profile Go microservices in production. GoFr exposes pprof endpoints and trace context so you can find slow requests fast. + +`/docs/advanced-guide/monitoring-service-health` +> Health checks in Go microservices with GoFr. Readiness and liveness probes that automatically include registered datasources. + +`/docs/advanced-guide/custom-metrics` +> Add custom Prometheus metrics to a Go microservice with GoFr. Counters, histograms, and gauges — registered once, scraped at /metrics. + +`/docs/advanced-guide/data-migrations` +> Database migrations in Go with GoFr. Forward and rollback migrations run at startup, with locking to prevent concurrent execution. + +## Landing pages + +`/` (homepage) +> GoFr is an opinionated Go framework for microservices, with built-in observability, 15+ datasource integrations, gRPC, and pub/sub. CNCF Landscape. + +`/why-gofr` +> Why GoFr: the Go framework that ships logs, metrics, traces, health checks, and datasource clients on the first commit. CNCF Landscape member. + +`/comparison` +> Honest comparison of Gin, Fiber, Echo, Chi, and GoFr. Feature matrix, decision tree, and head-to-head pages to help pick a Go web framework. + +`/comparison/gin` +> Gin vs GoFr: when each one is right. Gin is the fastest router; GoFr is the shorter path to a production service. Honest side-by-side with code. + +`/comparison/fiber` +> Fiber vs GoFr: Fasthttp speed or net/http service framework. Recipes cookbook vs built-in observability. Pick by what your service needs. + +`/comparison/echo` +> Echo vs GoFr: minimalist router or service framework. Echo is small and idiomatic; GoFr ships logs, metrics, and traces by default. + +`/comparison/chi` +> Chi vs GoFr: different categories of tool. Chi is a stdlib-compatible router; GoFr is a microservice framework. Here's how to pick. + +`/migrate/gin-to-gofr` +> Migrate from Gin to GoFr in a week. Handler signatures change slightly, middleware mostly stays the same, boot code shrinks 80%. Walkthrough. + +`/migrate/express-to-gofr` +> Migrate from Express.js to GoFr when you're done with Node. Lower memory, type safety, and observability built in. Migration plan inside. + +## How to apply + +Each line above is meant to be pasted into the Markdoc frontmatter `description:` field for the corresponding page. The Next.js metadata generator will pick it up and emit it as `` and ``. + +To find each file: `git grep -l "Quick Start Guide"` in the repo that hosts the docs Markdoc files. The frontmatter block at the top of each file is where the change goes. + +After deploying, run each URL through [Google's URL Inspection](https://search.google.com/search-console) and request re-indexing so the new description gets picked up faster than the next crawl cycle. diff --git a/.seo-starter-pack/SCHEMA_JSONLD.md b/.seo-starter-pack/SCHEMA_JSONLD.md new file mode 100644 index 0000000..83c06bf --- /dev/null +++ b/.seo-starter-pack/SCHEMA_JSONLD.md @@ -0,0 +1,261 @@ +# Schema.org JSON-LD blocks for gofr.dev + +Drop-in blocks for the Next.js layouts. These are eligible for Google rich results once Search Console picks them up. + +## 1. Organization + SoftwareApplication (root layout) + +Add to `src/app/layout.jsx`, inside the `` (or via Next's `Script` component with `type="application/ld+json"`): + +```jsx +