{"owner":"gofr-dev","repo":"gofr","hasSkills":true,"totalSkillsCount":9,"totalTokensCount":17824,"categories":["root-instruction","anthropic-skill"],"hasMcp":false,"mcpConfig":null,"found":["docs/AGENTS.md","docs/references/configs/page.md","docs/references/gofrcli/page.md","docs/references/gofrcli/migrate/page.md","docs/references/gofrcli/init/page.md","docs/references/context/page.md","docs/references/gofrcli/store/page.md","docs/references/testing/page.md","docs/references/gofrcli/wrap-grpc/page.md"],"skills":{"docs/AGENTS.md":"# GoFr — guide for AI coding assistants\n\nFor Claude Code, Cursor, Aider, Codex, etc. Hand\n[https://gofr.dev/AGENTS.md](https://gofr.dev/AGENTS.md) to your assistant\nwhen working on a GoFr project. It points at the specific docs you'll\nactually need rather than inlining everything.\n\nGoFr is an opinionated Go framework for microservices. Apache 2.0.\nRequires Go 1.26+. Repo: <https://github.com/gofr-dev/gofr>.\n\n## Core rules an assistant must know\n\n1. **One handler signature** for HTTP / gRPC / GraphQL / WebSocket / cron / CLI:\n   `func(c *gofr.Context) (any, error)`. Return value → `{\"data\": ...}`. Return error → error response.\n2. **Path params use `{name}`**, not `:name`. `app.GET(\"/users/{id}\", h)`.\n3. **`c.PathParam(\"id\")`** for path; **`c.Param(\"q\")`** for query; **`c.Bind(&v)`** for body.\n4. **Don't manually wire OpenTelemetry, Prometheus, or structured logging.** `gofr.New()` does it.\n5. **Pass `*gofr.Context`** (not `context.Background()`) to every downstream call so trace propagation and cancellation work.\n6. **Configuration comes from `configs/.env`** via `c.Config.Get(key)`. No hardcoded ports / hosts / secrets.\n7. **No ORM bundled.** Use plain SQL via `c.SQL`, or pair with `sqlc`/`gorm` yourself.\n8. **Middleware is standard `net/http`**: `func(http.Handler) http.Handler`, registered with `app.UseMiddleware(...)`.\n9. **Health is auto-exposed** at `/.well-known/health` and `/.well-known/alive`. Don't hand-roll `/healthz`.\n10. **Don't `panic()` for control flow.** Return errors.\n\n## Minimal app\n\n```go\npackage main\n\nimport \"gofr.dev/pkg/gofr\"\n\nfunc main() {\n    app := gofr.New()\n    app.GET(\"/hello\", func(c *gofr.Context) (any, error) {\n        return \"Hello, world\", nil\n    })\n    app.Run()\n}\n```\n\n## Migrations (schema + seed data, versioned)\n\nGoFr has a built-in migration runner — use it instead of `golang-migrate` / `goose`. Works for SQL, Redis, Mongo, Cassandra, ClickHouse, DGraph, SurrealDB.\n\n**Before writing a migration, fetch the full reference:** <https://gofr.dev/docs/advanced-guide/handling-data-migrations>. Runnable shape: <https://github.com/gofr-dev/gofr/tree/main/examples/using-migrations>.\n\nFive rules to keep in your head so you don't have to re-fetch on every change:\n\n1. Files live in `migrations/<unix-ts>_<name>.go`. Versions are `int64`, monotonic. Use `date +%s` for new ones.\n2. `migrations/all.go` exports `All() map[int64]migration.Migrate`. Wire with `a.Migrate(migrations.All())` once in `main.go`.\n3. Each migration is `migration.Migrate{ UP: func(d migration.Datasource) error { ... } }`. Inside `UP`, act on `d.SQL`, `d.Redis`, `d.MongoDB`, `d.Cassandra`, `d.Clickhouse`, `d.DGraph`, `d.SurrealDB`, `d.Logger`.\n4. Each migration runs **exactly once** per environment — don't add idempotent guards. There is **no down migration**; rollback = new forward migration.\n5. One purpose per file. Don't combine \"create table + backfill + drop column\" in one `UP`.\n\n## AI features: LLMs and MCP\n\nGoFr ships LLM and agent support. Use it instead of importing a provider SDK or hand-rolling HTTP, tracing and metrics\naround model calls. **Before writing this code, fetch the full guides:** <https://gofr.dev/docs/advanced-guide/llm> and\n<https://gofr.dev/docs/advanced-guide/mcp>. Runnable shape: <https://github.com/gofr-dev/gofr/tree/main/examples/using-ai>.\n\nRules to keep in your head so you don't have to re-fetch on every change:\n\n1. **Register a model once** with `app.AddLLM(&llm.Client{Provider: llm.Groq, Model: \"...\"})`\n   (`gofr.dev/pkg/gofr/ai/llm`). Providers: `llm.OpenAI`, `llm.Groq`, `llm.DeepSeek`, `llm.Together`, `llm.Ollama`;\n   set `BaseURL` for any other OpenAI-compatible endpoint. Or skip the call and set `LLM_PROVIDER`, `LLM_MODEL` and\n   `LLM_API_KEY` (optional `LLM_BASE_URL`) in `configs/.env`.\n2. **Never hardcode the API key.** It comes from `LLM_API_KEY`, then the provider's own variable (`OPENAI_API_KEY`,\n   `GROQ_API_KEY`, ...).\n3. **Call the model through `c.LLM()`**: `Generate`, `Chat`, `Stream`, `Embed`. It is already traced and metered. Extra\n   models: `app.AddLLM(m, gofr.WithName(\"fast\"))`, used as `c.LLM(\"fast\")`. Not every provider supports every method;\n   handle `ai.ErrEmbedNotSupported` / `ai.ErrStreamNotSupported` as ordinary errors.\n4. **Stream tokens** by returning `response.Stream{Source: stream}` from the handler\n   (`gofr.dev/pkg/gofr/http/response`).\n5. **Expose handlers to agents with `app.EnableMCP()`.** It serves the *read-only* handlers (`GET`, `HEAD`, `OPTIONS`,\n   `QUERY`) as MCP tools. `POST`/`PUT`/`PATCH`/`DELETE` are never exposed. Hide a route with\n   `gofr.WithExcludedRoutes(\"/internal/{id}\")`.\n6. **MCP binds to loopback on `MCP_PORT` (default `8200`).** `MCP_PORT=0` turns the transport off but keeps tools\n   available in-process. A port that cannot be claimed fails startup. `8200` is also Vault's default port.\n7. **Build agent loops in your own handler** with `c.LLM().Tools()` (`List`, `Call`, `Only`). GoFr has no built-in agent\n   loop; turns, stopping conditions and memory stay in your code.\n\n```go\npackage main\n\nimport (\n    \"gofr.dev/pkg/gofr\"\n    \"gofr.dev/pkg/gofr/ai/llm\"\n)\n\nfunc main() {\n    app := gofr.New()\n\n    app.AddLLM(&llm.Client{Provider: llm.Groq, Model: \"llama-3.3-70b-versatile\"})\n    app.EnableMCP() // exposes the GET handlers below to MCP clients\n\n    app.GET(\"/products/{id}\", func(c *gofr.Context) (any, error) {\n        return map[string]any{\"id\": c.PathParam(\"id\")}, nil\n    })\n\n    app.POST(\"/summarize\", func(c *gofr.Context) (any, error) {\n        var in struct {\n            Text string `json:\"text\"`\n        }\n        if err := c.Bind(&in); err != nil {\n            return nil, err\n        }\n\n        return c.LLM().Generate(c, \"Summarize the following:\\n\"+in.Text)\n    })\n\n    app.Run()\n}\n```\n\n## Where to look (fetch only what you need)\n\nEach link is a self-contained doc page. Fetch lazily.\n\n- Quick start: <https://gofr.dev/docs/quick-start/introduction>\n- Configuration: <https://gofr.dev/docs/quick-start/configuration>\n- Routing + REST handlers: <https://gofr.dev/docs/quick-start/add-rest-handlers>\n- Context reference (the central abstraction): <https://gofr.dev/docs/references/context>\n- Configs reference (every env var): <https://gofr.dev/docs/references/configs>\n- Testing patterns + mocks: <https://gofr.dev/docs/references/testing>\n- Observability (auto-wired): <https://gofr.dev/docs/quick-start/observability>\n- Custom OTel spans: <https://gofr.dev/docs/advanced-guide/custom-spans-in-tracing>\n- Custom Prometheus metrics: <https://gofr.dev/docs/advanced-guide/publishing-custom-metrics>\n- Datasources index (MySQL, Postgres, Mongo, Redis, Cassandra, ClickHouse, etc.): <https://gofr.dev/docs/datasources/getting-started>\n- Pub/Sub (Kafka, NATS, GCP, MQTT, SQS, Azure): <https://gofr.dev/docs/advanced-guide/using-publisher-subscriber>\n- gRPC: <https://gofr.dev/docs/advanced-guide/grpc>\n- GraphQL: <https://gofr.dev/docs/advanced-guide/graphql>\n- WebSockets: <https://gofr.dev/docs/advanced-guide/websocket>\n- Cron: <https://gofr.dev/docs/advanced-guide/using-cron>\n- Service-to-service HTTP w/ circuit breaker: <https://gofr.dev/docs/advanced-guide/http-communication>\n- Auth (Basic / API key / OAuth-JWT): <https://gofr.dev/docs/advanced-guide/authentication>\n- RBAC (config-driven): <https://gofr.dev/docs/advanced-guide/rbac>\n- Migrations (SQL + NoSQL, versioned): <https://gofr.dev/docs/advanced-guide/handling-data-migrations>\n- File storage (local / S3 / GCS / Azure / FTP / SFTP): <https://gofr.dev/docs/advanced-guide/handling-file>\n- Startup hooks: <https://gofr.dev/docs/advanced-guide/startup-hooks>\n- Errors: <https://gofr.dev/docs/advanced-guide/gofr-errors>\n- Custom DB drivers: <https://gofr.dev/docs/advanced-guide/injecting-databases-drivers>\n- Calling LLMs (`app.AddLLM`, `c.LLM()`, env config, multiple models, embeddings): <https://gofr.dev/docs/advanced-guide/llm>\n- MCP server and agent loops (`app.EnableMCP`, `c.LLM().Tools()`): <https://gofr.dev/docs/advanced-guide/mcp>\n- Streaming responses (SSE / NDJSON, `response.Stream`): <https://gofr.dev/docs/advanced-guide/streaming>\n\n## Migrating to GoFr\n\nEach migration page has the full mapping table for that source framework — fetch only the one that matches:\n\n- From Gin: <https://gofr.dev/migrate/from-gin>\n- From Fiber: <https://gofr.dev/migrate/from-fiber>\n- From Echo: handler shape similar to Gin; see <https://gofr.dev/comparison/gofr-vs-echo>\n- From Chi: see <https://gofr.dev/comparison/gofr-vs-chi>\n- From Express (Node.js): <https://gofr.dev/migrate/from-express>\n- From Flask (Python): <https://gofr.dev/migrate/from-flask>\n- From Spring Boot (Java): <https://gofr.dev/migrate/from-spring-boot>\n\n## Other entry points\n\n- Examples (runnable projects): <https://github.com/gofr-dev/gofr/tree/main/examples>\n- Full docs index: <https://gofr.dev/docs>\n- Concatenated full docs (one plaintext file): <https://gofr.dev/llms-full.txt>\n- Curated link index: <https://gofr.dev/llms.txt>\n- Changelog: <https://gofr.dev/changelog>\n","docs/references/configs/page.md":"---\ndescription: \"Reference of every GoFr configuration variable, grouped by category: HTTP, gRPC, datasources, observability, auth, and more — with defaults and value formats.\"\nnextjs:\n  metadata:\n    title: \"GoFr Configuration Reference — Env Vars and Defaults\"\n    description: \"Reference of every GoFr configuration variable, grouped by category: HTTP, gRPC, datasources, observability, auth, and more — with defaults and value formats.\"\n---\n\n# GoFr Configuration Options\n\nThis document lists all the configuration options supported by the GoFr framework. The configurations are grouped by category for better organization.\n\n## App\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  APP_NAME\n-  Name of the application. It is also the `service.name` on the resource attached to exported traces and metrics; OTEL_SERVICE_NAME and a service.name= entry in OTEL_RESOURCE_ATTRIBUTES are ignored.\n-  gofr-app\n\n---\n\n-  APP_ENV\n-  Name of the environment file to use (e.g., stage.env, prod.env, or local.env).\n\n---\n\n-  APP_VERSION\n-  Application version\n-  dev\n\n---\n\n-  LOG_LEVEL\n-  Level of verbosity for application logs. Supported values are **DEBUG, INFO, NOTICE, WARN, ERROR, FATAL**\n-  INFO\n\n---\n\n-  REMOTE_LOG_URL\n-  URL to remotely change the log level\n\n---\n\n-  REMOTE_LOG_FETCH_INTERVAL\n-  Time interval (in seconds) to check for remote log level updates\n-  15\n\n---\n\n-  METRICS_PORT\n-  Port on which the application exposes the Prometheus pull endpoint. Set to 0 to disable it (e.g. push-only serverless).\n-  2121\n\n---\n\n-  METRICS_EXPORTER\n-  Enables push-based metrics export alongside the pull endpoint. Supported values: otlp, gcp. Unset (or prometheus) keeps pull-only behavior.\n\n---\n\n-  METRICS_URL\n-  Endpoint of the OTLP metrics collector/backend. host:port for gRPC, full URL for HTTP. Required when METRICS_EXPORTER is otlp (gcp defaults to telemetry.googleapis.com:443).\n\n---\n\n-  METRICS_PROTOCOL\n-  OTLP transport for pushed metrics. Supported values: grpc, http.\n-  grpc\n\n---\n\n-  METRICS_EXPORT_INTERVAL\n-  Interval (in seconds) at which metrics are pushed to the collector/backend.\n-  30\n\n---\n\n-  METRICS_TEMPORALITY\n-  OTLP temporality preference. Supported values: cumulative, delta, lowmemory. Use delta for Datadog; cumulative for Prometheus/GMP/Grafana.\n-  cumulative\n\n---\n\n-  METRICS_HEADERS\n-  Custom headers for metric export requests in comma-separated key=value format (e.g., \"dd-api-key=secret\"). Takes priority over METRICS_AUTH_KEY.\n\n---\n\n-  METRICS_AUTH_KEY\n-  Authorization header value for metric export requests. Used when METRICS_HEADERS is unset.\n\n---\n\n-  METRICS_INSECURE\n-  Disables transport security for the OTLP metrics connection. Set to false for managed backends over TLS. Ignored by the gcp exporter (always TLS).\n-  true\n\n---\n\n-  METRICS_CARDINALITY_LIMIT\n-  Per-instrument attribute-set limit, inclusive of the overflow slot: an instrument keeps up to one fewer than this many distinct label sets per collection cycle, and the remaining series collapse into a single otel.metric.overflow series (so a value of n keeps n-1 real label sets). Set 0 or negative for unlimited. When unset, the OpenTelemetry SDK default applies (2000, or OTEL_GO_X_CARDINALITY_LIMIT if set); a set value takes precedence over OTEL_GO_X_CARDINALITY_LIMIT. HTTP metrics give requests that match no route (and unknown methods) at most a quarter of this limit, capped at 500 distinct (path, method, status) label sets; past that they are recorded as `__unmatched__` / `__other__`, so scanner traffic cannot push real routes into the overflow series.\n-  2000\n\n---\n\n-  OTEL_RESOURCE_ATTRIBUTES\n-  Standard OpenTelemetry resource attributes, comma-separated key=value. Merged into the resource attached to every exported metric and span, except service.name, which comes from APP_NAME (a service.name= entry is ignored with a warning), and framework_version, which cannot be overridden. Required for the gcp exporter outside Google Cloud: its ingest rejects any point whose prometheus_target has no location (e.g. \"location=us-central1\").\n\n---\n\n-  OTEL_SERVICE_NAME\n-  Standard OpenTelemetry service name. Ignored: GoFr sets service.name on exported traces and metrics from APP_NAME, and logs a warning at startup when this is set to a different value. Tracing and metrics each log it, so with both enabled the warning appears twice, once prefixed \"traces:\" and once \"metrics:\". Set APP_NAME to rename the service.\n\n---\n\n-  HTTP_PORT\n-  Port on which the HTTP server listens\n-  8000\n\n---\n\n-  GRPC_PORT\n-  Port on which the gRPC server listens\n-  9000\n\n---\n\n-  MCP_PORT\n-  Port on which the MCP server listens, bound to loopback. Only used when `app.EnableMCP()` is called; a port that cannot be claimed fails startup. Set to `0` to keep tools available in-process while serving no MCP transport. A non-numeric or out-of-range value refuses startup. Note the default collides with Vault's — see [MCP](/docs/advanced-guide/mcp).\n-  8200\n\n---\n\n-  TRACE_EXPORTER\n-  Tracing exporter to use. Supported values: gofr, zipkin, jaeger, otlp, gcp. `gcp` exports directly to Google Cloud's Telemetry (OTLP) API using Application Default Credentials, and requires the blank import `_ \"gofr.dev/pkg/gofr/traces/exporters/gcp\"`.\n\n---\n\n-  TRACER_HOST\n-  Hostname of the tracing collector. Required if TRACE_EXPORTER is set to zipkin or jaeger.\n-  **DEPRECATED**\n\n---\n\n-  TRACER_PORT\n-  Port of the tracing collector. Required if TRACE_EXPORTER is set to zipkin or jaeger.\n-  9411\n-  **DEPRECATED**\n\n---\n\n-  TRACER_URL\n-  URL of the trace collector. Required if TRACE_EXPORTER is set to zipkin, jaeger or otlp; optional for gcp, which defaults to `telemetry.googleapis.com:443`. For zipkin, jaeger and otlp an `http://` or `https://` scheme selects the transport, and a schemeless `host:port` is governed by TRACER_INSECURE. For gcp the value must be a schemeless `host:port` — that destination is always TLS on 443, so a scheme is rejected at startup rather than interpreted.\n\n---\n\n-  TRACER_INSECURE\n-  Whether a schemeless TRACER_URL (`host:port`) is exported over plaintext. Set to `false` to use TLS with the system root CAs. Ignored when TRACER_URL carries an `http://` or `https://` scheme, which selects the transport itself. Takes precedence over the OTel standard OTEL_EXPORTER_OTLP_INSECURE / OTEL_EXPORTER_OTLP_TRACES_INSECURE. Supported for otlp, jaeger.\n-  true\n\n---\n\n-  TRACER_RATIO\n-  Refers to the proportion of traces that are exported through sampling. It is optional configuration. By default, this ratio is set to 1. A value that is not a valid number is rejected with an error log and also resolves to 1, so a typo over-samples rather than silently disabling tracing.\n\n---\n\n-  TRACER_AUTH_KEY\n-  Authorization header for trace exporter requests. Supported for zipkin, jaeger, otlp.\n\n---\n\n-  TRACER_HEADERS\n-  Custom authentication headers for trace exporter requests in comma-separated key=value format (e.g., \"X-Api-Key=secret,Authorization=Bearer token\"). Supported for zipkin, jaeger, otlp. Takes priority over TRACER_AUTH_KEY.\n\n---\n\n-  CMD_LOGS_FILE\n-  File to save the logs in case of a CMD application\n\n---\n\n-  SHUTDOWN_GRACE_PERIOD\n-  Timeout duration for server shutdown process\n-  30s\n\n---\n\n-  GOFR_TELEMETRY\n-  Enable telemetry for GoFr framework usage\n-  true\n\n---\n\n-  GOFR_ROUTER\n-  Route matcher for the HTTP server. Set to `trie` to opt into the O(path length) trie index instead of the default linear scan — see [Routing Performance](/docs/advanced-guide/routing-performance). Any other value falls back to `mux`.\n-  mux\n\n---\n\n-  GOFR_RBAC_ROUTE_CHECK\n-  What the startup check does when the RBAC config and the registered routes disagree — see [Startup Route Check](/docs/advanced-guide/rbac#startup-route-check). `warn` logs each mismatch as an error and keeps starting, `fail` logs them and stops startup with exit status 1, `off` skips the check. Any other value is logged as an error and treated as `warn`.\n-  warn\n\n---\n\n-  LOG_DISABLE_PROBES\n-  Disable log probes for health checks\n-  false\n\n---\n\n-  GRPC_ENABLE_REFLECTION\n-  Enable gRPC server reflection\n-  false\n\n---\n\n-  HEALTH_CACHE_TTL\n-  How long a health result may be served without re-checking the backends, as a duration (`5s`, `10s`, `1m`). Unset, `0` or `disabled` turns caching off, which is the default: within a TTL a recovered backend still reports DOWN and a failed one still reports UP, so it is a trade to opt into rather than inherit.\n-  disabled\n\n---\n\n-  HEALTH_CHECK_TIMEOUT\n-  Upper bound on one round of health checks, as a duration (`2s`). Backends that have not answered by then are left out of the response and the aggregate status is DEGRADED. Datasources whose health check honors its context are canceled at that deadline. Once every outstanding check has returned, the next probe checks them again. Checks that cannot be canceled keep running after the round is abandoned: the SQL, Redis and PubSub health checks take no context, and a few datasources (such as Couchbase and NATS KV) don't yet honor the one they receive. While one of those is still running, a probe reports DEGRADED with no per-dependency detail rather than starting a second round against the same unresponsive backend. Unset or `0` means the round is bounded only by each backend client's own timeout.\n-  disabled\n\n{% /table %}\n\n## HTTP\n\n{% table %}\n\n- Name\n- Description\n\n---\n\n-  REQUEST_TIMEOUT\n-  Set the request timeouts (in seconds) for HTTP server.\n\n---\n\n- CERT_FILE\n- Set the path to your PEM certificate file for the HTTPS server to establish a secure connection.\n\n--- \n\n- KEY_FILE\n- Set the path to your PEM key file for the HTTPS server to establish a secure connection.\n\n{% /table %}\n\n### CORS\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n- ACCESS_CONTROL_ALLOW_ORIGIN\n- Allowed origin(s) for cross-origin requests. Supports comma-separated values for multiple origins (e.g., `https://app.example.com,https://admin.example.com`).\n- `*`\n\n---\n\n- ACCESS_CONTROL_ALLOW_HEADERS\n- Allowed request headers for cross-origin requests.\n- Authorization, Content-Type, x-requested-with, origin, true-client-ip, X-Correlation-ID\n\n---\n\n- ACCESS_CONTROL_ALLOW_METHODS\n- Allowed HTTP methods. Automatically set from registered routes if not provided.\n\n---\n\n- ACCESS_CONTROL_ALLOW_CREDENTIALS\n- Allow credentials (cookies, HTTP authentication) in cross-origin requests.\n\n---\n\n- ACCESS_CONTROL_EXPOSE_HEADERS\n- Additional headers exposed to the client in cross-origin responses.\n\n---\n\n- ACCESS_CONTROL_MAX_AGE\n- Maximum time (in seconds) browsers can cache preflight responses.\n\n{% /table %}\n\n## Datasource\n\n### SQL\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  DB_DIALECT\n-  Database dialect. Supported values: mysql, postgres, supabase\n\n---\n\n-  DB_HOST\n-  Hostname of the database server.\n\n---\n\n-  DB_PORT\n-  Port of the database server.\n-  3306\n\n---\n\n-  DB_USER\n-  Username for the database.\n\n---\n\n-  DB_PASSWORD\n-  Password for the database.\n\n---\n\n-  DB_NAME\n-  Name of the database to use.\n\n---\n\n-  DB_MAX_IDLE_CONNECTION\n-  Number of maximum idle connection.\n-  2\n\n---\n\n-  DB_MAX_OPEN_CONNECTION\n-  Number of maximum connections which can be used with database.\n-  0 (unlimited)\n---\n\n-  DB_SSL_MODE\n-  TLS/SSL mode for database connections. Supported modes: **disable** (no TLS), **preferred** (attempts TLS, falls back to plain), **require** (enforces TLS, skips validation), **skip-verify** (enforces TLS, no certificate validation), **verify-ca** (enforces TLS, validates certificate against CA), **verify-full** (enforces TLS with full validation including hostname). Currently supported for MySQL/MariaDB and PostgreSQL.\n-  disable\n\n---\n\n- DB_TLS_CA_CERT\n- Path to CA certificate file for TLS connections. Required for **verify-ca** and **verify-full** SSL modes.\n- None\n\n---\n\n- DB_TLS_CLIENT_CERT\n- Path to client certificate file for mutual TLS authentication.\n- None\n\n---\n\n- DB_TLS_CLIENT_KEY\n- Path to client private key file for mutual TLS authentication.\n- None\n\n---\n\n- DB_REPLICA_HOSTS\n- Comma-separated list of replica database hosts. Used for read replicas.\n- None\n\n---\n\n- DB_REPLICA_PORTS\n- Comma-separated list of replica database ports. Used for read replicas.\n- None\n\n---\n\n- DB_REPLICA_USERS\n- Comma-separated list of replica database users. Used for read replicas.\n- None\n\n---\n\n- DB_REPLICA_PASSWORDS\n- Comma-separated list of replica database passwords. Used for read replicas.\n- None\n\n---\n\n- DB_REPLICA_MAX_IDLE_CONNECTIONS\n- Maximum idle connections allowed for a replica\n- 50\n\n---\n\n- DB_REPLICA_MIN_IDLE_CONNECTIONS\n- Minimum idle connections for a replica\n- 10\n\n---\n\n- DB_REPLICA_DEFAULT_IDLE_CONNECTIONS\n- Idle connections used if no primary setting is provided\n- 10\n\n---\n\n- DB_REPLICA_MAX_OPEN_CONNECTIONS\n- Maximum open connections allowed for a replica\n- 200\n\n---\n\n- DB_REPLICA_MIN_OPEN_CONNECTIONS\n- Minimum open connections for a replica\n- 50\n\n---\n\n- DB_REPLICA_DEFAULT_OPEN_CONNECTIONS\n- Open connections used if no primary setting is provided\n- 100\n\n---\n\n\n- DB_CHARSET\n- The character set for database connection\n- utf8\n\n---\n\n- SUPABASE_CONNECTION_TYPE \n- Connection type to Supabase. Supported values: direct, session, transaction \n- direct\n\n---\n\n- SUPABASE_PROJECT_REF \n- Supabase project reference ID\n\n---\n\n- SUPABASE_REGION \n- Supabase region for pooled connections\n\n---\n\n- DB_URL \n- Full PostgreSQL connection string for Supabase (alternative to separate config parameters)\n\n{% /table %}\n\n### Redis\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  REDIS_HOST\n-  Hostname of the Redis server.\n-  localhost\n\n---\n\n-  REDIS_PORT\n-  Port of the Redis server.\n-  6379\n\n---\n\n- REDIS_USER\n- Username for the Redis server (optional).\n-  \"\"\n\n---\n\n- REDIS_PASSWORD\n- Password for the Redis server (optional).\n-  \"\"\n\n---\n\n- REDIS_DB\n- Database number to use for the Redis server.\n-  0\n\n---\n\n- REDIS_TLS_ENABLED\n- Enable TLS for Redis connections.\n-  false\n\n---\n\n- REDIS_TLS_CA_CERT\n- Path to the TLS CA certificate file for Redis (or PEM-encoded string).\n-  \"\"\n\n---\n\n- REDIS_TLS_CERT\n- Path to the TLS certificate file for Redis (or PEM-encoded string).\n-  \"\"\n\n---\n\n- REDIS_TLS_KEY\n- Path to the TLS key file for Redis (or PEM-encoded string).\n-  \"\"\n\n{% /table %}\n\n**Redis PubSub Configuration:**\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n- REDIS_PUBSUB_DB\n- Redis database number to use only for Redis Pub/Sub (when `PUBSUB_BACKEND=REDIS`). Use a different DB than `REDIS_DB` when running GoFr migrations with Redis Streams mode to avoid `gofr_migrations` key-type collisions.\n- Default: `15` (highest default Redis database, 0-15)\n\n---\n\n- REDIS_PUBSUB_MODE\n- Operation mode: `pubsub` or `streams`.\n- streams\n\n---\n\n- REDIS_STREAMS_CONSUMER_GROUP\n- Consumer group name (required for streams mode).\n-  \"\"\n\n---\n\n- REDIS_STREAMS_CONSUMER_NAME\n- Unique consumer name (optional, auto-generated if empty).\n-  \"\"\n\n---\n\n- REDIS_STREAMS_BLOCK_TIMEOUT\n- Blocking duration for reading new messages using Redis `XREADGROUP`. Lower values (1s-2s) provide faster detection but increase CPU usage. Higher values (10s-30s) reduce CPU usage, ideal for batch processing.\n- 5s\n\n---\n\n- REDIS_STREAMS_PEL_RATIO\n- Ratio of PEL (pending) messages to read vs new messages (0.0-1.0). Controls balance between retry and fresh messages. 0.7 = 70% PEL, 30% new.\n- 0.7\n\n---\n\n- REDIS_STREAMS_MAXLEN\n- Maximum length of the stream (approximate). Prevents streams from growing indefinitely. Set to `0` for unlimited.\n- 0 (unlimited)\n\n{% /table %}\n\n> **Note**: When using GoFr migrations with Streams mode, keep `REDIS_DB` and `REDIS_PUBSUB_DB` separate (defaults: 0 and 15). For `REDIS_STREAMS_BLOCK_TIMEOUT`: use 1s-2s for real-time or 10s-30s for batch processing.\n\n### Pub/Sub\n\n{% table %}\n\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  PUBSUB_BACKEND\n-  Pub/Sub message broker backend wired automatically by `gofr.New()`. Accepted values: `kafka`, `google`, `mqtt`, `redis` (case-insensitive). Other backends (NATS JetStream, AWS SQS, Azure Event Hub) are wired explicitly via `app.AddPubSub(...)`.\n-  \n\n{% /table %}\n\n**Kafka**\n\n{% table %}\n\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  PUBSUB_BROKER\n-  Comma-separated list of broker addresses\n-  localhost:9092\n\n---\n\n-  PARTITION_SIZE\n-  Size of each message partition (in bytes)\n-  0\n\n---\n\n-  PUBSUB_OFFSET\n-  Offset to start consuming messages from. -1 for earliest, 0 for latest.\n-  -1\n\n---\n\n- KAFKA_BATCH_SIZE\n- Number of messages to batch before sending to Kafka\n- 1\n\n---\n\n- KAFKA_BATCH_BYTES\n- Number of bytes to batch before sending to Kafka\n- 1048576\n\n---\n\n- KAFKA_BATCH_TIMEOUT\n- Time to wait before sending a batch to Kafka\n- 100ms\n\n---\n\n-  CONSUMER_ID\n-  Unique identifier for this consumer\n-  gofr-consumer\n\n---\n\n---\n\n- KAFKA_SECURITY_PROTOCOL\n- Security protocol used to communicate with Kafka (e.g., PLAINTEXT, SSL, SASL_PLAINTEXT, SASL_SSL)\n- PLAINTEXT\n\n---\n\n\n- KAFKA_SASL_MECHANISM\n- SASL mechanism for authentication (e.g. PLAIN, SCRAM-SHA-256, SCRAM-SHA-512)\n- None\n\n---\n\n- KAFKA_SASL_USERNAME\n- Username for SASL authentication\n- None\n\n---\n\n- KAFKA_SASL_PASSWORD\n- Password for SASL authentication\n- None\n\n---\n\n- KAFKA_TLS_CERT_FILE\n- Path to the TLS certificate file\n- None\n\n---\n\n- KAFKA_TLS_KEY_FILE\n- Path to the TLS key file\n- None\n\n---\n\n- KAFKA_TLS_CA_CERT_FILE\n- Path to the TLS CA certificate file\n- None\n\n---\n\n- KAFKA_TLS_INSECURE_SKIP_VERIFY\n- Skip TLS certificate verification\n- false\n\n{% /table %}\n\n**Google**\n\n{% table %}\n\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  GOOGLE_PROJECT_ID\n-  ID of the Google Cloud project. Required for Google Pub/Sub.\n-  None\n\n---\n\n-  GOOGLE_SUBSCRIPTION_NAME\n-  Name of the Google Pub/Sub subscription. Required for Google Pub/Sub.\n-  None\n\n---\n\n-  GOOGLE_MAX_OUTSTANDING_MESSAGES\n-  Max messages the client holds waiting for delivery to the handler, per subscribed topic (the memory/goroutine bound, not the handler concurrency). 0 uses the default; a negative value means no limit.\n-  1000\n\n---\n\n-  GOOGLE_MAX_OUTSTANDING_BYTES\n-  Max total size (bytes) of messages held waiting for delivery, per subscribed topic. 0 uses the default; a negative value means no limit.\n-  1000000000\n\n---\n\n-  GOOGLE_NUM_GOROUTINES\n-  Number of StreamingPull streams opened by the subscriber, per subscribed topic. It is the stream count, not handler concurrency, and does not raise throughput under GoFr's one-message-at-a-time delivery. 0 or a negative value uses the default.\n-  10\n\n{% /table %}\n\n**MQTT**\n\n{% table %}\n\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  MQTT_PORT\n-  Port of the MQTT broker\n-  1883\n\n---\n\n-  MQTT_MESSAGE_ORDER\n-  Enable guaranteed message order\n-  false\n\n---\n\n-  MQTT_PROTOCOL\n-  Communication protocol. Supported values: tcp, ssl.\n-  tcp\n\n---\n\n-  MQTT_HOST\n-  Hostname of the MQTT broker\n-  localhost\n\n---\n\n-  MQTT_USER\n-  Username for the MQTT broker\n\n---\n\n-  MQTT_PASSWORD\n-  Password for the MQTT broker\n\n---\n\n-  MQTT_CLIENT_ID_SUFFIX\n-  Suffix appended to the client ID\n\n---\n\n-  MQTT_QOS\n-  Quality of Service Level\n\n---\n\n-  MQTT_KEEP_ALIVE\n-  Sends regular messages to check the link is active. May not work as expected if handling func is blocking execution\n\n- MQTT_RETRIEVE_RETAINED\n- Retrieve retained messages on subscription\n\n{% /table %}\n\n**NATS JetStream**\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  NATS_SERVER\n-  URL of the NATS server. The NATS driver is wired explicitly via `app.AddPubSub(...)`; this row is a convention only — the actual env-var name is whatever you read from `app.Config.Get(...)` and pass into `nats.Config.Server`.\n-  nats://localhost:4222\n\n---\n\n-  NATS_CREDS_FILE\n-  File containing the NATS credentials\n- creds.json\n\n{% /table %}\n\n\n\n## Related production guides\n\n- **12-Factor Configuration**: [Env-driven config, secrets, and environment parity](/docs/guides/twelve-factor-config) — apply 12-factor methodology to the configs documented above.\n","docs/references/gofrcli/page.md":"---\ndescription: \"Use the GoFr CLI to scaffold projects, generate boilerplate, and run framework-aware tasks. Speeds up repetitive work and keeps services consistent.\"\nnextjs:\n  metadata:\n    title: \"GoFr CLI Reference — Project Scaffolding and Tooling\"\n    description: \"Use the GoFr CLI to scaffold projects, generate boilerplate, and run framework-aware tasks. Speeds up repetitive work and keeps services consistent.\"\n---\n\n# GoFR Command Line Interface\n\nManaging repetitive tasks and maintaining consistency across large-scale applications is challenging!\n\n**GoFr CLI provides the following:**\n\n* All-in-one command-line tool designed specifically for GoFr applications\n* Simplifies **database migrations** management\n* **Store Layer Generator** for type-safe data access code from YAML configurations\n* Abstracts **tracing**, **metrics** and structured **logging** for GoFr's gRPC server/client\n* Enforces standard **GoFr conventions** in new projects\n\n## Prerequisites\n\n- Go 1.25 or above. To check Go version use the following command:\n```bash\n  go version\n```\n\n## **Installation**\nTo get started with GoFr CLI, use the below commands\n\n```bash\n  go install gofr.dev/cli/gofr@latest\n```\n\nTo check the installation:\n```bash\n  gofr version\n```\n---\n\n## Usage\n\nThe CLI can be run directly from the terminal after installation. Here’s the general syntax:\n\n```bash\n  gofr <subcommand> [flags]=[arguments]\n```\n---\n\n## Commands\n\nThe CLI groups its functionality into four commands. See each subpage for full reference:\n\n- [`gofr init`](/docs/references/gofrcli/init) — initialize a new GoFr project with the standard layout.\n- [`gofr migrate`](/docs/references/gofrcli/migrate) — create database migration templates with timestamped filenames and an auto-generated registry.\n- [`gofr wrap grpc`](/docs/references/gofrcli/wrap-grpc) — generate gRPC server/client wrappers with built-in tracing, metrics, and logging.\n- [`gofr store`](/docs/references/gofrcli/store) — generate a type-safe data-access layer from YAML schema definitions.\n","docs/references/gofrcli/migrate/page.md":"---\ndescription: \"Generate timestamped database migration templates with an auto-maintained registry using the gofr migrate create command.\"\nnextjs:\n  metadata:\n    title: \"gofr migrate create — Generate Database Migration Templates\"\n    description: \"Generate timestamped database migration templates with an auto-maintained registry using the gofr migrate create command.\"\n---\n\n# gofr migrate create\n\nThe migrate create command generates a migration template file with pre-defined structure in your migrations directory.\nThis boilerplate code helps you maintain consistent patterns when writing database schema modifications across your project.\n\n\n## Command Usage\n```bash\n  gofr migrate create -name=<migration-name>\n```\n\n## Example Usage\n\n```bash\ngofr migrate create -name=create_employee_table\n```\nThis command generates a migration directory which has the below files:\n\n1. A new migration file with timestamp prefix (e.g., `20250127152047_create_employee_table.go`) containing:\n```go\npackage migrations\n\nimport (\n  \"gofr.dev/pkg/gofr/migration\"\n)\n\nfunc create_employee_table() migration.Migrate {\n  return migration.Migrate{\n    UP: func(d migration.Datasource) error {\n      // write your migrations here\n      return nil\n    },\n  }\n}\n```\n2. An auto-generated all.go file that maintains a registry of all migrations:\n```go\n// This is auto-generated file using 'gofr migrate' tool. DO NOT EDIT.\npackage migrations\n\nimport (\n  \"gofr.dev/pkg/gofr/migration\"\n)\n\nfunc All() map[int64]migration.Migrate {\n  return map[int64]migration.Migrate {\n    20250127152047: create_employee_table(),\n  }\n}\n```\n\n> **💡 Best Practice:** Learn about [organizing migrations by feature](/docs/advanced-guide/handling-data-migrations#organizing-migrations-by-feature) to avoid creating one migration per table or operation.\n\nFor detailed instructions on handling database migrations, see the [handling-data-migrations documentation](/docs/advanced-guide/handling-data-migrations)\nFor more examples, see the [using-migrations](https://github.com/gofr-dev/gofr/tree/main/examples/using-migrations)\n\n---\n\n## See also\n\n- [GoFr CLI overview](/docs/references/gofrcli)\n- [`gofr init`](/docs/references/gofrcli/init)\n- [`gofr wrap grpc`](/docs/references/gofrcli/wrap-grpc)\n- [`gofr store`](/docs/references/gofrcli/store)\n","docs/references/gofrcli/init/page.md":"---\ndescription: \"Initialize a new GoFr project with the standard layout and a Hello World starter program using the gofr init command.\"\nnextjs:\n  metadata:\n    title: \"gofr init — Initialize a New GoFr Project\"\n    description: \"Initialize a new GoFr project with the standard layout and a Hello World starter program using the gofr init command.\"\n---\n\n# gofr init\n\nThe init command initializes a new GoFr project. It sets up the foundational structure for the project and generates a basic \"Hello World!\" program as a starting point. This allows developers to quickly dive into building their application with a ready-made structure.\n\n## Command Usage\n```bash\n  gofr init\n```\n\n---\n\n## See also\n\n- [GoFr CLI overview](/docs/references/gofrcli)\n- [`gofr migrate`](/docs/references/gofrcli/migrate)\n- [`gofr wrap grpc`](/docs/references/gofrcli/wrap-grpc)\n- [`gofr store`](/docs/references/gofrcli/store)\n","docs/references/context/page.md":"---\ndescription: \"GoFr's ctx is injected into every handler. It carries request data plus the container of dependencies — DBs, logger, HTTP clients, and metrics — for the cycle.\"\nnextjs:\n  metadata:\n    title: \"GoFr Context Reference — Request Container API\"\n    description: \"GoFr's ctx is injected into every handler. It carries request data plus the container of dependencies — DBs, logger, HTTP clients, and metrics — for the cycle.\"\n---\n\n# GoFr Context\n\nGoFr context is an object injected by the GoFr handler. It contains all the request-specific data, for each\nrequest-response cycle a new context is created. The request can be either an HTTP request, gRPC call or\na message from Pub-Sub.\nGoFr Context also embeds the **_container_** which maintains all the dependencies like databases, logger, HTTP service clients,\nmetrics manager, etc. This reduces the complexity of the application as users don't have to maintain and keep track of\nall the dependencies by themselves.\n\nGoFr context is an extension of the Go context, providing a wrapper around the request and response providing\nuser access to dependencies.\n\n# Usage\n\n## Reading HTTP requests\n\n`ctx.Request` can be used to access the underlying request which provides the following methods to access different\nparts of the request.\n\n- `Context()` - to access the context associated with the incoming request\n\n```go\nctx.Request.Context()\n```\n\n- `Param(string)` - to access the query parameters present in the request, it returns the value of the key provided\n\n```go\n// Example: Request is /configs?key1=value1&key2=value2\nvalue := ctx.Request.Param(\"key1\")\n// value = \"value1\"\n```\n\n- `PathParam(string)` - to retrieve the path parameters\n  ```go\n  // Consider the path to be /employee/{id}\n  id := ctx.Request.PathParam(\"id\")\n  ```\n- `Bind(any)` - to access a decoded format of the request body, the body is mapped to the interface provided\n\n```go\n// incoming request body is\n// {\n//    \"name\" : \"trident\",\n//    \"category\" : \"snacks\"\n// }\n\ntype product struct{\n  Name string `json:\"name\"`\n  Category string `json:\"category\"`\n}\n\nvar p product\nctx.Bind(&p)\n// the Bind() method will map the incoming request to variable p\n```\n\n> **Pass a pointer.** `Bind` needs the address of your variable (`&p`) so it can write into it.\n> For an HTTP request, passing a value (`ctx.Bind(p)`) returns an error rather than silently\n> leaving your variable untouched. Always check the returned error:\n>\n> ```go\n> if err := ctx.Bind(&p); err != nil {\n>     return nil, err\n> }\n> ```\n\nThe `Content-Type` header selects how the body is decoded. It is matched case-insensitively and\nany parameters are ignored, so `application/json`, `Application/JSON` and\n`application/json; charset=utf-8` are all treated the same.\n\nIf a request carries a body whose `Content-Type` GoFr has no decoder for — `text/plain`,\n`application/xml`, or no header at all — `Bind` is a **no-op**: it returns no error and leaves\nyour target zeroed, and the body is discarded. Check the `Content-Type` your clients actually\nsend. `fetch(url, {method: \"POST\", body: str})` with no headers sends `text/plain`, not JSON, so\na request that looks correct can bind nothing.\n\n- `Binding multipart-form data / urlencoded form data `\n  - To bind multipart-form data or url-encoded form, we can use the Bind method similarly. The struct fields should be tagged appropriately\n    to map the form fields to the struct fields. The supported content types are `multipart/form-data` and `application/x-www-form-urlencoded`\n\n```go\ntype Data struct {\n\tName string `form:\"name\"`\n\n\tCompressed file.Zip `file:\"upload\"`\n\n\tFileHeader *multipart.FileHeader `file:\"file_upload\"`\n}\n```\n\n  - The `form` tag is used to bind non-file fields.\n  - The `file` tag is used to bind file fields. If the tag is not present, the field name is used as the key.\n\n\n- `HostName()` - to access the host name for the incoming request\n\n```go\n// for example if request is made from xyz.com\n  host := ctx.Request.HostName()\n  // the host would be http://xyz.com\n  // Note: the protocol if not provided in the headers will be set to http by default\n```\n\n- `Params(string)` - to access all query parameters for a given key returning slice of strings.\n\n```go\n// Example: Request is /search?category=books,electronics&category=tech\nvalues := ctx.Request.Params(\"category\")\n// values = []string{\"books\", \"electronics\", \"tech\"}\n```\n\n\n## Accessing Authentication Information\n\nGoFr provides a helper method to access authentication details from the context.\nThese values are populated when the respective authentication middleware is enabled (see [HTTP Auth Middleware](https://github.com/gofr-dev/gofr/blob/0845d19181d2cc55e12c557fc9ad51adb4ab44fd/examples/using-http-auth-middleware/ReadMe.md) section).\n\n```go\ninfo := ctx.GetAuthInfo()\n```\n\n### Methods\n\n* **`GetClaims()`** – Returns the JWT claims containing standard fields such as:\n\n  * `Issuer` – identifies who issued the token.\n  * `Subject` – identifies the principal that is the subject of the token.\n  * `Audience` – identifies the intended recipients of the token.\n  * `NotBefore` – time before which the token is not valid.\n  * `IssuedAt` – time at which the token was issued.\n  * `ExpirationTime` – time after which the token expires.\n\n  **Requires:** OAuth middleware (`EnableOAuth`)\n\n* **`GetUsername()`** – Returns the authenticated username when using Basic Authentication.\n\n  **Requires:** Basic Auth middleware (`EnableBasicAuthWithValidator`)\n\n* **`GetAPIKey()`** – Returns the API key used for authentication.\n\n  **Requires:** API Key middleware (`EnableAPIKeyAuthWithValidator`)\n\n> Note: These values will be available only if the respective authentication middleware is enabled in the application.\n\n\n## Accessing dependencies\n\nGoFr context embeds the container object which provides access to\nall the injected dependencies by the users. Users can access the fields and methods provided\nby the **_container_**.\n","docs/references/gofrcli/store/page.md":"---\ndescription: \"Generate a type-safe data-access layer from YAML schema definitions using the gofr store command, with built-in observability and registry support.\"\nnextjs:\n  metadata:\n    title: \"gofr store — Generate Type-Safe Data-Access Layers from YAML\"\n    description: \"Generate a type-safe data-access layer from YAML schema definitions using the gofr store command, with built-in observability and registry support.\"\n---\n\n# gofr store\n\n> **Available since:** `gofr-cli` **v0.8.1**\n\nThe `gofr store` command is a code generator that creates type-safe data access layers from YAML configuration files. It eliminates boilerplate code while maintaining GoFr's best practices for observability and context management.\n\n## **Features**\n\n* **YAML-Driven Configuration**: Define your data models and queries in a simple, declarative format.\n* **Type-Safe Code Generation**: Generates Go interfaces and implementation boilerplates.\n* **GoFr Context Integration**: Generated methods work with `*gofr.Context` for built-in observability.\n* **Multiple Stores**: Define all stores in a single YAML file — each gets its own directory.\n* **Store Registry**: Centralized factory management of all generated stores via `stores/all.go`.\n\n## **Commands**\n\n### **Initialize Store Configuration**\n\nCreate a new store directory and a `store.yaml` configuration template. **The `-name` flag is required.**\n\n```bash\ngofr store init -name=<store-name>\n```\n\n**Example:**\n```bash\ngofr store init -name=user\n```\n\nThis creates the following structure:\n- `stores/store.yaml` — Configuration file template (shared across all stores).\n- `stores/all.go` — Store registry factory (auto-generated, DO NOT EDIT).\n- `stores/user/interface.go` — Initial interface stub (DO NOT EDIT — regenerated by `generate`).\n- `stores/user/user.go` — Initial implementation stub (editable — add your SQL logic here).\n\n### **Generate Store Code**\n\nGenerate or update Go code from your store configuration file.\n\n```bash\ngofr store generate\n```\n\n> **💡 Note:** By default, this command looks for the configuration at **`stores/store.yaml`**. To use a different path, use the `-config` flag:\n> ```bash\n> gofr store generate -config=path/to/store.yaml\n> ```\n\n---\n\n## **Quick Start Example**\n\n**Step 1: Initialize Configuration**\n```bash\ngofr store init -name=user\n```\n\n**Step 2: Define Your Store in `stores/store.yaml`**\n```yaml\nversion: \"1.0\"\n\nstores:\n  - name: \"user\"\n    package: \"user\"\n    output_dir: \"stores/user\"\n    interface: \"UserStore\"\n    implementation: \"userStore\"\n    queries:\n      - name: \"GetUserByID\"\n        sql: \"SELECT id, name, email FROM users WHERE id = ?\"\n        type: \"select\"\n        model: \"User\"\n        returns: \"single\"\n        params:\n          - name: \"id\"\n            type: \"int64\"\n        description: \"Retrieves a user by their ID\"\n\n      - name: \"GetAllUsers\"\n        sql: \"SELECT id, name, email FROM users\"\n        type: \"select\"\n        model: \"User\"\n        returns: \"multiple\"\n        description: \"Retrieves all users\"\n\nmodels:\n  - name: \"User\"\n    fields:\n      - name: \"ID\"\n        type: \"int64\"\n        tag: 'db:\"id\" json:\"id\"'\n      - name: \"Name\"\n        type: \"string\"\n        tag: 'db:\"name\" json:\"name\"'\n      - name: \"Email\"\n        type: \"string\"\n        tag: 'db:\"email\" json:\"email\"'\n```\n\n**Step 3: Generate Store Code**\n```bash\ngofr store generate\n```\n\nThis generates:\n```text\nstores/\n├── store.yaml          # Central Configuration\n├── all.go              # Store registry factory (auto-generated)\n└── user/\n    ├── interface.go    # UserStore interface definition\n    ├── userStore.go    # userStore implementation boilerplate\n    └── user.go         # User model struct\n```\n\n**Step 4: Use in Your Application**\n```go\npackage main\n\nimport (\n    \"gofr.dev/pkg/gofr\"\n    \"your-project/stores/user\"\n)\n\nfunc main() {\n    app := gofr.New()\n\n    userStore := user.NewUserStore()\n\n    app.GET(\"/users/{id}\", func(ctx *gofr.Context) (interface{}, error) {\n        id, _ := strconv.ParseInt(ctx.PathParam(\"id\"), 10, 64)\n        return userStore.GetUserByID(ctx, id)\n    })\n\n    app.GET(\"/users\", func(ctx *gofr.Context) (interface{}, error) {\n        return userStore.GetAllUsers(ctx)\n    })\n\n    app.Run()\n}\n```\n\n---\n\n## **Multiple Stores in One File**\n\nYou can define all stores in a single YAML file. Each store gets its own output directory and all are registered into the same `stores/all.go` registry.\n\n```yaml\nversion: \"1.0\"\n\nstores:\n  - name: \"user\"\n    package: \"user\"\n    output_dir: \"stores/user\"\n    interface: \"UserStore\"\n    implementation: \"userStore\"\n    queries: [...]\n\n  - name: \"product\"\n    package: \"product\"\n    output_dir: \"stores/product\"\n    interface: \"ProductStore\"\n    implementation: \"productStore\"\n    queries: [...]\n\nmodels:\n  - name: \"User\"\n    fields: [...]\n  - name: \"Product\"\n    fields: [...]\n```\n\n**Generated structure:**\n```text\nstores/\n├── all.go\n├── user/\n│   ├── interface.go\n│   ├── userStore.go\n│   └── user.go\n└── product/\n    ├── interface.go\n    ├── productStore.go\n    └── product.go\n```\n\n**Using the registry with multiple stores:**\n```go\nimport (\n\"your-project/stores\"\n\"your-project/stores/user\"\n\"your-project/stores/product\"\n)\n\n// stores.GetStore returns a factory-created instance\nuserStore    := stores.GetStore(\"user\").(user.UserStore)\nproductStore := stores.GetStore(\"product\").(product.ProductStore)\n```\n\n> **💡 Note:** `stores.All()` returns a `map[string]func() any` — a map of **factory functions**, not active instances. `stores.GetStore(name)` calls the factory for you and returns the instance.\n\n---\n\n## **Configuration Reference**\n\n### **Store Configuration**\n\n| Field | Description | Required |\n|-------|-------------|----------|\n| `name` | Store identifier used in the registry key. | **Yes** |\n| `package` | Go package name for generated code. | **Yes** |\n| `output_dir` | Directory path where files will be generated. | Optional (defaults to `stores/<name>`) |\n| `interface` | Interface name — **recommended: `<Name>Store`** (e.g., `UserStore`). | Optional (defaults to `<Name>Store`) |\n| `implementation` | Private struct name for the implementation (e.g., `userStore`). | Optional (defaults to `<name>Store`) |\n| `queries` | List of database queries. | Optional |\n\n> **⚠️ Naming Convention:** The registry (`stores/all.go`) uses a hardcoded `<Name>Store` pattern when generating constructor calls (e.g., `NewUserStore()`). Always name your interface as `<Name>Store` to avoid compilation errors.\n\n### **Query Types**\n\n* **`select`** — SELECT queries.\n* **`insert`** — INSERT queries.\n* **`update`** — UPDATE queries.\n* **`delete`** — DELETE queries.\n\n### **Return Types**\n\n* **`single`** — Returns `(Model, error)`.\n* **`multiple`** — Returns `([]Model, error)`.\n* **`count`** — Returns `(int64, error)`.\n* **`custom`** — Returns `(any, error)`.\n\n### **Query Parameters**\n\n```yaml\nparams:\n  - name: \"id\"\n    type: \"int64\"\n  - name: \"email\"\n    type: \"string\"\n```\n\nSupported parameter types include all Go primitive types, `time.Time`, and pointer types (e.g., `*int64`).\n\n---\n\n## **Model Generation**\n\n### **Generate New Models**\n\n```yaml\nmodels:\n  - name: \"User\"\n    fields:\n      - name: \"ID\"\n        type: \"int64\"\n        tag: 'db:\"id\" json:\"id\"'\n      - name: \"Name\"\n        type: \"string\"\n        tag: 'db:\"name\" json:\"name\"'\n      - name: \"CreatedAt\"\n        type: \"time.Time\"\n        tag: 'db:\"created_at\" json:\"created_at\"'\n```\n\nThis generates:\n```go\ntype User struct {\nID        int64     `db:\"id\" json:\"id\"`\nName      string    `db:\"name\" json:\"name\"`\nCreatedAt time.Time `db:\"created_at\" json:\"created_at\"`\n}\n\nfunc (User) TableName() string {\nreturn \"user\"\n}\n```\n\n### **Reference Existing Models**\n\nIf you already have models defined elsewhere:\n\n```yaml\nmodels:\n  - name: \"User\"\n    path: \"../models/user.go\"\n    package: \"your-project/models\"\n```\n\n---\n\n## **Generated Code Structure**\n\n### **Interface (`interface.go`)**\n\n```go\n// Code generated by gofr.dev/cli/gofr. DO NOT EDIT.\npackage user\n\nimport \"gofr.dev/pkg/gofr\"\n\ntype UserStore interface {\n  GetUserByID(ctx *gofr.Context, id int64) (User, error)\n  GetAllUsers(ctx *gofr.Context) ([]User, error)\n}\n```\n\n### **Implementation (`userStore.go`)**\n\n```go\n// Code generated by gofr.dev/cli/gofr. DO NOT EDIT.\npackage user\n\ntype userStore struct{}\n\nfunc NewUserStore() UserStore {\n   return &userStore{}\n}\n\nfunc (s *userStore) GetUserByID(ctx *gofr.Context, id int64) (User, error) {\n   // TODO: Implement using ctx.SQL()\n   var result User\n   // err := ctx.SQL().QueryRowContext(ctx, sql, id).Scan(&result.ID, ...)\n   return result, nil\n}\n\nfunc (s *userStore) GetAllUsers(ctx *gofr.Context) ([]User, error) {\n   // TODO: Implement using ctx.SQL()\n   return []User{}, nil\n}\n```\n\n---\n\n## **Best Practices**\n\n1. **Implement the TODOs**: The generator creates method **signatures and boilerplate only**. You must fill in the `// TODO: Implement` sections with actual SQL execution using `ctx.SQL()` methods.\n2. **Use `<Name>Store` Interface Names**: The registry assumes this convention. E.g., `interface: \"UserStore\"` results in the constructor `NewUserStore()` and type assertion `.(user.UserStore)`.\n3. **One YAML, Many Stores**: Define all your stores in a single `store.yaml` to keep your data access layer centrally configured.\n4. **Know Which Files Are Auto-Generated**: Only `interface.go` and `all.go` are marked `DO NOT EDIT` and are overwritten on every `gofr store generate`. The implementation stub (`<name>.go`) created by `gofr store init` is editable — this is where you add your SQL logic. The `userStore.go` generated by `gofr store generate` is also editable boilerplate.\n5. **Version Control**: Always commit your `store.yaml`. Re-run `gofr store generate` after any configuration change to sync the generated interfaces.\n\n---\n\n## **Complete Example**\n\nFor a complete working example of the store generator, see the [store example](https://github.com/gofr-dev/gofr-cli/tree/main/store/example.yaml) in the gofr-cli repository.\n\nFor detailed configuration options and advanced usage, refer to the [Store Generator README](https://github.com/gofr-dev/gofr-cli/blob/main/store/README.md).\n\n---\n\n## See also\n\n- [GoFr CLI overview](/docs/references/gofrcli)\n- [`gofr init`](/docs/references/gofrcli/init)\n- [`gofr migrate`](/docs/references/gofrcli/migrate)\n- [`gofr wrap grpc`](/docs/references/gofrcli/wrap-grpc)\n","docs/references/testing/page.md":"---\ndescription: \"Write unit and integration tests for GoFr REST APIs. Mock the container's dependencies and assert handler responses, status codes, and headers reliably.\"\nnextjs:\n  metadata:\n    title: \"Testing GoFr REST APIs — Handlers, Mocks, Assertions\"\n    description: \"Write unit and integration tests for GoFr REST APIs. Mock the container's dependencies and assert handler responses, status codes, and headers reliably.\"\n---\n\n# Testing REST APIs with GoFr\n\nTesting REST APIs ensures that your endpoints function correctly under various conditions. This guide demonstrates how to write tests for GoFr-based REST APIs.\n\n## Mocking Databases in GoFr\n\nMocking databases allows for isolated testing by simulating various scenarios. GoFr's built-in mock container supports, not only SQL databases, but also extends to other data stores, including Redis, Cassandra, Key-Value stores, MongoDB, and ClickHouse.\n\n### Mocking `Select` Queries\n\n`Select` reads rows into a destination, so its mock takes the response you want written into that destination. Pass a pointer of the destination's type to `ExpectSelect`, along with the exact query text and arguments your handler uses, then set the rows with `ReturnsResponse`:\n\n```go\nvar users []User\n\nmock.SQL.ExpectSelect(ctx, &users, \"SELECT id, name FROM users WHERE status = ?\", \"active\").\n\tReturnsResponse([]User{{ID: 1, Name: \"John\"}})\n```\n\nWhen the handler calls `ctx.SQL.Select(ctx, &dest, \"SELECT id, name FROM users WHERE status = ?\", \"active\")`, `dest` is set to the response.\n\nThe query text must match exactly, and the arguments must have the same count, values and types (compared with `reflect.DeepEqual`, so slices such as `IN` lists are supported). If the query or arguments do not match, the destination is left untouched and the test fails with a message showing the expected and actual values.\n\n## Example of Unit Testing a REST API Using GoFr\n\nBelow is an example of how to test, say the `Add` method of a handler that interacts with a SQL database.\n\nHere’s an `Add` function for adding a book to the database using GoFr:\n\n```go\n// main.go\npackage main\n\nimport (\n\t\"gofr.dev/pkg/gofr\"\n\t\"gofr.dev/pkg/gofr/http\"\n)\n\ntype Book struct {\n\tId    int    `json:\"id\"`\n\tISBN  int    `json:\"isbn\"`\n\tTitle string `json:\"title\"`\n}\n\nfunc Add(ctx *gofr.Context) (any, error) {\n\tvar book Book\n\n\tif err := ctx.Bind(&book); err != nil {\n\t\tctx.Logger.Errorf(\"error in binding: %v\", err)\n\t\treturn nil, http.ErrorInvalidParam{Params: []string{\"body\"}}\n\t}\n\n\t// we assume the `id` column in the database is set to auto-increment.\n\tres, err := ctx.SQL.ExecContext(ctx, `INSERT INTO books (title, isbn) VALUES (?, ?)`, book.Title, book.ISBN)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tid, err := res.LastInsertId()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn id, nil\n}\n\nfunc main() {\n\t// initialize gofr object\n\tapp := gofr.New()\n\n\tapp.POST(\"/book\", Add)\n\n\t// Run the application\n\tapp.Run()\n}\n\n```\n\nHere’s how to write tests using GoFr:\n\n```go\n// main_test.go\npackage main\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"database/sql\"\n\t\"errors\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"gofr.dev/pkg/gofr\"\n\t\"gofr.dev/pkg/gofr/container\"\n\tgofrHttp \"gofr.dev/pkg/gofr/http\"\n)\n\nfunc TestAdd(t *testing.T) {\n\ttype gofrResponse struct {\n\t\tresult any\n\t\terr    error\n\t}\n\n\t// NewMockContainer provides mock implementations for various databases including:\n\t// Redis, SQL, ClickHouse, Cassandra, MongoDB, and KVStore.\n\t// These mock can be used to define database expectations in unit tests,\n\t// similar to the SQL example demonstrated here.\n\tmockContainer, mock := container.NewMockContainer(t)\n\n\tctx := &gofr.Context{\n\t\tContext:   context.Background(),\n\t\tRequest:   nil,\n\t\tContainer: mockContainer,\n\t}\n\n\ttests := []struct {\n\t\tname             string\n\t\trequestBody      string\n\t\tmockExpect       func()\n\t\texpectedResponse any\n\t}{\n\t\t{\n\t\t\tname:        \"Error while Binding\",\n\t\t\trequestBody: `title\":\"Book Title\",\"isbn\":12345}`,\n\t\t\tmockExpect: func() {\n\t\t\t},\n\t\t\texpectedResponse: gofrResponse{\n\t\t\t\tnil,\n\t\t\t\tgofrHttp.ErrorInvalidParam{Params: []string{\"body\"}}},\n\t\t},\n\t\t{\n\t\t\tname:        \"Successful Insertion\",\n\t\t\trequestBody: `{\"title\":\"Book Title\",\"isbn\":12345}`,\n\t\t\tmockExpect: func() {\n\t\t\t\tmock.SQL.\n\t\t\t\t\tExpectExec(`INSERT INTO books (title, isbn) VALUES (?, ?)`).\n\t\t\t\t\tWithArgs(\"Book Title\", 12345).\n\t\t\t\t\tWillReturnResult(sqlmock.NewResult(12, 1))\n\t\t\t},\n\t\t\texpectedResponse: gofrResponse{\n\t\t\t\tint64(12),\n\t\t\t\tnil,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:        \"Error on Insertion\",\n\t\t\trequestBody: `{\"title\":\"Book Title\",\"isbn\":12345}`,\n\t\t\tmockExpect: func() {\n\t\t\t\tmock.SQL.\n\t\t\t\t\tExpectExec(`INSERT INTO books (title, isbn) VALUES (?, ?)`).\n\t\t\t\t\tWithArgs(\"Book Title\", 12345).\n\t\t\t\t\tWillReturnError(sql.ErrConnDone)\n\t\t\t},\n\t\t\texpectedResponse: gofrResponse{\n\t\t\t\tnil,\n\t\t\t\tsql.ErrConnDone},\n\t\t},\n\t\t{\n\t\t\tname:        \"Error while fetching LastInsertId\",\n\t\t\trequestBody: `{\"title\":\"Book Title\",\"isbn\":12345}`,\n\t\t\tmockExpect: func() {\n\t\t\t\tmock.SQL.\n\t\t\t\t\tExpectExec(`INSERT INTO books (title, isbn) VALUES (?, ?)`).\n\t\t\t\t\tWithArgs(\"Book Title\", 12345).\n\t\t\t\t\tWillReturnError(errors.New(\"mocked result error\"))\n\t\t\t},\n\t\t\texpectedResponse: gofrResponse{\n\t\t\t\tnil,\n\t\t\t\terrors.New(\"mocked result error\")},\n\t\t},\n\t}\n\n\tfor i, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ttt.mockExpect()\n\n\t\t\tvar req *http.Request\n\n\t\t\treq = httptest.NewRequest(\n\t\t\t\thttp.MethodPost,\n\t\t\t\t\"/book\",\n\t\t\t\tbytes.NewBuffer([]byte(tt.requestBody)),\n\t\t\t)\n\n\t\t\treq.Header.Set(\"Content-Type\", \"application/json\")\n\n\t\t\trequest := gofrHttp.NewRequest(req)\n\n\t\t\tctx.Request = request\n\n\t\t\tval, err := Add(ctx)\n\n\t\t\tresponse := gofrResponse{val, err}\n\n\t\t\tassert.Equal(t, tt.expectedResponse, response, \"TEST[%d], Failed.\\n%s\", i, tt.name)\n\t\t})\n\t}\n}\n\n```\n\n## Testing HTTP Handlers with Mock Services\n\nWhen you register multiple services with `WithMockHTTPService`, each service gets its own separate mock instance. This allows you to set different expectations for each service using the `mocks.HTTPServices` map. Use table-driven tests to cover multiple scenarios:\n\n### Important Notes\n\n- **Context Matching**: Always use the exact context from your `gofr.Context` (`ctx.Context`) in expectations. gomock compares contexts by reference, not value, so using `t.Context()` or `context.Background()` will fail.\n- **Service Registration**: `WithMockHTTPService(\"serviceName\")` registers the service with the specified name. Each service gets its own separate mock instance.\n- **Multiple Services**: Use `mocks.HTTPServices[\"serviceName\"]` to access and set different expectations for each service. Each service has its own mock instance, so expectations are independent.\n- **Tests will fail** if the mocked HTTPService is not called as expected or if the context doesn't match.\n\n```go\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gofr.dev/pkg/gofr\"\n\t\"gofr.dev/pkg/gofr/container\"\n\tgofrHttp \"gofr.dev/pkg/gofr/http\"\n)\n\n// Handler that calls multiple HTTP services\n// This handler demonstrates calling two different services (paymentService and shippingService)\n// to fetch order details from different parts of the system.\nfunc OrderDetailsHandler(ctx *gofr.Context) (any, error) {\n\torderID := ctx.PathParam(\"id\")\n\tif orderID == \"\" {\n\t\treturn nil, errors.New(\"order ID is required\")\n\t}\n\n\t// First HTTP service call: Get payment details from paymentService\n\tpaymentService := ctx.GetHTTPService(\"paymentService\")\n\tpaymentResp, err := paymentService.Get(ctx.Context, \"/payments/\"+orderID, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to fetch payment details: %w\", err)\n\t}\n\tdefer paymentResp.Body.Close()\n\n\tvar paymentData struct {\n\t\tStatus string `json:\"status\"`\n\t\tAmount int    `json:\"amount\"`\n\t}\n\n\tpaymentBody, err := io.ReadAll(paymentResp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read payment response: %w\", err)\n\t}\n\n\tif err := json.Unmarshal(paymentBody, &paymentData); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse payment response: %w\", err)\n\t}\n\n\t// Second HTTP service call: Get shipping details from shippingService\n\tshippingService := ctx.GetHTTPService(\"shippingService\")\n\tshippingResp, err := shippingService.Get(ctx.Context, \"/shipping/\"+orderID, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to fetch shipping details: %w\", err)\n\t}\n\tdefer shippingResp.Body.Close()\n\n\tvar shippingData struct {\n\t\tStatus           string `json:\"status\"`\n\t\tTracking         string `json:\"tracking\"`\n\t\tEstimatedDelivery string `json:\"estimated_delivery\"`\n\t}\n\n\tshippingBody, err := io.ReadAll(shippingResp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read shipping response: %w\", err)\n\t}\n\n\tif err := json.Unmarshal(shippingBody, &shippingData); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse shipping response: %w\", err)\n\t}\n\n\t// Combine results from both services\n\treturn map[string]any{\n\t\t\"order_id\":          orderID,\n\t\t\"payment_status\":    paymentData.Status,\n\t\t\"payment_amount\":    paymentData.Amount,\n\t\t\"shipping_status\":   shippingData.Status,\n\t\t\"tracking_number\":   shippingData.Tracking,\n\t\t\"estimated_delivery\": shippingData.EstimatedDelivery,\n\t}, nil\n}\n\nfunc TestOrderDetailsHandler(t *testing.T) {\n\t// Helper function to create test context with path parameters\n\tcreateTestContext := func(path string, container *container.Container) *gofr.Context {\n\t\treq := httptest.NewRequest(http.MethodGet, path, nil)\n\t\t\n\t\t// Set path parameters using mux.SetURLVars (required for ctx.PathParam to work)\n\t\tif strings.Contains(path, \"/orders/\") {\n\t\t\tparts := strings.Split(strings.Trim(path, \"/\"), \"/\")\n\t\t\tif len(parts) >= 2 && parts[1] != \"\" {\n\t\t\t\treq = mux.SetURLVars(req, map[string]string{\"id\": parts[1]})\n\t\t\t}\n\t\t}\n\n\t\treturn &gofr.Context{\n\t\t\tContext:   req.Context(),\n\t\t\tRequest:   gofrHttp.NewRequest(req),\n\t\t\tContainer: container,\n\t\t}\n\t}\n\n\tconst testOrderID = \"12345\" // Reusable order ID for tests\n\n\ttests := []struct {\n\t\tname           string\n\t\tsetupMocks     func(*container.Mocks, *gofr.Context)\n\t\trequestPath    string\n\t\twantErr        bool\n\t\twantErrMsg     string\n\t\tvalidateResult func(*testing.T, any)\n\t}{\n\t\t{\n\t\t\tname: \"successful order details retrieval\",\n\t\t\tsetupMocks: func(mocks *container.Mocks, ctx *gofr.Context) {\n\t\t\t\t// Set up expectation for paymentService - this is the first HTTP call in the handler\n\t\t\t\tpaymentResp := &http.Response{\n\t\t\t\t\tStatusCode: http.StatusOK,\n\t\t\t\t\tBody:       io.NopCloser(strings.NewReader(`{\"status\":\"completed\",\"amount\":1500}`)),\n\t\t\t\t}\n\t\t\t\tmocks.HTTPServices[\"paymentService\"].EXPECT().Get(\n\t\t\t\t\tctx.Context,\n\t\t\t\t\t\"/payments/\"+testOrderID,\n\t\t\t\t\tnil,\n\t\t\t\t).Return(paymentResp, nil)\n\n\t\t\t\t// Set up expectation for shippingService - this is the second HTTP call in the handler\n\t\t\t\t// Note: Each service has its own independent mock instance\n\t\t\t\tshippingResp := &http.Response{\n\t\t\t\t\tStatusCode: http.StatusOK,\n\t\t\t\t\tBody:       io.NopCloser(strings.NewReader(`{\"status\":\"in_transit\",\"tracking\":\"TRACK123\",\"estimated_delivery\":\"2024-12-25\"}`)),\n\t\t\t\t}\n\t\t\t\tmocks.HTTPServices[\"shippingService\"].EXPECT().Get(\n\t\t\t\t\tctx.Context,\n\t\t\t\t\t\"/shipping/\"+testOrderID,\n\t\t\t\t\tnil,\n\t\t\t\t).Return(shippingResp, nil)\n\t\t\t},\n\t\t\trequestPath: \"/orders/\" + testOrderID,\n\t\t\twantErr:     false,\n\t\t\tvalidateResult: func(t *testing.T, result any) {\n\t\t\t\tresultMap := result.(map[string]any)\n\t\t\t\tassert.Equal(t, testOrderID, resultMap[\"order_id\"])\n\t\t\t\tassert.Equal(t, \"completed\", resultMap[\"payment_status\"])\n\t\t\t\tassert.Equal(t, 1500, resultMap[\"payment_amount\"])\n\t\t\t\tassert.Equal(t, \"in_transit\", resultMap[\"shipping_status\"])\n\t\t\t\tassert.Equal(t, \"TRACK123\", resultMap[\"tracking_number\"])\n\t\t\t\tassert.Equal(t, \"2024-12-25\", resultMap[\"estimated_delivery\"])\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"payment service error\",\n\t\t\tsetupMocks: func(mocks *container.Mocks, ctx *gofr.Context) {\n\t\t\t\t// Payment service returns an error - handler should fail before calling shipping service\n\t\t\t\tmocks.HTTPServices[\"paymentService\"].EXPECT().Get(\n\t\t\t\t\tctx.Context,\n\t\t\t\t\t\"/payments/\"+testOrderID,\n\t\t\t\t\tnil,\n\t\t\t\t).Return(nil, errors.New(\"payment service unavailable\"))\n\n\t\t\t\t// Shipping service should NOT be called when payment service fails\n\t\t\t\t// No expectation set for shippingService - test will fail if it's called\n\t\t\t},\n\t\t\trequestPath: \"/orders/\" + testOrderID,\n\t\t\twantErr:     true,\n\t\t\twantErrMsg:  \"failed to fetch payment details\",\n\t\t},\n\t\t{\n\t\t\tname: \"shipping service error\",\n\t\t\tsetupMocks: func(mocks *container.Mocks, ctx *gofr.Context) {\n\t\t\t\t// Payment service succeeds\n\t\t\t\tpaymentResp := &http.Response{\n\t\t\t\t\tStatusCode: http.StatusOK,\n\t\t\t\t\tBody:       io.NopCloser(strings.NewReader(`{\"status\":\"completed\",\"amount\":1500}`)),\n\t\t\t\t}\n\t\t\t\tmocks.HTTPServices[\"paymentService\"].EXPECT().Get(\n\t\t\t\t\tctx.Context,\n\t\t\t\t\t\"/payments/\"+testOrderID,\n\t\t\t\t\tnil,\n\t\t\t\t).Return(paymentResp, nil)\n\n\t\t\t\t// Shipping service returns an error - this is the second HTTP call\n\t\t\t\tmocks.HTTPServices[\"shippingService\"].EXPECT().Get(\n\t\t\t\t\tctx.Context,\n\t\t\t\t\t\"/shipping/\"+testOrderID,\n\t\t\t\t\tnil,\n\t\t\t\t).Return(nil, errors.New(\"shipping service unavailable\"))\n\t\t\t},\n\t\t\trequestPath: \"/orders/\" + testOrderID,\n\t\t\twantErr:     true,\n\t\t\twantErrMsg:  \"failed to fetch shipping details\",\n\t\t},\n\t\t{\n\t\t\tname: \"missing order ID\",\n\t\t\tsetupMocks: func(mocks *container.Mocks, ctx *gofr.Context) {\n\t\t\t\t// No service calls should be made when order ID is missing\n\t\t\t},\n\t\t\trequestPath: \"/orders/\",\n\t\t\twantErr:     true,\n\t\t\twantErrMsg:  \"order ID is required\",\n\t\t},\n\t}\n\n\t// Register HTTP services once - each service gets its own separate mock instance\n\t// Since all test cases use the same services, we can create the mock container outside the loop\n\tmockContainer, mocks := container.NewMockContainer(t,\n\t\tcontainer.WithMockHTTPService(\"paymentService\", \"shippingService\"),\n\t)\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Create test context using helper function\n\t\t\tctx := createTestContext(tt.requestPath, mockContainer)\n\n\t\t\t// Set up mock expectations BEFORE calling the handler\n\t\t\t// Each service's expectations are independent\n\t\t\ttt.setupMocks(mocks, ctx)\n\n\t\t\t// Call the handler\n\t\t\tresult, err := OrderDetailsHandler(ctx)\n\n\t\t\tif tt.wantErr {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), tt.wantErrMsg)\n\t\t\t\tassert.Nil(t, result)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tif tt.validateResult != nil {\n\t\t\t\t\ttt.validateResult(t, result)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n```\n\n**Key Points**:\n- Each service registered via `WithMockHTTPService` gets its own separate mock instance\n- Always use `mocks.HTTPServices[\"serviceName\"]` to access and set expectations for a specific service\n- Always create the `gofr.Context` with the exact request context (`req.Context()`) that will be used in the handler\n- Set expectations on the mock services before calling the handler\n- Test both success and error scenarios to ensure your handlers handle all cases correctly\n\n### Summary\n\n- **Mocking Database Interactions**: Use GoFr mock container to simulate database interactions.\n- **Mocking HTTP Services**: Use `WithMockHTTPService(\"serviceName\")` to register and mock HTTP services.\n- **Context Matching**: Always use `ctx.Context` from your `gofr.Context` in mock expectations, not `t.Context()` or `context.Background()`.\n- **Define Test Cases**: Create table-driven tests to handle various scenarios.\n- **Run and Validate**: Ensure that your tests check for expected results, and handle errors correctly.\n\nThis approach guarantees that your database and HTTP service interactions are tested independently, allowing you to simulate different responses and errors hassle-free.\n","docs/references/gofrcli/wrap-grpc/page.md":"---\ndescription: \"Generate gRPC server and client wrappers with built-in tracing, metrics, and logging using the gofr wrap grpc command.\"\nnextjs:\n  metadata:\n    title: \"gofr wrap grpc — Generate gRPC Server/Client Wrappers\"\n    description: \"Generate gRPC server and client wrappers with built-in tracing, metrics, and logging using the gofr wrap grpc command.\"\n---\n\n# gofr wrap grpc\n\n* The gofr wrap grpc command streamlines gRPC integration in a GoFr project by generating GoFr's context-aware structures.\n* It simplifies setting up gRPC handlers with minimal steps, and accessing datasources, adding tracing as well as custom metrics. Based on the proto file it creates the handler/client with GoFr's context.\n  For detailed instructions on using grpc with GoFr see the [gRPC documentation](/docs/advanced-guide/grpc)\n\n## Command Usage\n**gRPC Server**\n```bash\n  gofr wrap grpc server --proto=<path_to_the_proto_file>\n```\n## Generated Files\n**Server**\n- ```{serviceName}_gofr.go (auto-generated; do not modify)```\n- ```{serviceName}_server.go (example structure below)```\n\n## Example Usage\n**gRPC Server**\n\nThe command generates a server implementation template similar to this:\n```go\npackage server\n\nimport (\n   \"gofr.dev/pkg/gofr\"\n)\n\n// Register the gRPC service in your app using the following code in your main.go:\n//\n// service.Register{ServiceName}ServerWithGofr(app, &server.{ServiceName}Server{})\n//\n// {ServiceName}Server defines the gRPC server implementation.\n// Customize the struct with required dependencies and fields as needed.\ntype {ServiceName}Server struct {\n}\n\n// Example method (actual methods will depend on your proto file)\nfunc (s *MyServiceServer) MethodName(ctx *gofr.Context) (any, error) {\n   // Replace with actual logic if needed\n   return &ServiceResponse{\n   }, nil\n}\n```\nFor detailed instruction on setting up a gRPC server with GoFr see the [gRPC Server Documentation](https://gofr.dev/docs/advanced-guide/grpc#generating-g-rpc-server-handler-template-using)\n\n**gRPC Client**\n```bash\n  gofr wrap grpc client --proto=<path_to_the_proto_file>\n```\n\n**Client**\n- ```{serviceName}_client.go (example structure below)```\n\n\n## Example Usage:\nAssuming the service is named hello, after generating the hello_client.go file, you can seamlessly register and access the gRPC service using the following steps:\n\n```go\ntype GreetHandler struct {\n\thelloGRPCClient client.HelloGoFrClient\n}\n\nfunc NewGreetHandler(helloClient client.HelloGoFrClient) *GreetHandler {\n    return &GreetHandler{\n        helloGRPCClient: helloClient,\n    }\n}\n\nfunc (g GreetHandler) Hello(ctx *gofr.Context) (any, error) {\n    userName := ctx.Param(\"name\")\n    helloResponse, err := g.helloGRPCClient.SayHello(ctx, &client.HelloRequest{Name: userName})\n    if err != nil {\n        return nil, err\n    }\n\n    return helloResponse, nil\n}\n\nfunc main() {\n    app := gofr.New()\n\n// Create a gRPC client for the Hello service\n    helloGRPCClient, err := client.NewHelloGoFrClient(app.Config.Get(\"GRPC_SERVER_HOST\"), app.Metrics())\n    if err != nil {\n\t\tapp.Logger().Errorf(\"Failed to create Hello gRPC client: %v\", err)\n    return\n}\n\n    greetHandler := NewGreetHandler(helloGRPCClient)\n\n    // Register HTTP endpoint for Hello service\n    app.GET(\"/hello\", greetHandler.Hello)\n\n    // Run the application\n    app.Run()\n}\n```\nFor detailed instruction on setting up a gRPC server with GoFr see the [gRPC Client Documentation](https://gofr.dev/docs/advanced-guide/grpc#generating-tracing-enabled-g-rpc-client-using)\nFor more examples refer [gRPC Examples](https://github.com/gofr-dev/gofr/tree/main/examples/grpc)\n\n---\n\n## See also\n\n- [GoFr CLI overview](/docs/references/gofrcli)\n- [`gofr init`](/docs/references/gofrcli/init)\n- [`gofr migrate`](/docs/references/gofrcli/migrate)\n- [`gofr store`](/docs/references/gofrcli/store)\n"},"files":{"docs/AGENTS.md":"# GoFr — guide for AI coding assistants\n\nFor Claude Code, Cursor, Aider, Codex, etc. Hand\n[https://gofr.dev/AGENTS.md](https://gofr.dev/AGENTS.md) to your assistant\nwhen working on a GoFr project. It points at the specific docs you'll\nactually need rather than inlining everything.\n\nGoFr is an opinionated Go framework for microservices. Apache 2.0.\nRequires Go 1.26+. Repo: <https://github.com/gofr-dev/gofr>.\n\n## Core rules an assistant must know\n\n1. **One handler signature** for HTTP / gRPC / GraphQL / WebSocket / cron / CLI:\n   `func(c *gofr.Context) (any, error)`. Return value → `{\"data\": ...}`. Return error → error response.\n2. **Path params use `{name}`**, not `:name`. `app.GET(\"/users/{id}\", h)`.\n3. **`c.PathParam(\"id\")`** for path; **`c.Param(\"q\")`** for query; **`c.Bind(&v)`** for body.\n4. **Don't manually wire OpenTelemetry, Prometheus, or structured logging.** `gofr.New()` does it.\n5. **Pass `*gofr.Context`** (not `context.Background()`) to every downstream call so trace propagation and cancellation work.\n6. **Configuration comes from `configs/.env`** via `c.Config.Get(key)`. No hardcoded ports / hosts / secrets.\n7. **No ORM bundled.** Use plain SQL via `c.SQL`, or pair with `sqlc`/`gorm` yourself.\n8. **Middleware is standard `net/http`**: `func(http.Handler) http.Handler`, registered with `app.UseMiddleware(...)`.\n9. **Health is auto-exposed** at `/.well-known/health` and `/.well-known/alive`. Don't hand-roll `/healthz`.\n10. **Don't `panic()` for control flow.** Return errors.\n\n## Minimal app\n\n```go\npackage main\n\nimport \"gofr.dev/pkg/gofr\"\n\nfunc main() {\n    app := gofr.New()\n    app.GET(\"/hello\", func(c *gofr.Context) (any, error) {\n        return \"Hello, world\", nil\n    })\n    app.Run()\n}\n```\n\n## Migrations (schema + seed data, versioned)\n\nGoFr has a built-in migration runner — use it instead of `golang-migrate` / `goose`. Works for SQL, Redis, Mongo, Cassandra, ClickHouse, DGraph, SurrealDB.\n\n**Before writing a migration, fetch the full reference:** <https://gofr.dev/docs/advanced-guide/handling-data-migrations>. Runnable shape: <https://github.com/gofr-dev/gofr/tree/main/examples/using-migrations>.\n\nFive rules to keep in your head so you don't have to re-fetch on every change:\n\n1. Files live in `migrations/<unix-ts>_<name>.go`. Versions are `int64`, monotonic. Use `date +%s` for new ones.\n2. `migrations/all.go` exports `All() map[int64]migration.Migrate`. Wire with `a.Migrate(migrations.All())` once in `main.go`.\n3. Each migration is `migration.Migrate{ UP: func(d migration.Datasource) error { ... } }`. Inside `UP`, act on `d.SQL`, `d.Redis`, `d.MongoDB`, `d.Cassandra`, `d.Clickhouse`, `d.DGraph`, `d.SurrealDB`, `d.Logger`.\n4. Each migration runs **exactly once** per environment — don't add idempotent guards. There is **no down migration**; rollback = new forward migration.\n5. One purpose per file. Don't combine \"create table + backfill + drop column\" in one `UP`.\n\n## AI features: LLMs and MCP\n\nGoFr ships LLM and agent support. Use it instead of importing a provider SDK or hand-rolling HTTP, tracing and metrics\naround model calls. **Before writing this code, fetch the full guides:** <https://gofr.dev/docs/advanced-guide/llm> and\n<https://gofr.dev/docs/advanced-guide/mcp>. Runnable shape: <https://github.com/gofr-dev/gofr/tree/main/examples/using-ai>.\n\nRules to keep in your head so you don't have to re-fetch on every change:\n\n1. **Register a model once** with `app.AddLLM(&llm.Client{Provider: llm.Groq, Model: \"...\"})`\n   (`gofr.dev/pkg/gofr/ai/llm`). Providers: `llm.OpenAI`, `llm.Groq`, `llm.DeepSeek`, `llm.Together`, `llm.Ollama`;\n   set `BaseURL` for any other OpenAI-compatible endpoint. Or skip the call and set `LLM_PROVIDER`, `LLM_MODEL` and\n   `LLM_API_KEY` (optional `LLM_BASE_URL`) in `configs/.env`.\n2. **Never hardcode the API key.** It comes from `LLM_API_KEY`, then the provider's own variable (`OPENAI_API_KEY`,\n   `GROQ_API_KEY`, ...).\n3. **Call the model through `c.LLM()`**: `Generate`, `Chat`, `Stream`, `Embed`. It is already traced and metered. Extra\n   models: `app.AddLLM(m, gofr.WithName(\"fast\"))`, used as `c.LLM(\"fast\")`. Not every provider supports every method;\n   handle `ai.ErrEmbedNotSupported` / `ai.ErrStreamNotSupported` as ordinary errors.\n4. **Stream tokens** by returning `response.Stream{Source: stream}` from the handler\n   (`gofr.dev/pkg/gofr/http/response`).\n5. **Expose handlers to agents with `app.EnableMCP()`.** It serves the *read-only* handlers (`GET`, `HEAD`, `OPTIONS`,\n   `QUERY`) as MCP tools. `POST`/`PUT`/`PATCH`/`DELETE` are never exposed. Hide a route with\n   `gofr.WithExcludedRoutes(\"/internal/{id}\")`.\n6. **MCP binds to loopback on `MCP_PORT` (default `8200`).** `MCP_PORT=0` turns the transport off but keeps tools\n   available in-process. A port that cannot be claimed fails startup. `8200` is also Vault's default port.\n7. **Build agent loops in your own handler** with `c.LLM().Tools()` (`List`, `Call`, `Only`). GoFr has no built-in agent\n   loop; turns, stopping conditions and memory stay in your code.\n\n```go\npackage main\n\nimport (\n    \"gofr.dev/pkg/gofr\"\n    \"gofr.dev/pkg/gofr/ai/llm\"\n)\n\nfunc main() {\n    app := gofr.New()\n\n    app.AddLLM(&llm.Client{Provider: llm.Groq, Model: \"llama-3.3-70b-versatile\"})\n    app.EnableMCP() // exposes the GET handlers below to MCP clients\n\n    app.GET(\"/products/{id}\", func(c *gofr.Context) (any, error) {\n        return map[string]any{\"id\": c.PathParam(\"id\")}, nil\n    })\n\n    app.POST(\"/summarize\", func(c *gofr.Context) (any, error) {\n        var in struct {\n            Text string `json:\"text\"`\n        }\n        if err := c.Bind(&in); err != nil {\n            return nil, err\n        }\n\n        return c.LLM().Generate(c, \"Summarize the following:\\n\"+in.Text)\n    })\n\n    app.Run()\n}\n```\n\n## Where to look (fetch only what you need)\n\nEach link is a self-contained doc page. Fetch lazily.\n\n- Quick start: <https://gofr.dev/docs/quick-start/introduction>\n- Configuration: <https://gofr.dev/docs/quick-start/configuration>\n- Routing + REST handlers: <https://gofr.dev/docs/quick-start/add-rest-handlers>\n- Context reference (the central abstraction): <https://gofr.dev/docs/references/context>\n- Configs reference (every env var): <https://gofr.dev/docs/references/configs>\n- Testing patterns + mocks: <https://gofr.dev/docs/references/testing>\n- Observability (auto-wired): <https://gofr.dev/docs/quick-start/observability>\n- Custom OTel spans: <https://gofr.dev/docs/advanced-guide/custom-spans-in-tracing>\n- Custom Prometheus metrics: <https://gofr.dev/docs/advanced-guide/publishing-custom-metrics>\n- Datasources index (MySQL, Postgres, Mongo, Redis, Cassandra, ClickHouse, etc.): <https://gofr.dev/docs/datasources/getting-started>\n- Pub/Sub (Kafka, NATS, GCP, MQTT, SQS, Azure): <https://gofr.dev/docs/advanced-guide/using-publisher-subscriber>\n- gRPC: <https://gofr.dev/docs/advanced-guide/grpc>\n- GraphQL: <https://gofr.dev/docs/advanced-guide/graphql>\n- WebSockets: <https://gofr.dev/docs/advanced-guide/websocket>\n- Cron: <https://gofr.dev/docs/advanced-guide/using-cron>\n- Service-to-service HTTP w/ circuit breaker: <https://gofr.dev/docs/advanced-guide/http-communication>\n- Auth (Basic / API key / OAuth-JWT): <https://gofr.dev/docs/advanced-guide/authentication>\n- RBAC (config-driven): <https://gofr.dev/docs/advanced-guide/rbac>\n- Migrations (SQL + NoSQL, versioned): <https://gofr.dev/docs/advanced-guide/handling-data-migrations>\n- File storage (local / S3 / GCS / Azure / FTP / SFTP): <https://gofr.dev/docs/advanced-guide/handling-file>\n- Startup hooks: <https://gofr.dev/docs/advanced-guide/startup-hooks>\n- Errors: <https://gofr.dev/docs/advanced-guide/gofr-errors>\n- Custom DB drivers: <https://gofr.dev/docs/advanced-guide/injecting-databases-drivers>\n- Calling LLMs (`app.AddLLM`, `c.LLM()`, env config, multiple models, embeddings): <https://gofr.dev/docs/advanced-guide/llm>\n- MCP server and agent loops (`app.EnableMCP`, `c.LLM().Tools()`): <https://gofr.dev/docs/advanced-guide/mcp>\n- Streaming responses (SSE / NDJSON, `response.Stream`): <https://gofr.dev/docs/advanced-guide/streaming>\n\n## Migrating to GoFr\n\nEach migration page has the full mapping table for that source framework — fetch only the one that matches:\n\n- From Gin: <https://gofr.dev/migrate/from-gin>\n- From Fiber: <https://gofr.dev/migrate/from-fiber>\n- From Echo: handler shape similar to Gin; see <https://gofr.dev/comparison/gofr-vs-echo>\n- From Chi: see <https://gofr.dev/comparison/gofr-vs-chi>\n- From Express (Node.js): <https://gofr.dev/migrate/from-express>\n- From Flask (Python): <https://gofr.dev/migrate/from-flask>\n- From Spring Boot (Java): <https://gofr.dev/migrate/from-spring-boot>\n\n## Other entry points\n\n- Examples (runnable projects): <https://github.com/gofr-dev/gofr/tree/main/examples>\n- Full docs index: <https://gofr.dev/docs>\n- Concatenated full docs (one plaintext file): <https://gofr.dev/llms-full.txt>\n- Curated link index: <https://gofr.dev/llms.txt>\n- Changelog: <https://gofr.dev/changelog>\n","docs/references/configs/page.md":"---\ndescription: \"Reference of every GoFr configuration variable, grouped by category: HTTP, gRPC, datasources, observability, auth, and more — with defaults and value formats.\"\nnextjs:\n  metadata:\n    title: \"GoFr Configuration Reference — Env Vars and Defaults\"\n    description: \"Reference of every GoFr configuration variable, grouped by category: HTTP, gRPC, datasources, observability, auth, and more — with defaults and value formats.\"\n---\n\n# GoFr Configuration Options\n\nThis document lists all the configuration options supported by the GoFr framework. The configurations are grouped by category for better organization.\n\n## App\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  APP_NAME\n-  Name of the application. It is also the `service.name` on the resource attached to exported traces and metrics; OTEL_SERVICE_NAME and a service.name= entry in OTEL_RESOURCE_ATTRIBUTES are ignored.\n-  gofr-app\n\n---\n\n-  APP_ENV\n-  Name of the environment file to use (e.g., stage.env, prod.env, or local.env).\n\n---\n\n-  APP_VERSION\n-  Application version\n-  dev\n\n---\n\n-  LOG_LEVEL\n-  Level of verbosity for application logs. Supported values are **DEBUG, INFO, NOTICE, WARN, ERROR, FATAL**\n-  INFO\n\n---\n\n-  REMOTE_LOG_URL\n-  URL to remotely change the log level\n\n---\n\n-  REMOTE_LOG_FETCH_INTERVAL\n-  Time interval (in seconds) to check for remote log level updates\n-  15\n\n---\n\n-  METRICS_PORT\n-  Port on which the application exposes the Prometheus pull endpoint. Set to 0 to disable it (e.g. push-only serverless).\n-  2121\n\n---\n\n-  METRICS_EXPORTER\n-  Enables push-based metrics export alongside the pull endpoint. Supported values: otlp, gcp. Unset (or prometheus) keeps pull-only behavior.\n\n---\n\n-  METRICS_URL\n-  Endpoint of the OTLP metrics collector/backend. host:port for gRPC, full URL for HTTP. Required when METRICS_EXPORTER is otlp (gcp defaults to telemetry.googleapis.com:443).\n\n---\n\n-  METRICS_PROTOCOL\n-  OTLP transport for pushed metrics. Supported values: grpc, http.\n-  grpc\n\n---\n\n-  METRICS_EXPORT_INTERVAL\n-  Interval (in seconds) at which metrics are pushed to the collector/backend.\n-  30\n\n---\n\n-  METRICS_TEMPORALITY\n-  OTLP temporality preference. Supported values: cumulative, delta, lowmemory. Use delta for Datadog; cumulative for Prometheus/GMP/Grafana.\n-  cumulative\n\n---\n\n-  METRICS_HEADERS\n-  Custom headers for metric export requests in comma-separated key=value format (e.g., \"dd-api-key=secret\"). Takes priority over METRICS_AUTH_KEY.\n\n---\n\n-  METRICS_AUTH_KEY\n-  Authorization header value for metric export requests. Used when METRICS_HEADERS is unset.\n\n---\n\n-  METRICS_INSECURE\n-  Disables transport security for the OTLP metrics connection. Set to false for managed backends over TLS. Ignored by the gcp exporter (always TLS).\n-  true\n\n---\n\n-  METRICS_CARDINALITY_LIMIT\n-  Per-instrument attribute-set limit, inclusive of the overflow slot: an instrument keeps up to one fewer than this many distinct label sets per collection cycle, and the remaining series collapse into a single otel.metric.overflow series (so a value of n keeps n-1 real label sets). Set 0 or negative for unlimited. When unset, the OpenTelemetry SDK default applies (2000, or OTEL_GO_X_CARDINALITY_LIMIT if set); a set value takes precedence over OTEL_GO_X_CARDINALITY_LIMIT. HTTP metrics give requests that match no route (and unknown methods) at most a quarter of this limit, capped at 500 distinct (path, method, status) label sets; past that they are recorded as `__unmatched__` / `__other__`, so scanner traffic cannot push real routes into the overflow series.\n-  2000\n\n---\n\n-  OTEL_RESOURCE_ATTRIBUTES\n-  Standard OpenTelemetry resource attributes, comma-separated key=value. Merged into the resource attached to every exported metric and span, except service.name, which comes from APP_NAME (a service.name= entry is ignored with a warning), and framework_version, which cannot be overridden. Required for the gcp exporter outside Google Cloud: its ingest rejects any point whose prometheus_target has no location (e.g. \"location=us-central1\").\n\n---\n\n-  OTEL_SERVICE_NAME\n-  Standard OpenTelemetry service name. Ignored: GoFr sets service.name on exported traces and metrics from APP_NAME, and logs a warning at startup when this is set to a different value. Tracing and metrics each log it, so with both enabled the warning appears twice, once prefixed \"traces:\" and once \"metrics:\". Set APP_NAME to rename the service.\n\n---\n\n-  HTTP_PORT\n-  Port on which the HTTP server listens\n-  8000\n\n---\n\n-  GRPC_PORT\n-  Port on which the gRPC server listens\n-  9000\n\n---\n\n-  MCP_PORT\n-  Port on which the MCP server listens, bound to loopback. Only used when `app.EnableMCP()` is called; a port that cannot be claimed fails startup. Set to `0` to keep tools available in-process while serving no MCP transport. A non-numeric or out-of-range value refuses startup. Note the default collides with Vault's — see [MCP](/docs/advanced-guide/mcp).\n-  8200\n\n---\n\n-  TRACE_EXPORTER\n-  Tracing exporter to use. Supported values: gofr, zipkin, jaeger, otlp, gcp. `gcp` exports directly to Google Cloud's Telemetry (OTLP) API using Application Default Credentials, and requires the blank import `_ \"gofr.dev/pkg/gofr/traces/exporters/gcp\"`.\n\n---\n\n-  TRACER_HOST\n-  Hostname of the tracing collector. Required if TRACE_EXPORTER is set to zipkin or jaeger.\n-  **DEPRECATED**\n\n---\n\n-  TRACER_PORT\n-  Port of the tracing collector. Required if TRACE_EXPORTER is set to zipkin or jaeger.\n-  9411\n-  **DEPRECATED**\n\n---\n\n-  TRACER_URL\n-  URL of the trace collector. Required if TRACE_EXPORTER is set to zipkin, jaeger or otlp; optional for gcp, which defaults to `telemetry.googleapis.com:443`. For zipkin, jaeger and otlp an `http://` or `https://` scheme selects the transport, and a schemeless `host:port` is governed by TRACER_INSECURE. For gcp the value must be a schemeless `host:port` — that destination is always TLS on 443, so a scheme is rejected at startup rather than interpreted.\n\n---\n\n-  TRACER_INSECURE\n-  Whether a schemeless TRACER_URL (`host:port`) is exported over plaintext. Set to `false` to use TLS with the system root CAs. Ignored when TRACER_URL carries an `http://` or `https://` scheme, which selects the transport itself. Takes precedence over the OTel standard OTEL_EXPORTER_OTLP_INSECURE / OTEL_EXPORTER_OTLP_TRACES_INSECURE. Supported for otlp, jaeger.\n-  true\n\n---\n\n-  TRACER_RATIO\n-  Refers to the proportion of traces that are exported through sampling. It is optional configuration. By default, this ratio is set to 1. A value that is not a valid number is rejected with an error log and also resolves to 1, so a typo over-samples rather than silently disabling tracing.\n\n---\n\n-  TRACER_AUTH_KEY\n-  Authorization header for trace exporter requests. Supported for zipkin, jaeger, otlp.\n\n---\n\n-  TRACER_HEADERS\n-  Custom authentication headers for trace exporter requests in comma-separated key=value format (e.g., \"X-Api-Key=secret,Authorization=Bearer token\"). Supported for zipkin, jaeger, otlp. Takes priority over TRACER_AUTH_KEY.\n\n---\n\n-  CMD_LOGS_FILE\n-  File to save the logs in case of a CMD application\n\n---\n\n-  SHUTDOWN_GRACE_PERIOD\n-  Timeout duration for server shutdown process\n-  30s\n\n---\n\n-  GOFR_TELEMETRY\n-  Enable telemetry for GoFr framework usage\n-  true\n\n---\n\n-  GOFR_ROUTER\n-  Route matcher for the HTTP server. Set to `trie` to opt into the O(path length) trie index instead of the default linear scan — see [Routing Performance](/docs/advanced-guide/routing-performance). Any other value falls back to `mux`.\n-  mux\n\n---\n\n-  GOFR_RBAC_ROUTE_CHECK\n-  What the startup check does when the RBAC config and the registered routes disagree — see [Startup Route Check](/docs/advanced-guide/rbac#startup-route-check). `warn` logs each mismatch as an error and keeps starting, `fail` logs them and stops startup with exit status 1, `off` skips the check. Any other value is logged as an error and treated as `warn`.\n-  warn\n\n---\n\n-  LOG_DISABLE_PROBES\n-  Disable log probes for health checks\n-  false\n\n---\n\n-  GRPC_ENABLE_REFLECTION\n-  Enable gRPC server reflection\n-  false\n\n---\n\n-  HEALTH_CACHE_TTL\n-  How long a health result may be served without re-checking the backends, as a duration (`5s`, `10s`, `1m`). Unset, `0` or `disabled` turns caching off, which is the default: within a TTL a recovered backend still reports DOWN and a failed one still reports UP, so it is a trade to opt into rather than inherit.\n-  disabled\n\n---\n\n-  HEALTH_CHECK_TIMEOUT\n-  Upper bound on one round of health checks, as a duration (`2s`). Backends that have not answered by then are left out of the response and the aggregate status is DEGRADED. Datasources whose health check honors its context are canceled at that deadline. Once every outstanding check has returned, the next probe checks them again. Checks that cannot be canceled keep running after the round is abandoned: the SQL, Redis and PubSub health checks take no context, and a few datasources (such as Couchbase and NATS KV) don't yet honor the one they receive. While one of those is still running, a probe reports DEGRADED with no per-dependency detail rather than starting a second round against the same unresponsive backend. Unset or `0` means the round is bounded only by each backend client's own timeout.\n-  disabled\n\n{% /table %}\n\n## HTTP\n\n{% table %}\n\n- Name\n- Description\n\n---\n\n-  REQUEST_TIMEOUT\n-  Set the request timeouts (in seconds) for HTTP server.\n\n---\n\n- CERT_FILE\n- Set the path to your PEM certificate file for the HTTPS server to establish a secure connection.\n\n--- \n\n- KEY_FILE\n- Set the path to your PEM key file for the HTTPS server to establish a secure connection.\n\n{% /table %}\n\n### CORS\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n- ACCESS_CONTROL_ALLOW_ORIGIN\n- Allowed origin(s) for cross-origin requests. Supports comma-separated values for multiple origins (e.g., `https://app.example.com,https://admin.example.com`).\n- `*`\n\n---\n\n- ACCESS_CONTROL_ALLOW_HEADERS\n- Allowed request headers for cross-origin requests.\n- Authorization, Content-Type, x-requested-with, origin, true-client-ip, X-Correlation-ID\n\n---\n\n- ACCESS_CONTROL_ALLOW_METHODS\n- Allowed HTTP methods. Automatically set from registered routes if not provided.\n\n---\n\n- ACCESS_CONTROL_ALLOW_CREDENTIALS\n- Allow credentials (cookies, HTTP authentication) in cross-origin requests.\n\n---\n\n- ACCESS_CONTROL_EXPOSE_HEADERS\n- Additional headers exposed to the client in cross-origin responses.\n\n---\n\n- ACCESS_CONTROL_MAX_AGE\n- Maximum time (in seconds) browsers can cache preflight responses.\n\n{% /table %}\n\n## Datasource\n\n### SQL\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  DB_DIALECT\n-  Database dialect. Supported values: mysql, postgres, supabase\n\n---\n\n-  DB_HOST\n-  Hostname of the database server.\n\n---\n\n-  DB_PORT\n-  Port of the database server.\n-  3306\n\n---\n\n-  DB_USER\n-  Username for the database.\n\n---\n\n-  DB_PASSWORD\n-  Password for the database.\n\n---\n\n-  DB_NAME\n-  Name of the database to use.\n\n---\n\n-  DB_MAX_IDLE_CONNECTION\n-  Number of maximum idle connection.\n-  2\n\n---\n\n-  DB_MAX_OPEN_CONNECTION\n-  Number of maximum connections which can be used with database.\n-  0 (unlimited)\n---\n\n-  DB_SSL_MODE\n-  TLS/SSL mode for database connections. Supported modes: **disable** (no TLS), **preferred** (attempts TLS, falls back to plain), **require** (enforces TLS, skips validation), **skip-verify** (enforces TLS, no certificate validation), **verify-ca** (enforces TLS, validates certificate against CA), **verify-full** (enforces TLS with full validation including hostname). Currently supported for MySQL/MariaDB and PostgreSQL.\n-  disable\n\n---\n\n- DB_TLS_CA_CERT\n- Path to CA certificate file for TLS connections. Required for **verify-ca** and **verify-full** SSL modes.\n- None\n\n---\n\n- DB_TLS_CLIENT_CERT\n- Path to client certificate file for mutual TLS authentication.\n- None\n\n---\n\n- DB_TLS_CLIENT_KEY\n- Path to client private key file for mutual TLS authentication.\n- None\n\n---\n\n- DB_REPLICA_HOSTS\n- Comma-separated list of replica database hosts. Used for read replicas.\n- None\n\n---\n\n- DB_REPLICA_PORTS\n- Comma-separated list of replica database ports. Used for read replicas.\n- None\n\n---\n\n- DB_REPLICA_USERS\n- Comma-separated list of replica database users. Used for read replicas.\n- None\n\n---\n\n- DB_REPLICA_PASSWORDS\n- Comma-separated list of replica database passwords. Used for read replicas.\n- None\n\n---\n\n- DB_REPLICA_MAX_IDLE_CONNECTIONS\n- Maximum idle connections allowed for a replica\n- 50\n\n---\n\n- DB_REPLICA_MIN_IDLE_CONNECTIONS\n- Minimum idle connections for a replica\n- 10\n\n---\n\n- DB_REPLICA_DEFAULT_IDLE_CONNECTIONS\n- Idle connections used if no primary setting is provided\n- 10\n\n---\n\n- DB_REPLICA_MAX_OPEN_CONNECTIONS\n- Maximum open connections allowed for a replica\n- 200\n\n---\n\n- DB_REPLICA_MIN_OPEN_CONNECTIONS\n- Minimum open connections for a replica\n- 50\n\n---\n\n- DB_REPLICA_DEFAULT_OPEN_CONNECTIONS\n- Open connections used if no primary setting is provided\n- 100\n\n---\n\n\n- DB_CHARSET\n- The character set for database connection\n- utf8\n\n---\n\n- SUPABASE_CONNECTION_TYPE \n- Connection type to Supabase. Supported values: direct, session, transaction \n- direct\n\n---\n\n- SUPABASE_PROJECT_REF \n- Supabase project reference ID\n\n---\n\n- SUPABASE_REGION \n- Supabase region for pooled connections\n\n---\n\n- DB_URL \n- Full PostgreSQL connection string for Supabase (alternative to separate config parameters)\n\n{% /table %}\n\n### Redis\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  REDIS_HOST\n-  Hostname of the Redis server.\n-  localhost\n\n---\n\n-  REDIS_PORT\n-  Port of the Redis server.\n-  6379\n\n---\n\n- REDIS_USER\n- Username for the Redis server (optional).\n-  \"\"\n\n---\n\n- REDIS_PASSWORD\n- Password for the Redis server (optional).\n-  \"\"\n\n---\n\n- REDIS_DB\n- Database number to use for the Redis server.\n-  0\n\n---\n\n- REDIS_TLS_ENABLED\n- Enable TLS for Redis connections.\n-  false\n\n---\n\n- REDIS_TLS_CA_CERT\n- Path to the TLS CA certificate file for Redis (or PEM-encoded string).\n-  \"\"\n\n---\n\n- REDIS_TLS_CERT\n- Path to the TLS certificate file for Redis (or PEM-encoded string).\n-  \"\"\n\n---\n\n- REDIS_TLS_KEY\n- Path to the TLS key file for Redis (or PEM-encoded string).\n-  \"\"\n\n{% /table %}\n\n**Redis PubSub Configuration:**\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n- REDIS_PUBSUB_DB\n- Redis database number to use only for Redis Pub/Sub (when `PUBSUB_BACKEND=REDIS`). Use a different DB than `REDIS_DB` when running GoFr migrations with Redis Streams mode to avoid `gofr_migrations` key-type collisions.\n- Default: `15` (highest default Redis database, 0-15)\n\n---\n\n- REDIS_PUBSUB_MODE\n- Operation mode: `pubsub` or `streams`.\n- streams\n\n---\n\n- REDIS_STREAMS_CONSUMER_GROUP\n- Consumer group name (required for streams mode).\n-  \"\"\n\n---\n\n- REDIS_STREAMS_CONSUMER_NAME\n- Unique consumer name (optional, auto-generated if empty).\n-  \"\"\n\n---\n\n- REDIS_STREAMS_BLOCK_TIMEOUT\n- Blocking duration for reading new messages using Redis `XREADGROUP`. Lower values (1s-2s) provide faster detection but increase CPU usage. Higher values (10s-30s) reduce CPU usage, ideal for batch processing.\n- 5s\n\n---\n\n- REDIS_STREAMS_PEL_RATIO\n- Ratio of PEL (pending) messages to read vs new messages (0.0-1.0). Controls balance between retry and fresh messages. 0.7 = 70% PEL, 30% new.\n- 0.7\n\n---\n\n- REDIS_STREAMS_MAXLEN\n- Maximum length of the stream (approximate). Prevents streams from growing indefinitely. Set to `0` for unlimited.\n- 0 (unlimited)\n\n{% /table %}\n\n> **Note**: When using GoFr migrations with Streams mode, keep `REDIS_DB` and `REDIS_PUBSUB_DB` separate (defaults: 0 and 15). For `REDIS_STREAMS_BLOCK_TIMEOUT`: use 1s-2s for real-time or 10s-30s for batch processing.\n\n### Pub/Sub\n\n{% table %}\n\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  PUBSUB_BACKEND\n-  Pub/Sub message broker backend wired automatically by `gofr.New()`. Accepted values: `kafka`, `google`, `mqtt`, `redis` (case-insensitive). Other backends (NATS JetStream, AWS SQS, Azure Event Hub) are wired explicitly via `app.AddPubSub(...)`.\n-  \n\n{% /table %}\n\n**Kafka**\n\n{% table %}\n\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  PUBSUB_BROKER\n-  Comma-separated list of broker addresses\n-  localhost:9092\n\n---\n\n-  PARTITION_SIZE\n-  Size of each message partition (in bytes)\n-  0\n\n---\n\n-  PUBSUB_OFFSET\n-  Offset to start consuming messages from. -1 for earliest, 0 for latest.\n-  -1\n\n---\n\n- KAFKA_BATCH_SIZE\n- Number of messages to batch before sending to Kafka\n- 1\n\n---\n\n- KAFKA_BATCH_BYTES\n- Number of bytes to batch before sending to Kafka\n- 1048576\n\n---\n\n- KAFKA_BATCH_TIMEOUT\n- Time to wait before sending a batch to Kafka\n- 100ms\n\n---\n\n-  CONSUMER_ID\n-  Unique identifier for this consumer\n-  gofr-consumer\n\n---\n\n---\n\n- KAFKA_SECURITY_PROTOCOL\n- Security protocol used to communicate with Kafka (e.g., PLAINTEXT, SSL, SASL_PLAINTEXT, SASL_SSL)\n- PLAINTEXT\n\n---\n\n\n- KAFKA_SASL_MECHANISM\n- SASL mechanism for authentication (e.g. PLAIN, SCRAM-SHA-256, SCRAM-SHA-512)\n- None\n\n---\n\n- KAFKA_SASL_USERNAME\n- Username for SASL authentication\n- None\n\n---\n\n- KAFKA_SASL_PASSWORD\n- Password for SASL authentication\n- None\n\n---\n\n- KAFKA_TLS_CERT_FILE\n- Path to the TLS certificate file\n- None\n\n---\n\n- KAFKA_TLS_KEY_FILE\n- Path to the TLS key file\n- None\n\n---\n\n- KAFKA_TLS_CA_CERT_FILE\n- Path to the TLS CA certificate file\n- None\n\n---\n\n- KAFKA_TLS_INSECURE_SKIP_VERIFY\n- Skip TLS certificate verification\n- false\n\n{% /table %}\n\n**Google**\n\n{% table %}\n\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  GOOGLE_PROJECT_ID\n-  ID of the Google Cloud project. Required for Google Pub/Sub.\n-  None\n\n---\n\n-  GOOGLE_SUBSCRIPTION_NAME\n-  Name of the Google Pub/Sub subscription. Required for Google Pub/Sub.\n-  None\n\n---\n\n-  GOOGLE_MAX_OUTSTANDING_MESSAGES\n-  Max messages the client holds waiting for delivery to the handler, per subscribed topic (the memory/goroutine bound, not the handler concurrency). 0 uses the default; a negative value means no limit.\n-  1000\n\n---\n\n-  GOOGLE_MAX_OUTSTANDING_BYTES\n-  Max total size (bytes) of messages held waiting for delivery, per subscribed topic. 0 uses the default; a negative value means no limit.\n-  1000000000\n\n---\n\n-  GOOGLE_NUM_GOROUTINES\n-  Number of StreamingPull streams opened by the subscriber, per subscribed topic. It is the stream count, not handler concurrency, and does not raise throughput under GoFr's one-message-at-a-time delivery. 0 or a negative value uses the default.\n-  10\n\n{% /table %}\n\n**MQTT**\n\n{% table %}\n\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  MQTT_PORT\n-  Port of the MQTT broker\n-  1883\n\n---\n\n-  MQTT_MESSAGE_ORDER\n-  Enable guaranteed message order\n-  false\n\n---\n\n-  MQTT_PROTOCOL\n-  Communication protocol. Supported values: tcp, ssl.\n-  tcp\n\n---\n\n-  MQTT_HOST\n-  Hostname of the MQTT broker\n-  localhost\n\n---\n\n-  MQTT_USER\n-  Username for the MQTT broker\n\n---\n\n-  MQTT_PASSWORD\n-  Password for the MQTT broker\n\n---\n\n-  MQTT_CLIENT_ID_SUFFIX\n-  Suffix appended to the client ID\n\n---\n\n-  MQTT_QOS\n-  Quality of Service Level\n\n---\n\n-  MQTT_KEEP_ALIVE\n-  Sends regular messages to check the link is active. May not work as expected if handling func is blocking execution\n\n- MQTT_RETRIEVE_RETAINED\n- Retrieve retained messages on subscription\n\n{% /table %}\n\n**NATS JetStream**\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  NATS_SERVER\n-  URL of the NATS server. The NATS driver is wired explicitly via `app.AddPubSub(...)`; this row is a convention only — the actual env-var name is whatever you read from `app.Config.Get(...)` and pass into `nats.Config.Server`.\n-  nats://localhost:4222\n\n---\n\n-  NATS_CREDS_FILE\n-  File containing the NATS credentials\n- creds.json\n\n{% /table %}\n\n\n\n## Related production guides\n\n- **12-Factor Configuration**: [Env-driven config, secrets, and environment parity](/docs/guides/twelve-factor-config) — apply 12-factor methodology to the configs documented above.\n","docs/references/gofrcli/page.md":"---\ndescription: \"Use the GoFr CLI to scaffold projects, generate boilerplate, and run framework-aware tasks. Speeds up repetitive work and keeps services consistent.\"\nnextjs:\n  metadata:\n    title: \"GoFr CLI Reference — Project Scaffolding and Tooling\"\n    description: \"Use the GoFr CLI to scaffold projects, generate boilerplate, and run framework-aware tasks. Speeds up repetitive work and keeps services consistent.\"\n---\n\n# GoFR Command Line Interface\n\nManaging repetitive tasks and maintaining consistency across large-scale applications is challenging!\n\n**GoFr CLI provides the following:**\n\n* All-in-one command-line tool designed specifically for GoFr applications\n* Simplifies **database migrations** management\n* **Store Layer Generator** for type-safe data access code from YAML configurations\n* Abstracts **tracing**, **metrics** and structured **logging** for GoFr's gRPC server/client\n* Enforces standard **GoFr conventions** in new projects\n\n## Prerequisites\n\n- Go 1.25 or above. To check Go version use the following command:\n```bash\n  go version\n```\n\n## **Installation**\nTo get started with GoFr CLI, use the below commands\n\n```bash\n  go install gofr.dev/cli/gofr@latest\n```\n\nTo check the installation:\n```bash\n  gofr version\n```\n---\n\n## Usage\n\nThe CLI can be run directly from the terminal after installation. Here’s the general syntax:\n\n```bash\n  gofr <subcommand> [flags]=[arguments]\n```\n---\n\n## Commands\n\nThe CLI groups its functionality into four commands. See each subpage for full reference:\n\n- [`gofr init`](/docs/references/gofrcli/init) — initialize a new GoFr project with the standard layout.\n- [`gofr migrate`](/docs/references/gofrcli/migrate) — create database migration templates with timestamped filenames and an auto-generated registry.\n- [`gofr wrap grpc`](/docs/references/gofrcli/wrap-grpc) — generate gRPC server/client wrappers with built-in tracing, metrics, and logging.\n- [`gofr store`](/docs/references/gofrcli/store) — generate a type-safe data-access layer from YAML schema definitions.\n","docs/references/gofrcli/migrate/page.md":"---\ndescription: \"Generate timestamped database migration templates with an auto-maintained registry using the gofr migrate create command.\"\nnextjs:\n  metadata:\n    title: \"gofr migrate create — Generate Database Migration Templates\"\n    description: \"Generate timestamped database migration templates with an auto-maintained registry using the gofr migrate create command.\"\n---\n\n# gofr migrate create\n\nThe migrate create command generates a migration template file with pre-defined structure in your migrations directory.\nThis boilerplate code helps you maintain consistent patterns when writing database schema modifications across your project.\n\n\n## Command Usage\n```bash\n  gofr migrate create -name=<migration-name>\n```\n\n## Example Usage\n\n```bash\ngofr migrate create -name=create_employee_table\n```\nThis command generates a migration directory which has the below files:\n\n1. A new migration file with timestamp prefix (e.g., `20250127152047_create_employee_table.go`) containing:\n```go\npackage migrations\n\nimport (\n  \"gofr.dev/pkg/gofr/migration\"\n)\n\nfunc create_employee_table() migration.Migrate {\n  return migration.Migrate{\n    UP: func(d migration.Datasource) error {\n      // write your migrations here\n      return nil\n    },\n  }\n}\n```\n2. An auto-generated all.go file that maintains a registry of all migrations:\n```go\n// This is auto-generated file using 'gofr migrate' tool. DO NOT EDIT.\npackage migrations\n\nimport (\n  \"gofr.dev/pkg/gofr/migration\"\n)\n\nfunc All() map[int64]migration.Migrate {\n  return map[int64]migration.Migrate {\n    20250127152047: create_employee_table(),\n  }\n}\n```\n\n> **💡 Best Practice:** Learn about [organizing migrations by feature](/docs/advanced-guide/handling-data-migrations#organizing-migrations-by-feature) to avoid creating one migration per table or operation.\n\nFor detailed instructions on handling database migrations, see the [handling-data-migrations documentation](/docs/advanced-guide/handling-data-migrations)\nFor more examples, see the [using-migrations](https://github.com/gofr-dev/gofr/tree/main/examples/using-migrations)\n\n---\n\n## See also\n\n- [GoFr CLI overview](/docs/references/gofrcli)\n- [`gofr init`](/docs/references/gofrcli/init)\n- [`gofr wrap grpc`](/docs/references/gofrcli/wrap-grpc)\n- [`gofr store`](/docs/references/gofrcli/store)\n","docs/references/gofrcli/init/page.md":"---\ndescription: \"Initialize a new GoFr project with the standard layout and a Hello World starter program using the gofr init command.\"\nnextjs:\n  metadata:\n    title: \"gofr init — Initialize a New GoFr Project\"\n    description: \"Initialize a new GoFr project with the standard layout and a Hello World starter program using the gofr init command.\"\n---\n\n# gofr init\n\nThe init command initializes a new GoFr project. It sets up the foundational structure for the project and generates a basic \"Hello World!\" program as a starting point. This allows developers to quickly dive into building their application with a ready-made structure.\n\n## Command Usage\n```bash\n  gofr init\n```\n\n---\n\n## See also\n\n- [GoFr CLI overview](/docs/references/gofrcli)\n- [`gofr migrate`](/docs/references/gofrcli/migrate)\n- [`gofr wrap grpc`](/docs/references/gofrcli/wrap-grpc)\n- [`gofr store`](/docs/references/gofrcli/store)\n","docs/references/context/page.md":"---\ndescription: \"GoFr's ctx is injected into every handler. It carries request data plus the container of dependencies — DBs, logger, HTTP clients, and metrics — for the cycle.\"\nnextjs:\n  metadata:\n    title: \"GoFr Context Reference — Request Container API\"\n    description: \"GoFr's ctx is injected into every handler. It carries request data plus the container of dependencies — DBs, logger, HTTP clients, and metrics — for the cycle.\"\n---\n\n# GoFr Context\n\nGoFr context is an object injected by the GoFr handler. It contains all the request-specific data, for each\nrequest-response cycle a new context is created. The request can be either an HTTP request, gRPC call or\na message from Pub-Sub.\nGoFr Context also embeds the **_container_** which maintains all the dependencies like databases, logger, HTTP service clients,\nmetrics manager, etc. This reduces the complexity of the application as users don't have to maintain and keep track of\nall the dependencies by themselves.\n\nGoFr context is an extension of the Go context, providing a wrapper around the request and response providing\nuser access to dependencies.\n\n# Usage\n\n## Reading HTTP requests\n\n`ctx.Request` can be used to access the underlying request which provides the following methods to access different\nparts of the request.\n\n- `Context()` - to access the context associated with the incoming request\n\n```go\nctx.Request.Context()\n```\n\n- `Param(string)` - to access the query parameters present in the request, it returns the value of the key provided\n\n```go\n// Example: Request is /configs?key1=value1&key2=value2\nvalue := ctx.Request.Param(\"key1\")\n// value = \"value1\"\n```\n\n- `PathParam(string)` - to retrieve the path parameters\n  ```go\n  // Consider the path to be /employee/{id}\n  id := ctx.Request.PathParam(\"id\")\n  ```\n- `Bind(any)` - to access a decoded format of the request body, the body is mapped to the interface provided\n\n```go\n// incoming request body is\n// {\n//    \"name\" : \"trident\",\n//    \"category\" : \"snacks\"\n// }\n\ntype product struct{\n  Name string `json:\"name\"`\n  Category string `json:\"category\"`\n}\n\nvar p product\nctx.Bind(&p)\n// the Bind() method will map the incoming request to variable p\n```\n\n> **Pass a pointer.** `Bind` needs the address of your variable (`&p`) so it can write into it.\n> For an HTTP request, passing a value (`ctx.Bind(p)`) returns an error rather than silently\n> leaving your variable untouched. Always check the returned error:\n>\n> ```go\n> if err := ctx.Bind(&p); err != nil {\n>     return nil, err\n> }\n> ```\n\nThe `Content-Type` header selects how the body is decoded. It is matched case-insensitively and\nany parameters are ignored, so `application/json`, `Application/JSON` and\n`application/json; charset=utf-8` are all treated the same.\n\nIf a request carries a body whose `Content-Type` GoFr has no decoder for — `text/plain`,\n`application/xml`, or no header at all — `Bind` is a **no-op**: it returns no error and leaves\nyour target zeroed, and the body is discarded. Check the `Content-Type` your clients actually\nsend. `fetch(url, {method: \"POST\", body: str})` with no headers sends `text/plain`, not JSON, so\na request that looks correct can bind nothing.\n\n- `Binding multipart-form data / urlencoded form data `\n  - To bind multipart-form data or url-encoded form, we can use the Bind method similarly. The struct fields should be tagged appropriately\n    to map the form fields to the struct fields. The supported content types are `multipart/form-data` and `application/x-www-form-urlencoded`\n\n```go\ntype Data struct {\n\tName string `form:\"name\"`\n\n\tCompressed file.Zip `file:\"upload\"`\n\n\tFileHeader *multipart.FileHeader `file:\"file_upload\"`\n}\n```\n\n  - The `form` tag is used to bind non-file fields.\n  - The `file` tag is used to bind file fields. If the tag is not present, the field name is used as the key.\n\n\n- `HostName()` - to access the host name for the incoming request\n\n```go\n// for example if request is made from xyz.com\n  host := ctx.Request.HostName()\n  // the host would be http://xyz.com\n  // Note: the protocol if not provided in the headers will be set to http by default\n```\n\n- `Params(string)` - to access all query parameters for a given key returning slice of strings.\n\n```go\n// Example: Request is /search?category=books,electronics&category=tech\nvalues := ctx.Request.Params(\"category\")\n// values = []string{\"books\", \"electronics\", \"tech\"}\n```\n\n\n## Accessing Authentication Information\n\nGoFr provides a helper method to access authentication details from the context.\nThese values are populated when the respective authentication middleware is enabled (see [HTTP Auth Middleware](https://github.com/gofr-dev/gofr/blob/0845d19181d2cc55e12c557fc9ad51adb4ab44fd/examples/using-http-auth-middleware/ReadMe.md) section).\n\n```go\ninfo := ctx.GetAuthInfo()\n```\n\n### Methods\n\n* **`GetClaims()`** – Returns the JWT claims containing standard fields such as:\n\n  * `Issuer` – identifies who issued the token.\n  * `Subject` – identifies the principal that is the subject of the token.\n  * `Audience` – identifies the intended recipients of the token.\n  * `NotBefore` – time before which the token is not valid.\n  * `IssuedAt` – time at which the token was issued.\n  * `ExpirationTime` – time after which the token expires.\n\n  **Requires:** OAuth middleware (`EnableOAuth`)\n\n* **`GetUsername()`** – Returns the authenticated username when using Basic Authentication.\n\n  **Requires:** Basic Auth middleware (`EnableBasicAuthWithValidator`)\n\n* **`GetAPIKey()`** – Returns the API key used for authentication.\n\n  **Requires:** API Key middleware (`EnableAPIKeyAuthWithValidator`)\n\n> Note: These values will be available only if the respective authentication middleware is enabled in the application.\n\n\n## Accessing dependencies\n\nGoFr context embeds the container object which provides access to\nall the injected dependencies by the users. Users can access the fields and methods provided\nby the **_container_**.\n","docs/references/gofrcli/store/page.md":"---\ndescription: \"Generate a type-safe data-access layer from YAML schema definitions using the gofr store command, with built-in observability and registry support.\"\nnextjs:\n  metadata:\n    title: \"gofr store — Generate Type-Safe Data-Access Layers from YAML\"\n    description: \"Generate a type-safe data-access layer from YAML schema definitions using the gofr store command, with built-in observability and registry support.\"\n---\n\n# gofr store\n\n> **Available since:** `gofr-cli` **v0.8.1**\n\nThe `gofr store` command is a code generator that creates type-safe data access layers from YAML configuration files. It eliminates boilerplate code while maintaining GoFr's best practices for observability and context management.\n\n## **Features**\n\n* **YAML-Driven Configuration**: Define your data models and queries in a simple, declarative format.\n* **Type-Safe Code Generation**: Generates Go interfaces and implementation boilerplates.\n* **GoFr Context Integration**: Generated methods work with `*gofr.Context` for built-in observability.\n* **Multiple Stores**: Define all stores in a single YAML file — each gets its own directory.\n* **Store Registry**: Centralized factory management of all generated stores via `stores/all.go`.\n\n## **Commands**\n\n### **Initialize Store Configuration**\n\nCreate a new store directory and a `store.yaml` configuration template. **The `-name` flag is required.**\n\n```bash\ngofr store init -name=<store-name>\n```\n\n**Example:**\n```bash\ngofr store init -name=user\n```\n\nThis creates the following structure:\n- `stores/store.yaml` — Configuration file template (shared across all stores).\n- `stores/all.go` — Store registry factory (auto-generated, DO NOT EDIT).\n- `stores/user/interface.go` — Initial interface stub (DO NOT EDIT — regenerated by `generate`).\n- `stores/user/user.go` — Initial implementation stub (editable — add your SQL logic here).\n\n### **Generate Store Code**\n\nGenerate or update Go code from your store configuration file.\n\n```bash\ngofr store generate\n```\n\n> **💡 Note:** By default, this command looks for the configuration at **`stores/store.yaml`**. To use a different path, use the `-config` flag:\n> ```bash\n> gofr store generate -config=path/to/store.yaml\n> ```\n\n---\n\n## **Quick Start Example**\n\n**Step 1: Initialize Configuration**\n```bash\ngofr store init -name=user\n```\n\n**Step 2: Define Your Store in `stores/store.yaml`**\n```yaml\nversion: \"1.0\"\n\nstores:\n  - name: \"user\"\n    package: \"user\"\n    output_dir: \"stores/user\"\n    interface: \"UserStore\"\n    implementation: \"userStore\"\n    queries:\n      - name: \"GetUserByID\"\n        sql: \"SELECT id, name, email FROM users WHERE id = ?\"\n        type: \"select\"\n        model: \"User\"\n        returns: \"single\"\n        params:\n          - name: \"id\"\n            type: \"int64\"\n        description: \"Retrieves a user by their ID\"\n\n      - name: \"GetAllUsers\"\n        sql: \"SELECT id, name, email FROM users\"\n        type: \"select\"\n        model: \"User\"\n        returns: \"multiple\"\n        description: \"Retrieves all users\"\n\nmodels:\n  - name: \"User\"\n    fields:\n      - name: \"ID\"\n        type: \"int64\"\n        tag: 'db:\"id\" json:\"id\"'\n      - name: \"Name\"\n        type: \"string\"\n        tag: 'db:\"name\" json:\"name\"'\n      - name: \"Email\"\n        type: \"string\"\n        tag: 'db:\"email\" json:\"email\"'\n```\n\n**Step 3: Generate Store Code**\n```bash\ngofr store generate\n```\n\nThis generates:\n```text\nstores/\n├── store.yaml          # Central Configuration\n├── all.go              # Store registry factory (auto-generated)\n└── user/\n    ├── interface.go    # UserStore interface definition\n    ├── userStore.go    # userStore implementation boilerplate\n    └── user.go         # User model struct\n```\n\n**Step 4: Use in Your Application**\n```go\npackage main\n\nimport (\n    \"gofr.dev/pkg/gofr\"\n    \"your-project/stores/user\"\n)\n\nfunc main() {\n    app := gofr.New()\n\n    userStore := user.NewUserStore()\n\n    app.GET(\"/users/{id}\", func(ctx *gofr.Context) (interface{}, error) {\n        id, _ := strconv.ParseInt(ctx.PathParam(\"id\"), 10, 64)\n        return userStore.GetUserByID(ctx, id)\n    })\n\n    app.GET(\"/users\", func(ctx *gofr.Context) (interface{}, error) {\n        return userStore.GetAllUsers(ctx)\n    })\n\n    app.Run()\n}\n```\n\n---\n\n## **Multiple Stores in One File**\n\nYou can define all stores in a single YAML file. Each store gets its own output directory and all are registered into the same `stores/all.go` registry.\n\n```yaml\nversion: \"1.0\"\n\nstores:\n  - name: \"user\"\n    package: \"user\"\n    output_dir: \"stores/user\"\n    interface: \"UserStore\"\n    implementation: \"userStore\"\n    queries: [...]\n\n  - name: \"product\"\n    package: \"product\"\n    output_dir: \"stores/product\"\n    interface: \"ProductStore\"\n    implementation: \"productStore\"\n    queries: [...]\n\nmodels:\n  - name: \"User\"\n    fields: [...]\n  - name: \"Product\"\n    fields: [...]\n```\n\n**Generated structure:**\n```text\nstores/\n├── all.go\n├── user/\n│   ├── interface.go\n│   ├── userStore.go\n│   └── user.go\n└── product/\n    ├── interface.go\n    ├── productStore.go\n    └── product.go\n```\n\n**Using the registry with multiple stores:**\n```go\nimport (\n\"your-project/stores\"\n\"your-project/stores/user\"\n\"your-project/stores/product\"\n)\n\n// stores.GetStore returns a factory-created instance\nuserStore    := stores.GetStore(\"user\").(user.UserStore)\nproductStore := stores.GetStore(\"product\").(product.ProductStore)\n```\n\n> **💡 Note:** `stores.All()` returns a `map[string]func() any` — a map of **factory functions**, not active instances. `stores.GetStore(name)` calls the factory for you and returns the instance.\n\n---\n\n## **Configuration Reference**\n\n### **Store Configuration**\n\n| Field | Description | Required |\n|-------|-------------|----------|\n| `name` | Store identifier used in the registry key. | **Yes** |\n| `package` | Go package name for generated code. | **Yes** |\n| `output_dir` | Directory path where files will be generated. | Optional (defaults to `stores/<name>`) |\n| `interface` | Interface name — **recommended: `<Name>Store`** (e.g., `UserStore`). | Optional (defaults to `<Name>Store`) |\n| `implementation` | Private struct name for the implementation (e.g., `userStore`). | Optional (defaults to `<name>Store`) |\n| `queries` | List of database queries. | Optional |\n\n> **⚠️ Naming Convention:** The registry (`stores/all.go`) uses a hardcoded `<Name>Store` pattern when generating constructor calls (e.g., `NewUserStore()`). Always name your interface as `<Name>Store` to avoid compilation errors.\n\n### **Query Types**\n\n* **`select`** — SELECT queries.\n* **`insert`** — INSERT queries.\n* **`update`** — UPDATE queries.\n* **`delete`** — DELETE queries.\n\n### **Return Types**\n\n* **`single`** — Returns `(Model, error)`.\n* **`multiple`** — Returns `([]Model, error)`.\n* **`count`** — Returns `(int64, error)`.\n* **`custom`** — Returns `(any, error)`.\n\n### **Query Parameters**\n\n```yaml\nparams:\n  - name: \"id\"\n    type: \"int64\"\n  - name: \"email\"\n    type: \"string\"\n```\n\nSupported parameter types include all Go primitive types, `time.Time`, and pointer types (e.g., `*int64`).\n\n---\n\n## **Model Generation**\n\n### **Generate New Models**\n\n```yaml\nmodels:\n  - name: \"User\"\n    fields:\n      - name: \"ID\"\n        type: \"int64\"\n        tag: 'db:\"id\" json:\"id\"'\n      - name: \"Name\"\n        type: \"string\"\n        tag: 'db:\"name\" json:\"name\"'\n      - name: \"CreatedAt\"\n        type: \"time.Time\"\n        tag: 'db:\"created_at\" json:\"created_at\"'\n```\n\nThis generates:\n```go\ntype User struct {\nID        int64     `db:\"id\" json:\"id\"`\nName      string    `db:\"name\" json:\"name\"`\nCreatedAt time.Time `db:\"created_at\" json:\"created_at\"`\n}\n\nfunc (User) TableName() string {\nreturn \"user\"\n}\n```\n\n### **Reference Existing Models**\n\nIf you already have models defined elsewhere:\n\n```yaml\nmodels:\n  - name: \"User\"\n    path: \"../models/user.go\"\n    package: \"your-project/models\"\n```\n\n---\n\n## **Generated Code Structure**\n\n### **Interface (`interface.go`)**\n\n```go\n// Code generated by gofr.dev/cli/gofr. DO NOT EDIT.\npackage user\n\nimport \"gofr.dev/pkg/gofr\"\n\ntype UserStore interface {\n  GetUserByID(ctx *gofr.Context, id int64) (User, error)\n  GetAllUsers(ctx *gofr.Context) ([]User, error)\n}\n```\n\n### **Implementation (`userStore.go`)**\n\n```go\n// Code generated by gofr.dev/cli/gofr. DO NOT EDIT.\npackage user\n\ntype userStore struct{}\n\nfunc NewUserStore() UserStore {\n   return &userStore{}\n}\n\nfunc (s *userStore) GetUserByID(ctx *gofr.Context, id int64) (User, error) {\n   // TODO: Implement using ctx.SQL()\n   var result User\n   // err := ctx.SQL().QueryRowContext(ctx, sql, id).Scan(&result.ID, ...)\n   return result, nil\n}\n\nfunc (s *userStore) GetAllUsers(ctx *gofr.Context) ([]User, error) {\n   // TODO: Implement using ctx.SQL()\n   return []User{}, nil\n}\n```\n\n---\n\n## **Best Practices**\n\n1. **Implement the TODOs**: The generator creates method **signatures and boilerplate only**. You must fill in the `// TODO: Implement` sections with actual SQL execution using `ctx.SQL()` methods.\n2. **Use `<Name>Store` Interface Names**: The registry assumes this convention. E.g., `interface: \"UserStore\"` results in the constructor `NewUserStore()` and type assertion `.(user.UserStore)`.\n3. **One YAML, Many Stores**: Define all your stores in a single `store.yaml` to keep your data access layer centrally configured.\n4. **Know Which Files Are Auto-Generated**: Only `interface.go` and `all.go` are marked `DO NOT EDIT` and are overwritten on every `gofr store generate`. The implementation stub (`<name>.go`) created by `gofr store init` is editable — this is where you add your SQL logic. The `userStore.go` generated by `gofr store generate` is also editable boilerplate.\n5. **Version Control**: Always commit your `store.yaml`. Re-run `gofr store generate` after any configuration change to sync the generated interfaces.\n\n---\n\n## **Complete Example**\n\nFor a complete working example of the store generator, see the [store example](https://github.com/gofr-dev/gofr-cli/tree/main/store/example.yaml) in the gofr-cli repository.\n\nFor detailed configuration options and advanced usage, refer to the [Store Generator README](https://github.com/gofr-dev/gofr-cli/blob/main/store/README.md).\n\n---\n\n## See also\n\n- [GoFr CLI overview](/docs/references/gofrcli)\n- [`gofr init`](/docs/references/gofrcli/init)\n- [`gofr migrate`](/docs/references/gofrcli/migrate)\n- [`gofr wrap grpc`](/docs/references/gofrcli/wrap-grpc)\n","docs/references/testing/page.md":"---\ndescription: \"Write unit and integration tests for GoFr REST APIs. Mock the container's dependencies and assert handler responses, status codes, and headers reliably.\"\nnextjs:\n  metadata:\n    title: \"Testing GoFr REST APIs — Handlers, Mocks, Assertions\"\n    description: \"Write unit and integration tests for GoFr REST APIs. Mock the container's dependencies and assert handler responses, status codes, and headers reliably.\"\n---\n\n# Testing REST APIs with GoFr\n\nTesting REST APIs ensures that your endpoints function correctly under various conditions. This guide demonstrates how to write tests for GoFr-based REST APIs.\n\n## Mocking Databases in GoFr\n\nMocking databases allows for isolated testing by simulating various scenarios. GoFr's built-in mock container supports, not only SQL databases, but also extends to other data stores, including Redis, Cassandra, Key-Value stores, MongoDB, and ClickHouse.\n\n### Mocking `Select` Queries\n\n`Select` reads rows into a destination, so its mock takes the response you want written into that destination. Pass a pointer of the destination's type to `ExpectSelect`, along with the exact query text and arguments your handler uses, then set the rows with `ReturnsResponse`:\n\n```go\nvar users []User\n\nmock.SQL.ExpectSelect(ctx, &users, \"SELECT id, name FROM users WHERE status = ?\", \"active\").\n\tReturnsResponse([]User{{ID: 1, Name: \"John\"}})\n```\n\nWhen the handler calls `ctx.SQL.Select(ctx, &dest, \"SELECT id, name FROM users WHERE status = ?\", \"active\")`, `dest` is set to the response.\n\nThe query text must match exactly, and the arguments must have the same count, values and types (compared with `reflect.DeepEqual`, so slices such as `IN` lists are supported). If the query or arguments do not match, the destination is left untouched and the test fails with a message showing the expected and actual values.\n\n## Example of Unit Testing a REST API Using GoFr\n\nBelow is an example of how to test, say the `Add` method of a handler that interacts with a SQL database.\n\nHere’s an `Add` function for adding a book to the database using GoFr:\n\n```go\n// main.go\npackage main\n\nimport (\n\t\"gofr.dev/pkg/gofr\"\n\t\"gofr.dev/pkg/gofr/http\"\n)\n\ntype Book struct {\n\tId    int    `json:\"id\"`\n\tISBN  int    `json:\"isbn\"`\n\tTitle string `json:\"title\"`\n}\n\nfunc Add(ctx *gofr.Context) (any, error) {\n\tvar book Book\n\n\tif err := ctx.Bind(&book); err != nil {\n\t\tctx.Logger.Errorf(\"error in binding: %v\", err)\n\t\treturn nil, http.ErrorInvalidParam{Params: []string{\"body\"}}\n\t}\n\n\t// we assume the `id` column in the database is set to auto-increment.\n\tres, err := ctx.SQL.ExecContext(ctx, `INSERT INTO books (title, isbn) VALUES (?, ?)`, book.Title, book.ISBN)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tid, err := res.LastInsertId()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn id, nil\n}\n\nfunc main() {\n\t// initialize gofr object\n\tapp := gofr.New()\n\n\tapp.POST(\"/book\", Add)\n\n\t// Run the application\n\tapp.Run()\n}\n\n```\n\nHere’s how to write tests using GoFr:\n\n```go\n// main_test.go\npackage main\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"database/sql\"\n\t\"errors\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"gofr.dev/pkg/gofr\"\n\t\"gofr.dev/pkg/gofr/container\"\n\tgofrHttp \"gofr.dev/pkg/gofr/http\"\n)\n\nfunc TestAdd(t *testing.T) {\n\ttype gofrResponse struct {\n\t\tresult any\n\t\terr    error\n\t}\n\n\t// NewMockContainer provides mock implementations for various databases including:\n\t// Redis, SQL, ClickHouse, Cassandra, MongoDB, and KVStore.\n\t// These mock can be used to define database expectations in unit tests,\n\t// similar to the SQL example demonstrated here.\n\tmockContainer, mock := container.NewMockContainer(t)\n\n\tctx := &gofr.Context{\n\t\tContext:   context.Background(),\n\t\tRequest:   nil,\n\t\tContainer: mockContainer,\n\t}\n\n\ttests := []struct {\n\t\tname             string\n\t\trequestBody      string\n\t\tmockExpect       func()\n\t\texpectedResponse any\n\t}{\n\t\t{\n\t\t\tname:        \"Error while Binding\",\n\t\t\trequestBody: `title\":\"Book Title\",\"isbn\":12345}`,\n\t\t\tmockExpect: func() {\n\t\t\t},\n\t\t\texpectedResponse: gofrResponse{\n\t\t\t\tnil,\n\t\t\t\tgofrHttp.ErrorInvalidParam{Params: []string{\"body\"}}},\n\t\t},\n\t\t{\n\t\t\tname:        \"Successful Insertion\",\n\t\t\trequestBody: `{\"title\":\"Book Title\",\"isbn\":12345}`,\n\t\t\tmockExpect: func() {\n\t\t\t\tmock.SQL.\n\t\t\t\t\tExpectExec(`INSERT INTO books (title, isbn) VALUES (?, ?)`).\n\t\t\t\t\tWithArgs(\"Book Title\", 12345).\n\t\t\t\t\tWillReturnResult(sqlmock.NewResult(12, 1))\n\t\t\t},\n\t\t\texpectedResponse: gofrResponse{\n\t\t\t\tint64(12),\n\t\t\t\tnil,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:        \"Error on Insertion\",\n\t\t\trequestBody: `{\"title\":\"Book Title\",\"isbn\":12345}`,\n\t\t\tmockExpect: func() {\n\t\t\t\tmock.SQL.\n\t\t\t\t\tExpectExec(`INSERT INTO books (title, isbn) VALUES (?, ?)`).\n\t\t\t\t\tWithArgs(\"Book Title\", 12345).\n\t\t\t\t\tWillReturnError(sql.ErrConnDone)\n\t\t\t},\n\t\t\texpectedResponse: gofrResponse{\n\t\t\t\tnil,\n\t\t\t\tsql.ErrConnDone},\n\t\t},\n\t\t{\n\t\t\tname:        \"Error while fetching LastInsertId\",\n\t\t\trequestBody: `{\"title\":\"Book Title\",\"isbn\":12345}`,\n\t\t\tmockExpect: func() {\n\t\t\t\tmock.SQL.\n\t\t\t\t\tExpectExec(`INSERT INTO books (title, isbn) VALUES (?, ?)`).\n\t\t\t\t\tWithArgs(\"Book Title\", 12345).\n\t\t\t\t\tWillReturnError(errors.New(\"mocked result error\"))\n\t\t\t},\n\t\t\texpectedResponse: gofrResponse{\n\t\t\t\tnil,\n\t\t\t\terrors.New(\"mocked result error\")},\n\t\t},\n\t}\n\n\tfor i, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ttt.mockExpect()\n\n\t\t\tvar req *http.Request\n\n\t\t\treq = httptest.NewRequest(\n\t\t\t\thttp.MethodPost,\n\t\t\t\t\"/book\",\n\t\t\t\tbytes.NewBuffer([]byte(tt.requestBody)),\n\t\t\t)\n\n\t\t\treq.Header.Set(\"Content-Type\", \"application/json\")\n\n\t\t\trequest := gofrHttp.NewRequest(req)\n\n\t\t\tctx.Request = request\n\n\t\t\tval, err := Add(ctx)\n\n\t\t\tresponse := gofrResponse{val, err}\n\n\t\t\tassert.Equal(t, tt.expectedResponse, response, \"TEST[%d], Failed.\\n%s\", i, tt.name)\n\t\t})\n\t}\n}\n\n```\n\n## Testing HTTP Handlers with Mock Services\n\nWhen you register multiple services with `WithMockHTTPService`, each service gets its own separate mock instance. This allows you to set different expectations for each service using the `mocks.HTTPServices` map. Use table-driven tests to cover multiple scenarios:\n\n### Important Notes\n\n- **Context Matching**: Always use the exact context from your `gofr.Context` (`ctx.Context`) in expectations. gomock compares contexts by reference, not value, so using `t.Context()` or `context.Background()` will fail.\n- **Service Registration**: `WithMockHTTPService(\"serviceName\")` registers the service with the specified name. Each service gets its own separate mock instance.\n- **Multiple Services**: Use `mocks.HTTPServices[\"serviceName\"]` to access and set different expectations for each service. Each service has its own mock instance, so expectations are independent.\n- **Tests will fail** if the mocked HTTPService is not called as expected or if the context doesn't match.\n\n```go\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gofr.dev/pkg/gofr\"\n\t\"gofr.dev/pkg/gofr/container\"\n\tgofrHttp \"gofr.dev/pkg/gofr/http\"\n)\n\n// Handler that calls multiple HTTP services\n// This handler demonstrates calling two different services (paymentService and shippingService)\n// to fetch order details from different parts of the system.\nfunc OrderDetailsHandler(ctx *gofr.Context) (any, error) {\n\torderID := ctx.PathParam(\"id\")\n\tif orderID == \"\" {\n\t\treturn nil, errors.New(\"order ID is required\")\n\t}\n\n\t// First HTTP service call: Get payment details from paymentService\n\tpaymentService := ctx.GetHTTPService(\"paymentService\")\n\tpaymentResp, err := paymentService.Get(ctx.Context, \"/payments/\"+orderID, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to fetch payment details: %w\", err)\n\t}\n\tdefer paymentResp.Body.Close()\n\n\tvar paymentData struct {\n\t\tStatus string `json:\"status\"`\n\t\tAmount int    `json:\"amount\"`\n\t}\n\n\tpaymentBody, err := io.ReadAll(paymentResp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read payment response: %w\", err)\n\t}\n\n\tif err := json.Unmarshal(paymentBody, &paymentData); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse payment response: %w\", err)\n\t}\n\n\t// Second HTTP service call: Get shipping details from shippingService\n\tshippingService := ctx.GetHTTPService(\"shippingService\")\n\tshippingResp, err := shippingService.Get(ctx.Context, \"/shipping/\"+orderID, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to fetch shipping details: %w\", err)\n\t}\n\tdefer shippingResp.Body.Close()\n\n\tvar shippingData struct {\n\t\tStatus           string `json:\"status\"`\n\t\tTracking         string `json:\"tracking\"`\n\t\tEstimatedDelivery string `json:\"estimated_delivery\"`\n\t}\n\n\tshippingBody, err := io.ReadAll(shippingResp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read shipping response: %w\", err)\n\t}\n\n\tif err := json.Unmarshal(shippingBody, &shippingData); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse shipping response: %w\", err)\n\t}\n\n\t// Combine results from both services\n\treturn map[string]any{\n\t\t\"order_id\":          orderID,\n\t\t\"payment_status\":    paymentData.Status,\n\t\t\"payment_amount\":    paymentData.Amount,\n\t\t\"shipping_status\":   shippingData.Status,\n\t\t\"tracking_number\":   shippingData.Tracking,\n\t\t\"estimated_delivery\": shippingData.EstimatedDelivery,\n\t}, nil\n}\n\nfunc TestOrderDetailsHandler(t *testing.T) {\n\t// Helper function to create test context with path parameters\n\tcreateTestContext := func(path string, container *container.Container) *gofr.Context {\n\t\treq := httptest.NewRequest(http.MethodGet, path, nil)\n\t\t\n\t\t// Set path parameters using mux.SetURLVars (required for ctx.PathParam to work)\n\t\tif strings.Contains(path, \"/orders/\") {\n\t\t\tparts := strings.Split(strings.Trim(path, \"/\"), \"/\")\n\t\t\tif len(parts) >= 2 && parts[1] != \"\" {\n\t\t\t\treq = mux.SetURLVars(req, map[string]string{\"id\": parts[1]})\n\t\t\t}\n\t\t}\n\n\t\treturn &gofr.Context{\n\t\t\tContext:   req.Context(),\n\t\t\tRequest:   gofrHttp.NewRequest(req),\n\t\t\tContainer: container,\n\t\t}\n\t}\n\n\tconst testOrderID = \"12345\" // Reusable order ID for tests\n\n\ttests := []struct {\n\t\tname           string\n\t\tsetupMocks     func(*container.Mocks, *gofr.Context)\n\t\trequestPath    string\n\t\twantErr        bool\n\t\twantErrMsg     string\n\t\tvalidateResult func(*testing.T, any)\n\t}{\n\t\t{\n\t\t\tname: \"successful order details retrieval\",\n\t\t\tsetupMocks: func(mocks *container.Mocks, ctx *gofr.Context) {\n\t\t\t\t// Set up expectation for paymentService - this is the first HTTP call in the handler\n\t\t\t\tpaymentResp := &http.Response{\n\t\t\t\t\tStatusCode: http.StatusOK,\n\t\t\t\t\tBody:       io.NopCloser(strings.NewReader(`{\"status\":\"completed\",\"amount\":1500}`)),\n\t\t\t\t}\n\t\t\t\tmocks.HTTPServices[\"paymentService\"].EXPECT().Get(\n\t\t\t\t\tctx.Context,\n\t\t\t\t\t\"/payments/\"+testOrderID,\n\t\t\t\t\tnil,\n\t\t\t\t).Return(paymentResp, nil)\n\n\t\t\t\t// Set up expectation for shippingService - this is the second HTTP call in the handler\n\t\t\t\t// Note: Each service has its own independent mock instance\n\t\t\t\tshippingResp := &http.Response{\n\t\t\t\t\tStatusCode: http.StatusOK,\n\t\t\t\t\tBody:       io.NopCloser(strings.NewReader(`{\"status\":\"in_transit\",\"tracking\":\"TRACK123\",\"estimated_delivery\":\"2024-12-25\"}`)),\n\t\t\t\t}\n\t\t\t\tmocks.HTTPServices[\"shippingService\"].EXPECT().Get(\n\t\t\t\t\tctx.Context,\n\t\t\t\t\t\"/shipping/\"+testOrderID,\n\t\t\t\t\tnil,\n\t\t\t\t).Return(shippingResp, nil)\n\t\t\t},\n\t\t\trequestPath: \"/orders/\" + testOrderID,\n\t\t\twantErr:     false,\n\t\t\tvalidateResult: func(t *testing.T, result any) {\n\t\t\t\tresultMap := result.(map[string]any)\n\t\t\t\tassert.Equal(t, testOrderID, resultMap[\"order_id\"])\n\t\t\t\tassert.Equal(t, \"completed\", resultMap[\"payment_status\"])\n\t\t\t\tassert.Equal(t, 1500, resultMap[\"payment_amount\"])\n\t\t\t\tassert.Equal(t, \"in_transit\", resultMap[\"shipping_status\"])\n\t\t\t\tassert.Equal(t, \"TRACK123\", resultMap[\"tracking_number\"])\n\t\t\t\tassert.Equal(t, \"2024-12-25\", resultMap[\"estimated_delivery\"])\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"payment service error\",\n\t\t\tsetupMocks: func(mocks *container.Mocks, ctx *gofr.Context) {\n\t\t\t\t// Payment service returns an error - handler should fail before calling shipping service\n\t\t\t\tmocks.HTTPServices[\"paymentService\"].EXPECT().Get(\n\t\t\t\t\tctx.Context,\n\t\t\t\t\t\"/payments/\"+testOrderID,\n\t\t\t\t\tnil,\n\t\t\t\t).Return(nil, errors.New(\"payment service unavailable\"))\n\n\t\t\t\t// Shipping service should NOT be called when payment service fails\n\t\t\t\t// No expectation set for shippingService - test will fail if it's called\n\t\t\t},\n\t\t\trequestPath: \"/orders/\" + testOrderID,\n\t\t\twantErr:     true,\n\t\t\twantErrMsg:  \"failed to fetch payment details\",\n\t\t},\n\t\t{\n\t\t\tname: \"shipping service error\",\n\t\t\tsetupMocks: func(mocks *container.Mocks, ctx *gofr.Context) {\n\t\t\t\t// Payment service succeeds\n\t\t\t\tpaymentResp := &http.Response{\n\t\t\t\t\tStatusCode: http.StatusOK,\n\t\t\t\t\tBody:       io.NopCloser(strings.NewReader(`{\"status\":\"completed\",\"amount\":1500}`)),\n\t\t\t\t}\n\t\t\t\tmocks.HTTPServices[\"paymentService\"].EXPECT().Get(\n\t\t\t\t\tctx.Context,\n\t\t\t\t\t\"/payments/\"+testOrderID,\n\t\t\t\t\tnil,\n\t\t\t\t).Return(paymentResp, nil)\n\n\t\t\t\t// Shipping service returns an error - this is the second HTTP call\n\t\t\t\tmocks.HTTPServices[\"shippingService\"].EXPECT().Get(\n\t\t\t\t\tctx.Context,\n\t\t\t\t\t\"/shipping/\"+testOrderID,\n\t\t\t\t\tnil,\n\t\t\t\t).Return(nil, errors.New(\"shipping service unavailable\"))\n\t\t\t},\n\t\t\trequestPath: \"/orders/\" + testOrderID,\n\t\t\twantErr:     true,\n\t\t\twantErrMsg:  \"failed to fetch shipping details\",\n\t\t},\n\t\t{\n\t\t\tname: \"missing order ID\",\n\t\t\tsetupMocks: func(mocks *container.Mocks, ctx *gofr.Context) {\n\t\t\t\t// No service calls should be made when order ID is missing\n\t\t\t},\n\t\t\trequestPath: \"/orders/\",\n\t\t\twantErr:     true,\n\t\t\twantErrMsg:  \"order ID is required\",\n\t\t},\n\t}\n\n\t// Register HTTP services once - each service gets its own separate mock instance\n\t// Since all test cases use the same services, we can create the mock container outside the loop\n\tmockContainer, mocks := container.NewMockContainer(t,\n\t\tcontainer.WithMockHTTPService(\"paymentService\", \"shippingService\"),\n\t)\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Create test context using helper function\n\t\t\tctx := createTestContext(tt.requestPath, mockContainer)\n\n\t\t\t// Set up mock expectations BEFORE calling the handler\n\t\t\t// Each service's expectations are independent\n\t\t\ttt.setupMocks(mocks, ctx)\n\n\t\t\t// Call the handler\n\t\t\tresult, err := OrderDetailsHandler(ctx)\n\n\t\t\tif tt.wantErr {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), tt.wantErrMsg)\n\t\t\t\tassert.Nil(t, result)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tif tt.validateResult != nil {\n\t\t\t\t\ttt.validateResult(t, result)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n```\n\n**Key Points**:\n- Each service registered via `WithMockHTTPService` gets its own separate mock instance\n- Always use `mocks.HTTPServices[\"serviceName\"]` to access and set expectations for a specific service\n- Always create the `gofr.Context` with the exact request context (`req.Context()`) that will be used in the handler\n- Set expectations on the mock services before calling the handler\n- Test both success and error scenarios to ensure your handlers handle all cases correctly\n\n### Summary\n\n- **Mocking Database Interactions**: Use GoFr mock container to simulate database interactions.\n- **Mocking HTTP Services**: Use `WithMockHTTPService(\"serviceName\")` to register and mock HTTP services.\n- **Context Matching**: Always use `ctx.Context` from your `gofr.Context` in mock expectations, not `t.Context()` or `context.Background()`.\n- **Define Test Cases**: Create table-driven tests to handle various scenarios.\n- **Run and Validate**: Ensure that your tests check for expected results, and handle errors correctly.\n\nThis approach guarantees that your database and HTTP service interactions are tested independently, allowing you to simulate different responses and errors hassle-free.\n","docs/references/gofrcli/wrap-grpc/page.md":"---\ndescription: \"Generate gRPC server and client wrappers with built-in tracing, metrics, and logging using the gofr wrap grpc command.\"\nnextjs:\n  metadata:\n    title: \"gofr wrap grpc — Generate gRPC Server/Client Wrappers\"\n    description: \"Generate gRPC server and client wrappers with built-in tracing, metrics, and logging using the gofr wrap grpc command.\"\n---\n\n# gofr wrap grpc\n\n* The gofr wrap grpc command streamlines gRPC integration in a GoFr project by generating GoFr's context-aware structures.\n* It simplifies setting up gRPC handlers with minimal steps, and accessing datasources, adding tracing as well as custom metrics. Based on the proto file it creates the handler/client with GoFr's context.\n  For detailed instructions on using grpc with GoFr see the [gRPC documentation](/docs/advanced-guide/grpc)\n\n## Command Usage\n**gRPC Server**\n```bash\n  gofr wrap grpc server --proto=<path_to_the_proto_file>\n```\n## Generated Files\n**Server**\n- ```{serviceName}_gofr.go (auto-generated; do not modify)```\n- ```{serviceName}_server.go (example structure below)```\n\n## Example Usage\n**gRPC Server**\n\nThe command generates a server implementation template similar to this:\n```go\npackage server\n\nimport (\n   \"gofr.dev/pkg/gofr\"\n)\n\n// Register the gRPC service in your app using the following code in your main.go:\n//\n// service.Register{ServiceName}ServerWithGofr(app, &server.{ServiceName}Server{})\n//\n// {ServiceName}Server defines the gRPC server implementation.\n// Customize the struct with required dependencies and fields as needed.\ntype {ServiceName}Server struct {\n}\n\n// Example method (actual methods will depend on your proto file)\nfunc (s *MyServiceServer) MethodName(ctx *gofr.Context) (any, error) {\n   // Replace with actual logic if needed\n   return &ServiceResponse{\n   }, nil\n}\n```\nFor detailed instruction on setting up a gRPC server with GoFr see the [gRPC Server Documentation](https://gofr.dev/docs/advanced-guide/grpc#generating-g-rpc-server-handler-template-using)\n\n**gRPC Client**\n```bash\n  gofr wrap grpc client --proto=<path_to_the_proto_file>\n```\n\n**Client**\n- ```{serviceName}_client.go (example structure below)```\n\n\n## Example Usage:\nAssuming the service is named hello, after generating the hello_client.go file, you can seamlessly register and access the gRPC service using the following steps:\n\n```go\ntype GreetHandler struct {\n\thelloGRPCClient client.HelloGoFrClient\n}\n\nfunc NewGreetHandler(helloClient client.HelloGoFrClient) *GreetHandler {\n    return &GreetHandler{\n        helloGRPCClient: helloClient,\n    }\n}\n\nfunc (g GreetHandler) Hello(ctx *gofr.Context) (any, error) {\n    userName := ctx.Param(\"name\")\n    helloResponse, err := g.helloGRPCClient.SayHello(ctx, &client.HelloRequest{Name: userName})\n    if err != nil {\n        return nil, err\n    }\n\n    return helloResponse, nil\n}\n\nfunc main() {\n    app := gofr.New()\n\n// Create a gRPC client for the Hello service\n    helloGRPCClient, err := client.NewHelloGoFrClient(app.Config.Get(\"GRPC_SERVER_HOST\"), app.Metrics())\n    if err != nil {\n\t\tapp.Logger().Errorf(\"Failed to create Hello gRPC client: %v\", err)\n    return\n}\n\n    greetHandler := NewGreetHandler(helloGRPCClient)\n\n    // Register HTTP endpoint for Hello service\n    app.GET(\"/hello\", greetHandler.Hello)\n\n    // Run the application\n    app.Run()\n}\n```\nFor detailed instruction on setting up a gRPC server with GoFr see the [gRPC Client Documentation](https://gofr.dev/docs/advanced-guide/grpc#generating-tracing-enabled-g-rpc-client-using)\nFor more examples refer [gRPC Examples](https://github.com/gofr-dev/gofr/tree/main/examples/grpc)\n\n---\n\n## See also\n\n- [GoFr CLI overview](/docs/references/gofrcli)\n- [`gofr init`](/docs/references/gofrcli/init)\n- [`gofr migrate`](/docs/references/gofrcli/migrate)\n- [`gofr store`](/docs/references/gofrcli/store)\n"},"items":[{"name":"AGENTS.md","path":"docs/AGENTS.md","rawUrl":"https://raw.githubusercontent.com/gofr-dev/gofr/HEAD/docs/AGENTS.md","title":"docs - AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# GoFr — guide for AI coding assistants\n\nFor Claude Code, Cursor, Aider, Codex, etc. Hand\n[https://gofr.dev/AGENTS.md](https://gofr.dev/AGENTS.md) to your assistant\nwhen working on a GoFr project. It points at the specific docs you'll\nactually need rather than inlining everything.\n\nGoFr is an opinionated Go framework for microservices. Apache 2.0.\nRequires Go 1.26+. Repo: <https://github.com/gofr-dev/gofr>.\n\n## Core rules an assistant must know\n\n1. **One handler signature** for HTTP / gRPC / GraphQL / WebSocket / cron / CLI:\n   `func(c *gofr.Context) (any, error)`. Return value → `{\"data\": ...}`. Return error → error response.\n2. **Path params use `{name}`**, not `:name`. `app.GET(\"/users/{id}\", h)`.\n3. **`c.PathParam(\"id\")`** for path; **`c.Param(\"q\")`** for query; **`c.Bind(&v)`** for body.\n4. **Don't manually wire OpenTelemetry, Prometheus, or structured logging.** `gofr.New()` does it.\n5. **Pass `*gofr.Context`** (not `context.Background()`) to every downstream call so trace propagation and cancellation work.\n6. **Configuration comes from `configs/.env`** via `c.Config.Get(key)`. No hardcoded ports / hosts / secrets.\n7. **No ORM bundled.** Use plain SQL via `c.SQL`, or pair with `sqlc`/`gorm` yourself.\n8. **Middleware is standard `net/http`**: `func(http.Handler) http.Handler`, registered with `app.UseMiddleware(...)`.\n9. **Health is auto-exposed** at `/.well-known/health` and `/.well-known/alive`. Don't hand-roll `/healthz`.\n10. **Don't `panic()` for control flow.** Return errors.\n\n## Minimal app\n\n```go\npackage main\n\nimport \"gofr.dev/pkg/gofr\"\n\nfunc main() {\n    app := gofr.New()\n    app.GET(\"/hello\", func(c *gofr.Context) (any, error) {\n        return \"Hello, world\", nil\n    })\n    app.Run()\n}\n```\n\n## Migrations (schema + seed data, versioned)\n\nGoFr has a built-in migration runner — use it instead of `golang-migrate` / `goose`. Works for SQL, Redis, Mongo, Cassandra, ClickHouse, DGraph, SurrealDB.\n\n**Before writing a migration, fetch the full reference:** <https://gofr.dev/docs/advanced-guide/handling-data-migrations>. Runnable shape: <https://github.com/gofr-dev/gofr/tree/main/examples/using-migrations>.\n\nFive rules to keep in your head so you don't have to re-fetch on every change:\n\n1. Files live in `migrations/<unix-ts>_<name>.go`. Versions are `int64`, monotonic. Use `date +%s` for new ones.\n2. `migrations/all.go` exports `All() map[int64]migration.Migrate`. Wire with `a.Migrate(migrations.All())` once in `main.go`.\n3. Each migration is `migration.Migrate{ UP: func(d migration.Datasource) error { ... } }`. Inside `UP`, act on `d.SQL`, `d.Redis`, `d.MongoDB`, `d.Cassandra`, `d.Clickhouse`, `d.DGraph`, `d.SurrealDB`, `d.Logger`.\n4. Each migration runs **exactly once** per environment — don't add idempotent guards. There is **no down migration**; rollback = new forward migration.\n5. One purpose per file. Don't combine \"create table + backfill + drop column\" in one `UP`.\n\n## AI features: LLMs and MCP\n\nGoFr ships LLM and agent support. Use it instead of importing a provider SDK or hand-rolling HTTP, tracing and metrics\naround model calls. **Before writing this code, fetch the full guides:** <https://gofr.dev/docs/advanced-guide/llm> and\n<https://gofr.dev/docs/advanced-guide/mcp>. Runnable shape: <https://github.com/gofr-dev/gofr/tree/main/examples/using-ai>.\n\nRules to keep in your head so you don't have to re-fetch on every change:\n\n1. **Register a model once** with `app.AddLLM(&llm.Client{Provider: llm.Groq, Model: \"...\"})`\n   (`gofr.dev/pkg/gofr/ai/llm`). Providers: `llm.OpenAI`, `llm.Groq`, `llm.DeepSeek`, `llm.Together`, `llm.Ollama`;\n   set `BaseURL` for any other OpenAI-compatible endpoint. Or skip the call and set `LLM_PROVIDER`, `LLM_MODEL` and\n   `LLM_API_KEY` (optional `LLM_BASE_URL`) in `configs/.env`.\n2. **Never hardcode the API key.** It comes from `LLM_API_KEY`, then the provider's own variable (`OPENAI_API_KEY`,\n   `GROQ_API_KEY`, ...).\n3. **Call the model through `c.LLM()`**: `Generate`, `Chat`, `Stream`, `Embed`. It is already traced and metered. Extra\n   models: `app.AddLLM(m, gofr.WithName(\"fast\"))`, used as `c.LLM(\"fast\")`. Not every provider supports every method;\n   handle `ai.ErrEmbedNotSupported` / `ai.ErrStreamNotSupported` as ordinary errors.\n4. **Stream tokens** by returning `response.Stream{Source: stream}` from the handler\n   (`gofr.dev/pkg/gofr/http/response`).\n5. **Expose handlers to agents with `app.EnableMCP()`.** It serves the *read-only* handlers (`GET`, `HEAD`, `OPTIONS`,\n   `QUERY`) as MCP tools. `POST`/`PUT`/`PATCH`/`DELETE` are never exposed. Hide a route with\n   `gofr.WithExcludedRoutes(\"/internal/{id}\")`.\n6. **MCP binds to loopback on `MCP_PORT` (default `8200`).** `MCP_PORT=0` turns the transport off but keeps tools\n   available in-process. A port that cannot be claimed fails startup. `8200` is also Vault's default port.\n7. **Build agent loops in your own handler** with `c.LLM().Tools()` (`List`, `Call`, `Only`). GoFr has no built-in agent\n   loop; turns, stopping conditions and memory stay in your code.\n\n```go\npackage main\n\nimport (\n    \"gofr.dev/pkg/gofr\"\n    \"gofr.dev/pkg/gofr/ai/llm\"\n)\n\nfunc main() {\n    app := gofr.New()\n\n    app.AddLLM(&llm.Client{Provider: llm.Groq, Model: \"llama-3.3-70b-versatile\"})\n    app.EnableMCP() // exposes the GET handlers below to MCP clients\n\n    app.GET(\"/products/{id}\", func(c *gofr.Context) (any, error) {\n        return map[string]any{\"id\": c.PathParam(\"id\")}, nil\n    })\n\n    app.POST(\"/summarize\", func(c *gofr.Context) (any, error) {\n        var in struct {\n            Text string `json:\"text\"`\n        }\n        if err := c.Bind(&in); err != nil {\n            return nil, err\n        }\n\n        return c.LLM().Generate(c, \"Summarize the following:\\n\"+in.Text)\n    })\n\n    app.Run()\n}\n```\n\n## Where to look (fetch only what you need)\n\nEach link is a self-contained doc page. Fetch lazily.\n\n- Quick start: <https://gofr.dev/docs/quick-start/introduction>\n- Configuration: <https://gofr.dev/docs/quick-start/configuration>\n- Routing + REST handlers: <https://gofr.dev/docs/quick-start/add-rest-handlers>\n- Context reference (the central abstraction): <https://gofr.dev/docs/references/context>\n- Configs reference (every env var): <https://gofr.dev/docs/references/configs>\n- Testing patterns + mocks: <https://gofr.dev/docs/references/testing>\n- Observability (auto-wired): <https://gofr.dev/docs/quick-start/observability>\n- Custom OTel spans: <https://gofr.dev/docs/advanced-guide/custom-spans-in-tracing>\n- Custom Prometheus metrics: <https://gofr.dev/docs/advanced-guide/publishing-custom-metrics>\n- Datasources index (MySQL, Postgres, Mongo, Redis, Cassandra, ClickHouse, etc.): <https://gofr.dev/docs/datasources/getting-started>\n- Pub/Sub (Kafka, NATS, GCP, MQTT, SQS, Azure): <https://gofr.dev/docs/advanced-guide/using-publisher-subscriber>\n- gRPC: <https://gofr.dev/docs/advanced-guide/grpc>\n- GraphQL: <https://gofr.dev/docs/advanced-guide/graphql>\n- WebSockets: <https://gofr.dev/docs/advanced-guide/websocket>\n- Cron: <https://gofr.dev/docs/advanced-guide/using-cron>\n- Service-to-service HTTP w/ circuit breaker: <https://gofr.dev/docs/advanced-guide/http-communication>\n- Auth (Basic / API key / OAuth-JWT): <https://gofr.dev/docs/advanced-guide/authentication>\n- RBAC (config-driven): <https://gofr.dev/docs/advanced-guide/rbac>\n- Migrations (SQL + NoSQL, versioned): <https://gofr.dev/docs/advanced-guide/handling-data-migrations>\n- File storage (local / S3 / GCS / Azure / FTP / SFTP): <https://gofr.dev/docs/advanced-guide/handling-file>\n- Startup hooks: <https://gofr.dev/docs/advanced-guide/startup-hooks>\n- Errors: <https://gofr.dev/docs/advanced-guide/gofr-errors>\n- Custom DB drivers: <https://gofr.dev/docs/advanced-guide/injecting-databases-drivers>\n- Calling LLMs (`app.AddLLM`, `c.LLM()`, env config, multiple models, embeddings): <https://gofr.dev/docs/advanced-guide/llm>\n- MCP server and agent loops (`app.EnableMCP`, `c.LLM().Tools()`): <https://gofr.dev/docs/advanced-guide/mcp>\n- Streaming responses (SSE / NDJSON, `response.Stream`): <https://gofr.dev/docs/advanced-guide/streaming>\n\n## Migrating to GoFr\n\nEach migration page has the full mapping table for that source framework — fetch only the one that matches:\n\n- From Gin: <https://gofr.dev/migrate/from-gin>\n- From Fiber: <https://gofr.dev/migrate/from-fiber>\n- From Echo: handler shape similar to Gin; see <https://gofr.dev/comparison/gofr-vs-echo>\n- From Chi: see <https://gofr.dev/comparison/gofr-vs-chi>\n- From Express (Node.js): <https://gofr.dev/migrate/from-express>\n- From Flask (Python): <https://gofr.dev/migrate/from-flask>\n- From Spring Boot (Java): <https://gofr.dev/migrate/from-spring-boot>\n\n## Other entry points\n\n- Examples (runnable projects): <https://github.com/gofr-dev/gofr/tree/main/examples>\n- Full docs index: <https://gofr.dev/docs>\n- Concatenated full docs (one plaintext file): <https://gofr.dev/llms-full.txt>\n- Curated link index: <https://gofr.dev/llms.txt>\n- Changelog: <https://gofr.dev/changelog>\n","isInternal":false,"tokens":2605,"sizeBytes":9020},{"name":"page.md","path":"docs/references/configs/page.md","rawUrl":"https://raw.githubusercontent.com/gofr-dev/gofr/HEAD/docs/references/configs/page.md","title":"Configs Skill","category":"anthropic-skill","format":"markdown","content":"---\ndescription: \"Reference of every GoFr configuration variable, grouped by category: HTTP, gRPC, datasources, observability, auth, and more — with defaults and value formats.\"\nnextjs:\n  metadata:\n    title: \"GoFr Configuration Reference — Env Vars and Defaults\"\n    description: \"Reference of every GoFr configuration variable, grouped by category: HTTP, gRPC, datasources, observability, auth, and more — with defaults and value formats.\"\n---\n\n# GoFr Configuration Options\n\nThis document lists all the configuration options supported by the GoFr framework. The configurations are grouped by category for better organization.\n\n## App\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  APP_NAME\n-  Name of the application. It is also the `service.name` on the resource attached to exported traces and metrics; OTEL_SERVICE_NAME and a service.name= entry in OTEL_RESOURCE_ATTRIBUTES are ignored.\n-  gofr-app\n\n---\n\n-  APP_ENV\n-  Name of the environment file to use (e.g., stage.env, prod.env, or local.env).\n\n---\n\n-  APP_VERSION\n-  Application version\n-  dev\n\n---\n\n-  LOG_LEVEL\n-  Level of verbosity for application logs. Supported values are **DEBUG, INFO, NOTICE, WARN, ERROR, FATAL**\n-  INFO\n\n---\n\n-  REMOTE_LOG_URL\n-  URL to remotely change the log level\n\n---\n\n-  REMOTE_LOG_FETCH_INTERVAL\n-  Time interval (in seconds) to check for remote log level updates\n-  15\n\n---\n\n-  METRICS_PORT\n-  Port on which the application exposes the Prometheus pull endpoint. Set to 0 to disable it (e.g. push-only serverless).\n-  2121\n\n---\n\n-  METRICS_EXPORTER\n-  Enables push-based metrics export alongside the pull endpoint. Supported values: otlp, gcp. Unset (or prometheus) keeps pull-only behavior.\n\n---\n\n-  METRICS_URL\n-  Endpoint of the OTLP metrics collector/backend. host:port for gRPC, full URL for HTTP. Required when METRICS_EXPORTER is otlp (gcp defaults to telemetry.googleapis.com:443).\n\n---\n\n-  METRICS_PROTOCOL\n-  OTLP transport for pushed metrics. Supported values: grpc, http.\n-  grpc\n\n---\n\n-  METRICS_EXPORT_INTERVAL\n-  Interval (in seconds) at which metrics are pushed to the collector/backend.\n-  30\n\n---\n\n-  METRICS_TEMPORALITY\n-  OTLP temporality preference. Supported values: cumulative, delta, lowmemory. Use delta for Datadog; cumulative for Prometheus/GMP/Grafana.\n-  cumulative\n\n---\n\n-  METRICS_HEADERS\n-  Custom headers for metric export requests in comma-separated key=value format (e.g., \"dd-api-key=secret\"). Takes priority over METRICS_AUTH_KEY.\n\n---\n\n-  METRICS_AUTH_KEY\n-  Authorization header value for metric export requests. Used when METRICS_HEADERS is unset.\n\n---\n\n-  METRICS_INSECURE\n-  Disables transport security for the OTLP metrics connection. Set to false for managed backends over TLS. Ignored by the gcp exporter (always TLS).\n-  true\n\n---\n\n-  METRICS_CARDINALITY_LIMIT\n-  Per-instrument attribute-set limit, inclusive of the overflow slot: an instrument keeps up to one fewer than this many distinct label sets per collection cycle, and the remaining series collapse into a single otel.metric.overflow series (so a value of n keeps n-1 real label sets). Set 0 or negative for unlimited. When unset, the OpenTelemetry SDK default applies (2000, or OTEL_GO_X_CARDINALITY_LIMIT if set); a set value takes precedence over OTEL_GO_X_CARDINALITY_LIMIT. HTTP metrics give requests that match no route (and unknown methods) at most a quarter of this limit, capped at 500 distinct (path, method, status) label sets; past that they are recorded as `__unmatched__` / `__other__`, so scanner traffic cannot push real routes into the overflow series.\n-  2000\n\n---\n\n-  OTEL_RESOURCE_ATTRIBUTES\n-  Standard OpenTelemetry resource attributes, comma-separated key=value. Merged into the resource attached to every exported metric and span, except service.name, which comes from APP_NAME (a service.name= entry is ignored with a warning), and framework_version, which cannot be overridden. Required for the gcp exporter outside Google Cloud: its ingest rejects any point whose prometheus_target has no location (e.g. \"location=us-central1\").\n\n---\n\n-  OTEL_SERVICE_NAME\n-  Standard OpenTelemetry service name. Ignored: GoFr sets service.name on exported traces and metrics from APP_NAME, and logs a warning at startup when this is set to a different value. Tracing and metrics each log it, so with both enabled the warning appears twice, once prefixed \"traces:\" and once \"metrics:\". Set APP_NAME to rename the service.\n\n---\n\n-  HTTP_PORT\n-  Port on which the HTTP server listens\n-  8000\n\n---\n\n-  GRPC_PORT\n-  Port on which the gRPC server listens\n-  9000\n\n---\n\n-  MCP_PORT\n-  Port on which the MCP server listens, bound to loopback. Only used when `app.EnableMCP()` is called; a port that cannot be claimed fails startup. Set to `0` to keep tools available in-process while serving no MCP transport. A non-numeric or out-of-range value refuses startup. Note the default collides with Vault's — see [MCP](/docs/advanced-guide/mcp).\n-  8200\n\n---\n\n-  TRACE_EXPORTER\n-  Tracing exporter to use. Supported values: gofr, zipkin, jaeger, otlp, gcp. `gcp` exports directly to Google Cloud's Telemetry (OTLP) API using Application Default Credentials, and requires the blank import `_ \"gofr.dev/pkg/gofr/traces/exporters/gcp\"`.\n\n---\n\n-  TRACER_HOST\n-  Hostname of the tracing collector. Required if TRACE_EXPORTER is set to zipkin or jaeger.\n-  **DEPRECATED**\n\n---\n\n-  TRACER_PORT\n-  Port of the tracing collector. Required if TRACE_EXPORTER is set to zipkin or jaeger.\n-  9411\n-  **DEPRECATED**\n\n---\n\n-  TRACER_URL\n-  URL of the trace collector. Required if TRACE_EXPORTER is set to zipkin, jaeger or otlp; optional for gcp, which defaults to `telemetry.googleapis.com:443`. For zipkin, jaeger and otlp an `http://` or `https://` scheme selects the transport, and a schemeless `host:port` is governed by TRACER_INSECURE. For gcp the value must be a schemeless `host:port` — that destination is always TLS on 443, so a scheme is rejected at startup rather than interpreted.\n\n---\n\n-  TRACER_INSECURE\n-  Whether a schemeless TRACER_URL (`host:port`) is exported over plaintext. Set to `false` to use TLS with the system root CAs. Ignored when TRACER_URL carries an `http://` or `https://` scheme, which selects the transport itself. Takes precedence over the OTel standard OTEL_EXPORTER_OTLP_INSECURE / OTEL_EXPORTER_OTLP_TRACES_INSECURE. Supported for otlp, jaeger.\n-  true\n\n---\n\n-  TRACER_RATIO\n-  Refers to the proportion of traces that are exported through sampling. It is optional configuration. By default, this ratio is set to 1. A value that is not a valid number is rejected with an error log and also resolves to 1, so a typo over-samples rather than silently disabling tracing.\n\n---\n\n-  TRACER_AUTH_KEY\n-  Authorization header for trace exporter requests. Supported for zipkin, jaeger, otlp.\n\n---\n\n-  TRACER_HEADERS\n-  Custom authentication headers for trace exporter requests in comma-separated key=value format (e.g., \"X-Api-Key=secret,Authorization=Bearer token\"). Supported for zipkin, jaeger, otlp. Takes priority over TRACER_AUTH_KEY.\n\n---\n\n-  CMD_LOGS_FILE\n-  File to save the logs in case of a CMD application\n\n---\n\n-  SHUTDOWN_GRACE_PERIOD\n-  Timeout duration for server shutdown process\n-  30s\n\n---\n\n-  GOFR_TELEMETRY\n-  Enable telemetry for GoFr framework usage\n-  true\n\n---\n\n-  GOFR_ROUTER\n-  Route matcher for the HTTP server. Set to `trie` to opt into the O(path length) trie index instead of the default linear scan — see [Routing Performance](/docs/advanced-guide/routing-performance). Any other value falls back to `mux`.\n-  mux\n\n---\n\n-  GOFR_RBAC_ROUTE_CHECK\n-  What the startup check does when the RBAC config and the registered routes disagree — see [Startup Route Check](/docs/advanced-guide/rbac#startup-route-check). `warn` logs each mismatch as an error and keeps starting, `fail` logs them and stops startup with exit status 1, `off` skips the check. Any other value is logged as an error and treated as `warn`.\n-  warn\n\n---\n\n-  LOG_DISABLE_PROBES\n-  Disable log probes for health checks\n-  false\n\n---\n\n-  GRPC_ENABLE_REFLECTION\n-  Enable gRPC server reflection\n-  false\n\n---\n\n-  HEALTH_CACHE_TTL\n-  How long a health result may be served without re-checking the backends, as a duration (`5s`, `10s`, `1m`). Unset, `0` or `disabled` turns caching off, which is the default: within a TTL a recovered backend still reports DOWN and a failed one still reports UP, so it is a trade to opt into rather than inherit.\n-  disabled\n\n---\n\n-  HEALTH_CHECK_TIMEOUT\n-  Upper bound on one round of health checks, as a duration (`2s`). Backends that have not answered by then are left out of the response and the aggregate status is DEGRADED. Datasources whose health check honors its context are canceled at that deadline. Once every outstanding check has returned, the next probe checks them again. Checks that cannot be canceled keep running after the round is abandoned: the SQL, Redis and PubSub health checks take no context, and a few datasources (such as Couchbase and NATS KV) don't yet honor the one they receive. While one of those is still running, a probe reports DEGRADED with no per-dependency detail rather than starting a second round against the same unresponsive backend. Unset or `0` means the round is bounded only by each backend client's own timeout.\n-  disabled\n\n{% /table %}\n\n## HTTP\n\n{% table %}\n\n- Name\n- Description\n\n---\n\n-  REQUEST_TIMEOUT\n-  Set the request timeouts (in seconds) for HTTP server.\n\n---\n\n- CERT_FILE\n- Set the path to your PEM certificate file for the HTTPS server to establish a secure connection.\n\n--- \n\n- KEY_FILE\n- Set the path to your PEM key file for the HTTPS server to establish a secure connection.\n\n{% /table %}\n\n### CORS\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n- ACCESS_CONTROL_ALLOW_ORIGIN\n- Allowed origin(s) for cross-origin requests. Supports comma-separated values for multiple origins (e.g., `https://app.example.com,https://admin.example.com`).\n- `*`\n\n---\n\n- ACCESS_CONTROL_ALLOW_HEADERS\n- Allowed request headers for cross-origin requests.\n- Authorization, Content-Type, x-requested-with, origin, true-client-ip, X-Correlation-ID\n\n---\n\n- ACCESS_CONTROL_ALLOW_METHODS\n- Allowed HTTP methods. Automatically set from registered routes if not provided.\n\n---\n\n- ACCESS_CONTROL_ALLOW_CREDENTIALS\n- Allow credentials (cookies, HTTP authentication) in cross-origin requests.\n\n---\n\n- ACCESS_CONTROL_EXPOSE_HEADERS\n- Additional headers exposed to the client in cross-origin responses.\n\n---\n\n- ACCESS_CONTROL_MAX_AGE\n- Maximum time (in seconds) browsers can cache preflight responses.\n\n{% /table %}\n\n## Datasource\n\n### SQL\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  DB_DIALECT\n-  Database dialect. Supported values: mysql, postgres, supabase\n\n---\n\n-  DB_HOST\n-  Hostname of the database server.\n\n---\n\n-  DB_PORT\n-  Port of the database server.\n-  3306\n\n---\n\n-  DB_USER\n-  Username for the database.\n\n---\n\n-  DB_PASSWORD\n-  Password for the database.\n\n---\n\n-  DB_NAME\n-  Name of the database to use.\n\n---\n\n-  DB_MAX_IDLE_CONNECTION\n-  Number of maximum idle connection.\n-  2\n\n---\n\n-  DB_MAX_OPEN_CONNECTION\n-  Number of maximum connections which can be used with database.\n-  0 (unlimited)\n---\n\n-  DB_SSL_MODE\n-  TLS/SSL mode for database connections. Supported modes: **disable** (no TLS), **preferred** (attempts TLS, falls back to plain), **require** (enforces TLS, skips validation), **skip-verify** (enforces TLS, no certificate validation), **verify-ca** (enforces TLS, validates certificate against CA), **verify-full** (enforces TLS with full validation including hostname). Currently supported for MySQL/MariaDB and PostgreSQL.\n-  disable\n\n---\n\n- DB_TLS_CA_CERT\n- Path to CA certificate file for TLS connections. Required for **verify-ca** and **verify-full** SSL modes.\n- None\n\n---\n\n- DB_TLS_CLIENT_CERT\n- Path to client certificate file for mutual TLS authentication.\n- None\n\n---\n\n- DB_TLS_CLIENT_KEY\n- Path to client private key file for mutual TLS authentication.\n- None\n\n---\n\n- DB_REPLICA_HOSTS\n- Comma-separated list of replica database hosts. Used for read replicas.\n- None\n\n---\n\n- DB_REPLICA_PORTS\n- Comma-separated list of replica database ports. Used for read replicas.\n- None\n\n---\n\n- DB_REPLICA_USERS\n- Comma-separated list of replica database users. Used for read replicas.\n- None\n\n---\n\n- DB_REPLICA_PASSWORDS\n- Comma-separated list of replica database passwords. Used for read replicas.\n- None\n\n---\n\n- DB_REPLICA_MAX_IDLE_CONNECTIONS\n- Maximum idle connections allowed for a replica\n- 50\n\n---\n\n- DB_REPLICA_MIN_IDLE_CONNECTIONS\n- Minimum idle connections for a replica\n- 10\n\n---\n\n- DB_REPLICA_DEFAULT_IDLE_CONNECTIONS\n- Idle connections used if no primary setting is provided\n- 10\n\n---\n\n- DB_REPLICA_MAX_OPEN_CONNECTIONS\n- Maximum open connections allowed for a replica\n- 200\n\n---\n\n- DB_REPLICA_MIN_OPEN_CONNECTIONS\n- Minimum open connections for a replica\n- 50\n\n---\n\n- DB_REPLICA_DEFAULT_OPEN_CONNECTIONS\n- Open connections used if no primary setting is provided\n- 100\n\n---\n\n\n- DB_CHARSET\n- The character set for database connection\n- utf8\n\n---\n\n- SUPABASE_CONNECTION_TYPE \n- Connection type to Supabase. Supported values: direct, session, transaction \n- direct\n\n---\n\n- SUPABASE_PROJECT_REF \n- Supabase project reference ID\n\n---\n\n- SUPABASE_REGION \n- Supabase region for pooled connections\n\n---\n\n- DB_URL \n- Full PostgreSQL connection string for Supabase (alternative to separate config parameters)\n\n{% /table %}\n\n### Redis\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  REDIS_HOST\n-  Hostname of the Redis server.\n-  localhost\n\n---\n\n-  REDIS_PORT\n-  Port of the Redis server.\n-  6379\n\n---\n\n- REDIS_USER\n- Username for the Redis server (optional).\n-  \"\"\n\n---\n\n- REDIS_PASSWORD\n- Password for the Redis server (optional).\n-  \"\"\n\n---\n\n- REDIS_DB\n- Database number to use for the Redis server.\n-  0\n\n---\n\n- REDIS_TLS_ENABLED\n- Enable TLS for Redis connections.\n-  false\n\n---\n\n- REDIS_TLS_CA_CERT\n- Path to the TLS CA certificate file for Redis (or PEM-encoded string).\n-  \"\"\n\n---\n\n- REDIS_TLS_CERT\n- Path to the TLS certificate file for Redis (or PEM-encoded string).\n-  \"\"\n\n---\n\n- REDIS_TLS_KEY\n- Path to the TLS key file for Redis (or PEM-encoded string).\n-  \"\"\n\n{% /table %}\n\n**Redis PubSub Configuration:**\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n- REDIS_PUBSUB_DB\n- Redis database number to use only for Redis Pub/Sub (when `PUBSUB_BACKEND=REDIS`). Use a different DB than `REDIS_DB` when running GoFr migrations with Redis Streams mode to avoid `gofr_migrations` key-type collisions.\n- Default: `15` (highest default Redis database, 0-15)\n\n---\n\n- REDIS_PUBSUB_MODE\n- Operation mode: `pubsub` or `streams`.\n- streams\n\n---\n\n- REDIS_STREAMS_CONSUMER_GROUP\n- Consumer group name (required for streams mode).\n-  \"\"\n\n---\n\n- REDIS_STREAMS_CONSUMER_NAME\n- Unique consumer name (optional, auto-generated if empty).\n-  \"\"\n\n---\n\n- REDIS_STREAMS_BLOCK_TIMEOUT\n- Blocking duration for reading new messages using Redis `XREADGROUP`. Lower values (1s-2s) provide faster detection but increase CPU usage. Higher values (10s-30s) reduce CPU usage, ideal for batch processing.\n- 5s\n\n---\n\n- REDIS_STREAMS_PEL_RATIO\n- Ratio of PEL (pending) messages to read vs new messages (0.0-1.0). Controls balance between retry and fresh messages. 0.7 = 70% PEL, 30% new.\n- 0.7\n\n---\n\n- REDIS_STREAMS_MAXLEN\n- Maximum length of the stream (approximate). Prevents streams from growing indefinitely. Set to `0` for unlimited.\n- 0 (unlimited)\n\n{% /table %}\n\n> **Note**: When using GoFr migrations with Streams mode, keep `REDIS_DB` and `REDIS_PUBSUB_DB` separate (defaults: 0 and 15). For `REDIS_STREAMS_BLOCK_TIMEOUT`: use 1s-2s for real-time or 10s-30s for batch processing.\n\n### Pub/Sub\n\n{% table %}\n\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  PUBSUB_BACKEND\n-  Pub/Sub message broker backend wired automatically by `gofr.New()`. Accepted values: `kafka`, `google`, `mqtt`, `redis` (case-insensitive). Other backends (NATS JetStream, AWS SQS, Azure Event Hub) are wired explicitly via `app.AddPubSub(...)`.\n-  \n\n{% /table %}\n\n**Kafka**\n\n{% table %}\n\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  PUBSUB_BROKER\n-  Comma-separated list of broker addresses\n-  localhost:9092\n\n---\n\n-  PARTITION_SIZE\n-  Size of each message partition (in bytes)\n-  0\n\n---\n\n-  PUBSUB_OFFSET\n-  Offset to start consuming messages from. -1 for earliest, 0 for latest.\n-  -1\n\n---\n\n- KAFKA_BATCH_SIZE\n- Number of messages to batch before sending to Kafka\n- 1\n\n---\n\n- KAFKA_BATCH_BYTES\n- Number of bytes to batch before sending to Kafka\n- 1048576\n\n---\n\n- KAFKA_BATCH_TIMEOUT\n- Time to wait before sending a batch to Kafka\n- 100ms\n\n---\n\n-  CONSUMER_ID\n-  Unique identifier for this consumer\n-  gofr-consumer\n\n---\n\n---\n\n- KAFKA_SECURITY_PROTOCOL\n- Security protocol used to communicate with Kafka (e.g., PLAINTEXT, SSL, SASL_PLAINTEXT, SASL_SSL)\n- PLAINTEXT\n\n---\n\n\n- KAFKA_SASL_MECHANISM\n- SASL mechanism for authentication (e.g. PLAIN, SCRAM-SHA-256, SCRAM-SHA-512)\n- None\n\n---\n\n- KAFKA_SASL_USERNAME\n- Username for SASL authentication\n- None\n\n---\n\n- KAFKA_SASL_PASSWORD\n- Password for SASL authentication\n- None\n\n---\n\n- KAFKA_TLS_CERT_FILE\n- Path to the TLS certificate file\n- None\n\n---\n\n- KAFKA_TLS_KEY_FILE\n- Path to the TLS key file\n- None\n\n---\n\n- KAFKA_TLS_CA_CERT_FILE\n- Path to the TLS CA certificate file\n- None\n\n---\n\n- KAFKA_TLS_INSECURE_SKIP_VERIFY\n- Skip TLS certificate verification\n- false\n\n{% /table %}\n\n**Google**\n\n{% table %}\n\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  GOOGLE_PROJECT_ID\n-  ID of the Google Cloud project. Required for Google Pub/Sub.\n-  None\n\n---\n\n-  GOOGLE_SUBSCRIPTION_NAME\n-  Name of the Google Pub/Sub subscription. Required for Google Pub/Sub.\n-  None\n\n---\n\n-  GOOGLE_MAX_OUTSTANDING_MESSAGES\n-  Max messages the client holds waiting for delivery to the handler, per subscribed topic (the memory/goroutine bound, not the handler concurrency). 0 uses the default; a negative value means no limit.\n-  1000\n\n---\n\n-  GOOGLE_MAX_OUTSTANDING_BYTES\n-  Max total size (bytes) of messages held waiting for delivery, per subscribed topic. 0 uses the default; a negative value means no limit.\n-  1000000000\n\n---\n\n-  GOOGLE_NUM_GOROUTINES\n-  Number of StreamingPull streams opened by the subscriber, per subscribed topic. It is the stream count, not handler concurrency, and does not raise throughput under GoFr's one-message-at-a-time delivery. 0 or a negative value uses the default.\n-  10\n\n{% /table %}\n\n**MQTT**\n\n{% table %}\n\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  MQTT_PORT\n-  Port of the MQTT broker\n-  1883\n\n---\n\n-  MQTT_MESSAGE_ORDER\n-  Enable guaranteed message order\n-  false\n\n---\n\n-  MQTT_PROTOCOL\n-  Communication protocol. Supported values: tcp, ssl.\n-  tcp\n\n---\n\n-  MQTT_HOST\n-  Hostname of the MQTT broker\n-  localhost\n\n---\n\n-  MQTT_USER\n-  Username for the MQTT broker\n\n---\n\n-  MQTT_PASSWORD\n-  Password for the MQTT broker\n\n---\n\n-  MQTT_CLIENT_ID_SUFFIX\n-  Suffix appended to the client ID\n\n---\n\n-  MQTT_QOS\n-  Quality of Service Level\n\n---\n\n-  MQTT_KEEP_ALIVE\n-  Sends regular messages to check the link is active. May not work as expected if handling func is blocking execution\n\n- MQTT_RETRIEVE_RETAINED\n- Retrieve retained messages on subscription\n\n{% /table %}\n\n**NATS JetStream**\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  NATS_SERVER\n-  URL of the NATS server. The NATS driver is wired explicitly via `app.AddPubSub(...)`; this row is a convention only — the actual env-var name is whatever you read from `app.Config.Get(...)` and pass into `nats.Config.Server`.\n-  nats://localhost:4222\n\n---\n\n-  NATS_CREDS_FILE\n-  File containing the NATS credentials\n- creds.json\n\n{% /table %}\n\n\n\n## Related production guides\n\n- **12-Factor Configuration**: [Env-driven config, secrets, and environment parity](/docs/guides/twelve-factor-config) — apply 12-factor methodology to the configs documented above.\n","frontmatter":{"description":"Reference of every GoFr configuration variable, grouped by category: HTTP, gRPC, datasources, observability, auth, and more — with defaults and value formats.","nextjs":{"metadata":{"title":"GoFr Configuration Reference — Env Vars and Defaults","description":"Reference of every GoFr configuration variable, grouped by category: HTTP, gRPC, datasources, observability, auth, and more — with defaults and value formats."}}},"isInternal":false,"tokens":5070,"sizeBytes":19913},{"name":"page.md","path":"docs/references/context/page.md","rawUrl":"https://raw.githubusercontent.com/gofr-dev/gofr/HEAD/docs/references/context/page.md","title":"Context Skill","category":"anthropic-skill","format":"markdown","content":"---\ndescription: \"GoFr's ctx is injected into every handler. It carries request data plus the container of dependencies — DBs, logger, HTTP clients, and metrics — for the cycle.\"\nnextjs:\n  metadata:\n    title: \"GoFr Context Reference — Request Container API\"\n    description: \"GoFr's ctx is injected into every handler. It carries request data plus the container of dependencies — DBs, logger, HTTP clients, and metrics — for the cycle.\"\n---\n\n# GoFr Context\n\nGoFr context is an object injected by the GoFr handler. It contains all the request-specific data, for each\nrequest-response cycle a new context is created. The request can be either an HTTP request, gRPC call or\na message from Pub-Sub.\nGoFr Context also embeds the **_container_** which maintains all the dependencies like databases, logger, HTTP service clients,\nmetrics manager, etc. This reduces the complexity of the application as users don't have to maintain and keep track of\nall the dependencies by themselves.\n\nGoFr context is an extension of the Go context, providing a wrapper around the request and response providing\nuser access to dependencies.\n\n# Usage\n\n## Reading HTTP requests\n\n`ctx.Request` can be used to access the underlying request which provides the following methods to access different\nparts of the request.\n\n- `Context()` - to access the context associated with the incoming request\n\n```go\nctx.Request.Context()\n```\n\n- `Param(string)` - to access the query parameters present in the request, it returns the value of the key provided\n\n```go\n// Example: Request is /configs?key1=value1&key2=value2\nvalue := ctx.Request.Param(\"key1\")\n// value = \"value1\"\n```\n\n- `PathParam(string)` - to retrieve the path parameters\n  ```go\n  // Consider the path to be /employee/{id}\n  id := ctx.Request.PathParam(\"id\")\n  ```\n- `Bind(any)` - to access a decoded format of the request body, the body is mapped to the interface provided\n\n```go\n// incoming request body is\n// {\n//    \"name\" : \"trident\",\n//    \"category\" : \"snacks\"\n// }\n\ntype product struct{\n  Name string `json:\"name\"`\n  Category string `json:\"category\"`\n}\n\nvar p product\nctx.Bind(&p)\n// the Bind() method will map the incoming request to variable p\n```\n\n> **Pass a pointer.** `Bind` needs the address of your variable (`&p`) so it can write into it.\n> For an HTTP request, passing a value (`ctx.Bind(p)`) returns an error rather than silently\n> leaving your variable untouched. Always check the returned error:\n>\n> ```go\n> if err := ctx.Bind(&p); err != nil {\n>     return nil, err\n> }\n> ```\n\nThe `Content-Type` header selects how the body is decoded. It is matched case-insensitively and\nany parameters are ignored, so `application/json`, `Application/JSON` and\n`application/json; charset=utf-8` are all treated the same.\n\nIf a request carries a body whose `Content-Type` GoFr has no decoder for — `text/plain`,\n`application/xml`, or no header at all — `Bind` is a **no-op**: it returns no error and leaves\nyour target zeroed, and the body is discarded. Check the `Content-Type` your clients actually\nsend. `fetch(url, {method: \"POST\", body: str})` with no headers sends `text/plain`, not JSON, so\na request that looks correct can bind nothing.\n\n- `Binding multipart-form data / urlencoded form data `\n  - To bind multipart-form data or url-encoded form, we can use the Bind method similarly. The struct fields should be tagged appropriately\n    to map the form fields to the struct fields. The supported content types are `multipart/form-data` and `application/x-www-form-urlencoded`\n\n```go\ntype Data struct {\n\tName string `form:\"name\"`\n\n\tCompressed file.Zip `file:\"upload\"`\n\n\tFileHeader *multipart.FileHeader `file:\"file_upload\"`\n}\n```\n\n  - The `form` tag is used to bind non-file fields.\n  - The `file` tag is used to bind file fields. If the tag is not present, the field name is used as the key.\n\n\n- `HostName()` - to access the host name for the incoming request\n\n```go\n// for example if request is made from xyz.com\n  host := ctx.Request.HostName()\n  // the host would be http://xyz.com\n  // Note: the protocol if not provided in the headers will be set to http by default\n```\n\n- `Params(string)` - to access all query parameters for a given key returning slice of strings.\n\n```go\n// Example: Request is /search?category=books,electronics&category=tech\nvalues := ctx.Request.Params(\"category\")\n// values = []string{\"books\", \"electronics\", \"tech\"}\n```\n\n\n## Accessing Authentication Information\n\nGoFr provides a helper method to access authentication details from the context.\nThese values are populated when the respective authentication middleware is enabled (see [HTTP Auth Middleware](https://github.com/gofr-dev/gofr/blob/0845d19181d2cc55e12c557fc9ad51adb4ab44fd/examples/using-http-auth-middleware/ReadMe.md) section).\n\n```go\ninfo := ctx.GetAuthInfo()\n```\n\n### Methods\n\n* **`GetClaims()`** – Returns the JWT claims containing standard fields such as:\n\n  * `Issuer` – identifies who issued the token.\n  * `Subject` – identifies the principal that is the subject of the token.\n  * `Audience` – identifies the intended recipients of the token.\n  * `NotBefore` – time before which the token is not valid.\n  * `IssuedAt` – time at which the token was issued.\n  * `ExpirationTime` – time after which the token expires.\n\n  **Requires:** OAuth middleware (`EnableOAuth`)\n\n* **`GetUsername()`** – Returns the authenticated username when using Basic Authentication.\n\n  **Requires:** Basic Auth middleware (`EnableBasicAuthWithValidator`)\n\n* **`GetAPIKey()`** – Returns the API key used for authentication.\n\n  **Requires:** API Key middleware (`EnableAPIKeyAuthWithValidator`)\n\n> Note: These values will be available only if the respective authentication middleware is enabled in the application.\n\n\n## Accessing dependencies\n\nGoFr context embeds the container object which provides access to\nall the injected dependencies by the users. Users can access the fields and methods provided\nby the **_container_**.\n","frontmatter":{"description":"GoFr's ctx is injected into every handler. It carries request data plus the container of dependencies — DBs, logger, HTTP clients, and metrics — for the cycle.","nextjs":{"metadata":{"title":"GoFr Context Reference — Request Container API","description":"GoFr's ctx is injected into every handler. It carries request data plus the container of dependencies — DBs, logger, HTTP clients, and metrics — for the cycle."}}},"isInternal":false,"tokens":1395,"sizeBytes":5974},{"name":"page.md","path":"docs/references/gofrcli/init/page.md","rawUrl":"https://raw.githubusercontent.com/gofr-dev/gofr/HEAD/docs/references/gofrcli/init/page.md","title":"Init Skill","category":"anthropic-skill","format":"markdown","content":"---\ndescription: \"Initialize a new GoFr project with the standard layout and a Hello World starter program using the gofr init command.\"\nnextjs:\n  metadata:\n    title: \"gofr init — Initialize a New GoFr Project\"\n    description: \"Initialize a new GoFr project with the standard layout and a Hello World starter program using the gofr init command.\"\n---\n\n# gofr init\n\nThe init command initializes a new GoFr project. It sets up the foundational structure for the project and generates a basic \"Hello World!\" program as a starting point. This allows developers to quickly dive into building their application with a ready-made structure.\n\n## Command Usage\n```bash\n  gofr init\n```\n\n---\n\n## See also\n\n- [GoFr CLI overview](/docs/references/gofrcli)\n- [`gofr migrate`](/docs/references/gofrcli/migrate)\n- [`gofr wrap grpc`](/docs/references/gofrcli/wrap-grpc)\n- [`gofr store`](/docs/references/gofrcli/store)\n","frontmatter":{"description":"Initialize a new GoFr project with the standard layout and a Hello World starter program using the gofr init command.","nextjs":{"metadata":{"title":"gofr init — Initialize a New GoFr Project","description":"Initialize a new GoFr project with the standard layout and a Hello World starter program using the gofr init command."}}},"isInternal":false,"tokens":222,"sizeBytes":906},{"name":"page.md","path":"docs/references/gofrcli/migrate/page.md","rawUrl":"https://raw.githubusercontent.com/gofr-dev/gofr/HEAD/docs/references/gofrcli/migrate/page.md","title":"Migrate Skill","category":"anthropic-skill","format":"markdown","content":"---\ndescription: \"Generate timestamped database migration templates with an auto-maintained registry using the gofr migrate create command.\"\nnextjs:\n  metadata:\n    title: \"gofr migrate create — Generate Database Migration Templates\"\n    description: \"Generate timestamped database migration templates with an auto-maintained registry using the gofr migrate create command.\"\n---\n\n# gofr migrate create\n\nThe migrate create command generates a migration template file with pre-defined structure in your migrations directory.\nThis boilerplate code helps you maintain consistent patterns when writing database schema modifications across your project.\n\n\n## Command Usage\n```bash\n  gofr migrate create -name=<migration-name>\n```\n\n## Example Usage\n\n```bash\ngofr migrate create -name=create_employee_table\n```\nThis command generates a migration directory which has the below files:\n\n1. A new migration file with timestamp prefix (e.g., `20250127152047_create_employee_table.go`) containing:\n```go\npackage migrations\n\nimport (\n  \"gofr.dev/pkg/gofr/migration\"\n)\n\nfunc create_employee_table() migration.Migrate {\n  return migration.Migrate{\n    UP: func(d migration.Datasource) error {\n      // write your migrations here\n      return nil\n    },\n  }\n}\n```\n2. An auto-generated all.go file that maintains a registry of all migrations:\n```go\n// This is auto-generated file using 'gofr migrate' tool. DO NOT EDIT.\npackage migrations\n\nimport (\n  \"gofr.dev/pkg/gofr/migration\"\n)\n\nfunc All() map[int64]migration.Migrate {\n  return map[int64]migration.Migrate {\n    20250127152047: create_employee_table(),\n  }\n}\n```\n\n> **💡 Best Practice:** Learn about [organizing migrations by feature](/docs/advanced-guide/handling-data-migrations#organizing-migrations-by-feature) to avoid creating one migration per table or operation.\n\nFor detailed instructions on handling database migrations, see the [handling-data-migrations documentation](/docs/advanced-guide/handling-data-migrations)\nFor more examples, see the [using-migrations](https://github.com/gofr-dev/gofr/tree/main/examples/using-migrations)\n\n---\n\n## See also\n\n- [GoFr CLI overview](/docs/references/gofrcli)\n- [`gofr init`](/docs/references/gofrcli/init)\n- [`gofr wrap grpc`](/docs/references/gofrcli/wrap-grpc)\n- [`gofr store`](/docs/references/gofrcli/store)\n","frontmatter":{"description":"Generate timestamped database migration templates with an auto-maintained registry using the gofr migrate create command.","nextjs":{"metadata":{"title":"gofr migrate create — Generate Database Migration Templates","description":"Generate timestamped database migration templates with an auto-maintained registry using the gofr migrate create command."}}},"isInternal":false,"tokens":534,"sizeBytes":2304},{"name":"page.md","path":"docs/references/gofrcli/page.md","rawUrl":"https://raw.githubusercontent.com/gofr-dev/gofr/HEAD/docs/references/gofrcli/page.md","title":"Gofrcli Skill","category":"anthropic-skill","format":"markdown","content":"---\ndescription: \"Use the GoFr CLI to scaffold projects, generate boilerplate, and run framework-aware tasks. Speeds up repetitive work and keeps services consistent.\"\nnextjs:\n  metadata:\n    title: \"GoFr CLI Reference — Project Scaffolding and Tooling\"\n    description: \"Use the GoFr CLI to scaffold projects, generate boilerplate, and run framework-aware tasks. Speeds up repetitive work and keeps services consistent.\"\n---\n\n# GoFR Command Line Interface\n\nManaging repetitive tasks and maintaining consistency across large-scale applications is challenging!\n\n**GoFr CLI provides the following:**\n\n* All-in-one command-line tool designed specifically for GoFr applications\n* Simplifies **database migrations** management\n* **Store Layer Generator** for type-safe data access code from YAML configurations\n* Abstracts **tracing**, **metrics** and structured **logging** for GoFr's gRPC server/client\n* Enforces standard **GoFr conventions** in new projects\n\n## Prerequisites\n\n- Go 1.25 or above. To check Go version use the following command:\n```bash\n  go version\n```\n\n## **Installation**\nTo get started with GoFr CLI, use the below commands\n\n```bash\n  go install gofr.dev/cli/gofr@latest\n```\n\nTo check the installation:\n```bash\n  gofr version\n```\n---\n\n## Usage\n\nThe CLI can be run directly from the terminal after installation. Here’s the general syntax:\n\n```bash\n  gofr <subcommand> [flags]=[arguments]\n```\n---\n\n## Commands\n\nThe CLI groups its functionality into four commands. See each subpage for full reference:\n\n- [`gofr init`](/docs/references/gofrcli/init) — initialize a new GoFr project with the standard layout.\n- [`gofr migrate`](/docs/references/gofrcli/migrate) — create database migration templates with timestamped filenames and an auto-generated registry.\n- [`gofr wrap grpc`](/docs/references/gofrcli/wrap-grpc) — generate gRPC server/client wrappers with built-in tracing, metrics, and logging.\n- [`gofr store`](/docs/references/gofrcli/store) — generate a type-safe data-access layer from YAML schema definitions.\n","frontmatter":{"description":"Use the GoFr CLI to scaffold projects, generate boilerplate, and run framework-aware tasks. Speeds up repetitive work and keeps services consistent.","nextjs":{"metadata":{"title":"GoFr CLI Reference — Project Scaffolding and Tooling","description":"Use the GoFr CLI to scaffold projects, generate boilerplate, and run framework-aware tasks. Speeds up repetitive work and keeps services consistent."}}},"isInternal":false,"tokens":466,"sizeBytes":2046},{"name":"page.md","path":"docs/references/gofrcli/store/page.md","rawUrl":"https://raw.githubusercontent.com/gofr-dev/gofr/HEAD/docs/references/gofrcli/store/page.md","title":"Store Skill","category":"anthropic-skill","format":"markdown","content":"---\ndescription: \"Generate a type-safe data-access layer from YAML schema definitions using the gofr store command, with built-in observability and registry support.\"\nnextjs:\n  metadata:\n    title: \"gofr store — Generate Type-Safe Data-Access Layers from YAML\"\n    description: \"Generate a type-safe data-access layer from YAML schema definitions using the gofr store command, with built-in observability and registry support.\"\n---\n\n# gofr store\n\n> **Available since:** `gofr-cli` **v0.8.1**\n\nThe `gofr store` command is a code generator that creates type-safe data access layers from YAML configuration files. It eliminates boilerplate code while maintaining GoFr's best practices for observability and context management.\n\n## **Features**\n\n* **YAML-Driven Configuration**: Define your data models and queries in a simple, declarative format.\n* **Type-Safe Code Generation**: Generates Go interfaces and implementation boilerplates.\n* **GoFr Context Integration**: Generated methods work with `*gofr.Context` for built-in observability.\n* **Multiple Stores**: Define all stores in a single YAML file — each gets its own directory.\n* **Store Registry**: Centralized factory management of all generated stores via `stores/all.go`.\n\n## **Commands**\n\n### **Initialize Store Configuration**\n\nCreate a new store directory and a `store.yaml` configuration template. **The `-name` flag is required.**\n\n```bash\ngofr store init -name=<store-name>\n```\n\n**Example:**\n```bash\ngofr store init -name=user\n```\n\nThis creates the following structure:\n- `stores/store.yaml` — Configuration file template (shared across all stores).\n- `stores/all.go` — Store registry factory (auto-generated, DO NOT EDIT).\n- `stores/user/interface.go` — Initial interface stub (DO NOT EDIT — regenerated by `generate`).\n- `stores/user/user.go` — Initial implementation stub (editable — add your SQL logic here).\n\n### **Generate Store Code**\n\nGenerate or update Go code from your store configuration file.\n\n```bash\ngofr store generate\n```\n\n> **💡 Note:** By default, this command looks for the configuration at **`stores/store.yaml`**. To use a different path, use the `-config` flag:\n> ```bash\n> gofr store generate -config=path/to/store.yaml\n> ```\n\n---\n\n## **Quick Start Example**\n\n**Step 1: Initialize Configuration**\n```bash\ngofr store init -name=user\n```\n\n**Step 2: Define Your Store in `stores/store.yaml`**\n```yaml\nversion: \"1.0\"\n\nstores:\n  - name: \"user\"\n    package: \"user\"\n    output_dir: \"stores/user\"\n    interface: \"UserStore\"\n    implementation: \"userStore\"\n    queries:\n      - name: \"GetUserByID\"\n        sql: \"SELECT id, name, email FROM users WHERE id = ?\"\n        type: \"select\"\n        model: \"User\"\n        returns: \"single\"\n        params:\n          - name: \"id\"\n            type: \"int64\"\n        description: \"Retrieves a user by their ID\"\n\n      - name: \"GetAllUsers\"\n        sql: \"SELECT id, name, email FROM users\"\n        type: \"select\"\n        model: \"User\"\n        returns: \"multiple\"\n        description: \"Retrieves all users\"\n\nmodels:\n  - name: \"User\"\n    fields:\n      - name: \"ID\"\n        type: \"int64\"\n        tag: 'db:\"id\" json:\"id\"'\n      - name: \"Name\"\n        type: \"string\"\n        tag: 'db:\"name\" json:\"name\"'\n      - name: \"Email\"\n        type: \"string\"\n        tag: 'db:\"email\" json:\"email\"'\n```\n\n**Step 3: Generate Store Code**\n```bash\ngofr store generate\n```\n\nThis generates:\n```text\nstores/\n├── store.yaml          # Central Configuration\n├── all.go              # Store registry factory (auto-generated)\n└── user/\n    ├── interface.go    # UserStore interface definition\n    ├── userStore.go    # userStore implementation boilerplate\n    └── user.go         # User model struct\n```\n\n**Step 4: Use in Your Application**\n```go\npackage main\n\nimport (\n    \"gofr.dev/pkg/gofr\"\n    \"your-project/stores/user\"\n)\n\nfunc main() {\n    app := gofr.New()\n\n    userStore := user.NewUserStore()\n\n    app.GET(\"/users/{id}\", func(ctx *gofr.Context) (interface{}, error) {\n        id, _ := strconv.ParseInt(ctx.PathParam(\"id\"), 10, 64)\n        return userStore.GetUserByID(ctx, id)\n    })\n\n    app.GET(\"/users\", func(ctx *gofr.Context) (interface{}, error) {\n        return userStore.GetAllUsers(ctx)\n    })\n\n    app.Run()\n}\n```\n\n---\n\n## **Multiple Stores in One File**\n\nYou can define all stores in a single YAML file. Each store gets its own output directory and all are registered into the same `stores/all.go` registry.\n\n```yaml\nversion: \"1.0\"\n\nstores:\n  - name: \"user\"\n    package: \"user\"\n    output_dir: \"stores/user\"\n    interface: \"UserStore\"\n    implementation: \"userStore\"\n    queries: [...]\n\n  - name: \"product\"\n    package: \"product\"\n    output_dir: \"stores/product\"\n    interface: \"ProductStore\"\n    implementation: \"productStore\"\n    queries: [...]\n\nmodels:\n  - name: \"User\"\n    fields: [...]\n  - name: \"Product\"\n    fields: [...]\n```\n\n**Generated structure:**\n```text\nstores/\n├── all.go\n├── user/\n│   ├── interface.go\n│   ├── userStore.go\n│   └── user.go\n└── product/\n    ├── interface.go\n    ├── productStore.go\n    └── product.go\n```\n\n**Using the registry with multiple stores:**\n```go\nimport (\n\"your-project/stores\"\n\"your-project/stores/user\"\n\"your-project/stores/product\"\n)\n\n// stores.GetStore returns a factory-created instance\nuserStore    := stores.GetStore(\"user\").(user.UserStore)\nproductStore := stores.GetStore(\"product\").(product.ProductStore)\n```\n\n> **💡 Note:** `stores.All()` returns a `map[string]func() any` — a map of **factory functions**, not active instances. `stores.GetStore(name)` calls the factory for you and returns the instance.\n\n---\n\n## **Configuration Reference**\n\n### **Store Configuration**\n\n| Field | Description | Required |\n|-------|-------------|----------|\n| `name` | Store identifier used in the registry key. | **Yes** |\n| `package` | Go package name for generated code. | **Yes** |\n| `output_dir` | Directory path where files will be generated. | Optional (defaults to `stores/<name>`) |\n| `interface` | Interface name — **recommended: `<Name>Store`** (e.g., `UserStore`). | Optional (defaults to `<Name>Store`) |\n| `implementation` | Private struct name for the implementation (e.g., `userStore`). | Optional (defaults to `<name>Store`) |\n| `queries` | List of database queries. | Optional |\n\n> **⚠️ Naming Convention:** The registry (`stores/all.go`) uses a hardcoded `<Name>Store` pattern when generating constructor calls (e.g., `NewUserStore()`). Always name your interface as `<Name>Store` to avoid compilation errors.\n\n### **Query Types**\n\n* **`select`** — SELECT queries.\n* **`insert`** — INSERT queries.\n* **`update`** — UPDATE queries.\n* **`delete`** — DELETE queries.\n\n### **Return Types**\n\n* **`single`** — Returns `(Model, error)`.\n* **`multiple`** — Returns `([]Model, error)`.\n* **`count`** — Returns `(int64, error)`.\n* **`custom`** — Returns `(any, error)`.\n\n### **Query Parameters**\n\n```yaml\nparams:\n  - name: \"id\"\n    type: \"int64\"\n  - name: \"email\"\n    type: \"string\"\n```\n\nSupported parameter types include all Go primitive types, `time.Time`, and pointer types (e.g., `*int64`).\n\n---\n\n## **Model Generation**\n\n### **Generate New Models**\n\n```yaml\nmodels:\n  - name: \"User\"\n    fields:\n      - name: \"ID\"\n        type: \"int64\"\n        tag: 'db:\"id\" json:\"id\"'\n      - name: \"Name\"\n        type: \"string\"\n        tag: 'db:\"name\" json:\"name\"'\n      - name: \"CreatedAt\"\n        type: \"time.Time\"\n        tag: 'db:\"created_at\" json:\"created_at\"'\n```\n\nThis generates:\n```go\ntype User struct {\nID        int64     `db:\"id\" json:\"id\"`\nName      string    `db:\"name\" json:\"name\"`\nCreatedAt time.Time `db:\"created_at\" json:\"created_at\"`\n}\n\nfunc (User) TableName() string {\nreturn \"user\"\n}\n```\n\n### **Reference Existing Models**\n\nIf you already have models defined elsewhere:\n\n```yaml\nmodels:\n  - name: \"User\"\n    path: \"../models/user.go\"\n    package: \"your-project/models\"\n```\n\n---\n\n## **Generated Code Structure**\n\n### **Interface (`interface.go`)**\n\n```go\n// Code generated by gofr.dev/cli/gofr. DO NOT EDIT.\npackage user\n\nimport \"gofr.dev/pkg/gofr\"\n\ntype UserStore interface {\n  GetUserByID(ctx *gofr.Context, id int64) (User, error)\n  GetAllUsers(ctx *gofr.Context) ([]User, error)\n}\n```\n\n### **Implementation (`userStore.go`)**\n\n```go\n// Code generated by gofr.dev/cli/gofr. DO NOT EDIT.\npackage user\n\ntype userStore struct{}\n\nfunc NewUserStore() UserStore {\n   return &userStore{}\n}\n\nfunc (s *userStore) GetUserByID(ctx *gofr.Context, id int64) (User, error) {\n   // TODO: Implement using ctx.SQL()\n   var result User\n   // err := ctx.SQL().QueryRowContext(ctx, sql, id).Scan(&result.ID, ...)\n   return result, nil\n}\n\nfunc (s *userStore) GetAllUsers(ctx *gofr.Context) ([]User, error) {\n   // TODO: Implement using ctx.SQL()\n   return []User{}, nil\n}\n```\n\n---\n\n## **Best Practices**\n\n1. **Implement the TODOs**: The generator creates method **signatures and boilerplate only**. You must fill in the `// TODO: Implement` sections with actual SQL execution using `ctx.SQL()` methods.\n2. **Use `<Name>Store` Interface Names**: The registry assumes this convention. E.g., `interface: \"UserStore\"` results in the constructor `NewUserStore()` and type assertion `.(user.UserStore)`.\n3. **One YAML, Many Stores**: Define all your stores in a single `store.yaml` to keep your data access layer centrally configured.\n4. **Know Which Files Are Auto-Generated**: Only `interface.go` and `all.go` are marked `DO NOT EDIT` and are overwritten on every `gofr store generate`. The implementation stub (`<name>.go`) created by `gofr store init` is editable — this is where you add your SQL logic. The `userStore.go` generated by `gofr store generate` is also editable boilerplate.\n5. **Version Control**: Always commit your `store.yaml`. Re-run `gofr store generate` after any configuration change to sync the generated interfaces.\n\n---\n\n## **Complete Example**\n\nFor a complete working example of the store generator, see the [store example](https://github.com/gofr-dev/gofr-cli/tree/main/store/example.yaml) in the gofr-cli repository.\n\nFor detailed configuration options and advanced usage, refer to the [Store Generator README](https://github.com/gofr-dev/gofr-cli/blob/main/store/README.md).\n\n---\n\n## See also\n\n- [GoFr CLI overview](/docs/references/gofrcli)\n- [`gofr init`](/docs/references/gofrcli/init)\n- [`gofr migrate`](/docs/references/gofrcli/migrate)\n- [`gofr wrap grpc`](/docs/references/gofrcli/wrap-grpc)\n","frontmatter":{"description":"Generate a type-safe data-access layer from YAML schema definitions using the gofr store command, with built-in observability and registry support.","nextjs":{"metadata":{"title":"gofr store — Generate Type-Safe Data-Access Layers from YAML","description":"Generate a type-safe data-access layer from YAML schema definitions using the gofr store command, with built-in observability and registry support."}}},"isInternal":false,"tokens":2669,"sizeBytes":10510},{"name":"page.md","path":"docs/references/gofrcli/wrap-grpc/page.md","rawUrl":"https://raw.githubusercontent.com/gofr-dev/gofr/HEAD/docs/references/gofrcli/wrap-grpc/page.md","title":"Wrap-grpc Skill","category":"anthropic-skill","format":"markdown","content":"---\ndescription: \"Generate gRPC server and client wrappers with built-in tracing, metrics, and logging using the gofr wrap grpc command.\"\nnextjs:\n  metadata:\n    title: \"gofr wrap grpc — Generate gRPC Server/Client Wrappers\"\n    description: \"Generate gRPC server and client wrappers with built-in tracing, metrics, and logging using the gofr wrap grpc command.\"\n---\n\n# gofr wrap grpc\n\n* The gofr wrap grpc command streamlines gRPC integration in a GoFr project by generating GoFr's context-aware structures.\n* It simplifies setting up gRPC handlers with minimal steps, and accessing datasources, adding tracing as well as custom metrics. Based on the proto file it creates the handler/client with GoFr's context.\n  For detailed instructions on using grpc with GoFr see the [gRPC documentation](/docs/advanced-guide/grpc)\n\n## Command Usage\n**gRPC Server**\n```bash\n  gofr wrap grpc server --proto=<path_to_the_proto_file>\n```\n## Generated Files\n**Server**\n- ```{serviceName}_gofr.go (auto-generated; do not modify)```\n- ```{serviceName}_server.go (example structure below)```\n\n## Example Usage\n**gRPC Server**\n\nThe command generates a server implementation template similar to this:\n```go\npackage server\n\nimport (\n   \"gofr.dev/pkg/gofr\"\n)\n\n// Register the gRPC service in your app using the following code in your main.go:\n//\n// service.Register{ServiceName}ServerWithGofr(app, &server.{ServiceName}Server{})\n//\n// {ServiceName}Server defines the gRPC server implementation.\n// Customize the struct with required dependencies and fields as needed.\ntype {ServiceName}Server struct {\n}\n\n// Example method (actual methods will depend on your proto file)\nfunc (s *MyServiceServer) MethodName(ctx *gofr.Context) (any, error) {\n   // Replace with actual logic if needed\n   return &ServiceResponse{\n   }, nil\n}\n```\nFor detailed instruction on setting up a gRPC server with GoFr see the [gRPC Server Documentation](https://gofr.dev/docs/advanced-guide/grpc#generating-g-rpc-server-handler-template-using)\n\n**gRPC Client**\n```bash\n  gofr wrap grpc client --proto=<path_to_the_proto_file>\n```\n\n**Client**\n- ```{serviceName}_client.go (example structure below)```\n\n\n## Example Usage:\nAssuming the service is named hello, after generating the hello_client.go file, you can seamlessly register and access the gRPC service using the following steps:\n\n```go\ntype GreetHandler struct {\n\thelloGRPCClient client.HelloGoFrClient\n}\n\nfunc NewGreetHandler(helloClient client.HelloGoFrClient) *GreetHandler {\n    return &GreetHandler{\n        helloGRPCClient: helloClient,\n    }\n}\n\nfunc (g GreetHandler) Hello(ctx *gofr.Context) (any, error) {\n    userName := ctx.Param(\"name\")\n    helloResponse, err := g.helloGRPCClient.SayHello(ctx, &client.HelloRequest{Name: userName})\n    if err != nil {\n        return nil, err\n    }\n\n    return helloResponse, nil\n}\n\nfunc main() {\n    app := gofr.New()\n\n// Create a gRPC client for the Hello service\n    helloGRPCClient, err := client.NewHelloGoFrClient(app.Config.Get(\"GRPC_SERVER_HOST\"), app.Metrics())\n    if err != nil {\n\t\tapp.Logger().Errorf(\"Failed to create Hello gRPC client: %v\", err)\n    return\n}\n\n    greetHandler := NewGreetHandler(helloGRPCClient)\n\n    // Register HTTP endpoint for Hello service\n    app.GET(\"/hello\", greetHandler.Hello)\n\n    // Run the application\n    app.Run()\n}\n```\nFor detailed instruction on setting up a gRPC server with GoFr see the [gRPC Client Documentation](https://gofr.dev/docs/advanced-guide/grpc#generating-tracing-enabled-g-rpc-client-using)\nFor more examples refer [gRPC Examples](https://github.com/gofr-dev/gofr/tree/main/examples/grpc)\n\n---\n\n## See also\n\n- [GoFr CLI overview](/docs/references/gofrcli)\n- [`gofr init`](/docs/references/gofrcli/init)\n- [`gofr migrate`](/docs/references/gofrcli/migrate)\n- [`gofr store`](/docs/references/gofrcli/store)\n","frontmatter":{"description":"Generate gRPC server and client wrappers with built-in tracing, metrics, and logging using the gofr wrap grpc command.","nextjs":{"metadata":{"title":"gofr wrap grpc — Generate gRPC Server/Client Wrappers","description":"Generate gRPC server and client wrappers with built-in tracing, metrics, and logging using the gofr wrap grpc command."}}},"isInternal":false,"tokens":949,"sizeBytes":3821},{"name":"page.md","path":"docs/references/testing/page.md","rawUrl":"https://raw.githubusercontent.com/gofr-dev/gofr/HEAD/docs/references/testing/page.md","title":"Testing Skill","category":"anthropic-skill","format":"markdown","content":"---\ndescription: \"Write unit and integration tests for GoFr REST APIs. Mock the container's dependencies and assert handler responses, status codes, and headers reliably.\"\nnextjs:\n  metadata:\n    title: \"Testing GoFr REST APIs — Handlers, Mocks, Assertions\"\n    description: \"Write unit and integration tests for GoFr REST APIs. Mock the container's dependencies and assert handler responses, status codes, and headers reliably.\"\n---\n\n# Testing REST APIs with GoFr\n\nTesting REST APIs ensures that your endpoints function correctly under various conditions. This guide demonstrates how to write tests for GoFr-based REST APIs.\n\n## Mocking Databases in GoFr\n\nMocking databases allows for isolated testing by simulating various scenarios. GoFr's built-in mock container supports, not only SQL databases, but also extends to other data stores, including Redis, Cassandra, Key-Value stores, MongoDB, and ClickHouse.\n\n### Mocking `Select` Queries\n\n`Select` reads rows into a destination, so its mock takes the response you want written into that destination. Pass a pointer of the destination's type to `ExpectSelect`, along with the exact query text and arguments your handler uses, then set the rows with `ReturnsResponse`:\n\n```go\nvar users []User\n\nmock.SQL.ExpectSelect(ctx, &users, \"SELECT id, name FROM users WHERE status = ?\", \"active\").\n\tReturnsResponse([]User{{ID: 1, Name: \"John\"}})\n```\n\nWhen the handler calls `ctx.SQL.Select(ctx, &dest, \"SELECT id, name FROM users WHERE status = ?\", \"active\")`, `dest` is set to the response.\n\nThe query text must match exactly, and the arguments must have the same count, values and types (compared with `reflect.DeepEqual`, so slices such as `IN` lists are supported). If the query or arguments do not match, the destination is left untouched and the test fails with a message showing the expected and actual values.\n\n## Example of Unit Testing a REST API Using GoFr\n\nBelow is an example of how to test, say the `Add` method of a handler that interacts with a SQL database.\n\nHere’s an `Add` function for adding a book to the database using GoFr:\n\n```go\n// main.go\npackage main\n\nimport (\n\t\"gofr.dev/pkg/gofr\"\n\t\"gofr.dev/pkg/gofr/http\"\n)\n\ntype Book struct {\n\tId    int    `json:\"id\"`\n\tISBN  int    `json:\"isbn\"`\n\tTitle string `json:\"title\"`\n}\n\nfunc Add(ctx *gofr.Context) (any, error) {\n\tvar book Book\n\n\tif err := ctx.Bind(&book); err != nil {\n\t\tctx.Logger.Errorf(\"error in binding: %v\", err)\n\t\treturn nil, http.ErrorInvalidParam{Params: []string{\"body\"}}\n\t}\n\n\t// we assume the `id` column in the database is set to auto-increment.\n\tres, err := ctx.SQL.ExecContext(ctx, `INSERT INTO books (title, isbn) VALUES (?, ?)`, book.Title, book.ISBN)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tid, err := res.LastInsertId()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn id, nil\n}\n\nfunc main() {\n\t// initialize gofr object\n\tapp := gofr.New()\n\n\tapp.POST(\"/book\", Add)\n\n\t// Run the application\n\tapp.Run()\n}\n\n```\n\nHere’s how to write tests using GoFr:\n\n```go\n// main_test.go\npackage main\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"database/sql\"\n\t\"errors\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"gofr.dev/pkg/gofr\"\n\t\"gofr.dev/pkg/gofr/container\"\n\tgofrHttp \"gofr.dev/pkg/gofr/http\"\n)\n\nfunc TestAdd(t *testing.T) {\n\ttype gofrResponse struct {\n\t\tresult any\n\t\terr    error\n\t}\n\n\t// NewMockContainer provides mock implementations for various databases including:\n\t// Redis, SQL, ClickHouse, Cassandra, MongoDB, and KVStore.\n\t// These mock can be used to define database expectations in unit tests,\n\t// similar to the SQL example demonstrated here.\n\tmockContainer, mock := container.NewMockContainer(t)\n\n\tctx := &gofr.Context{\n\t\tContext:   context.Background(),\n\t\tRequest:   nil,\n\t\tContainer: mockContainer,\n\t}\n\n\ttests := []struct {\n\t\tname             string\n\t\trequestBody      string\n\t\tmockExpect       func()\n\t\texpectedResponse any\n\t}{\n\t\t{\n\t\t\tname:        \"Error while Binding\",\n\t\t\trequestBody: `title\":\"Book Title\",\"isbn\":12345}`,\n\t\t\tmockExpect: func() {\n\t\t\t},\n\t\t\texpectedResponse: gofrResponse{\n\t\t\t\tnil,\n\t\t\t\tgofrHttp.ErrorInvalidParam{Params: []string{\"body\"}}},\n\t\t},\n\t\t{\n\t\t\tname:        \"Successful Insertion\",\n\t\t\trequestBody: `{\"title\":\"Book Title\",\"isbn\":12345}`,\n\t\t\tmockExpect: func() {\n\t\t\t\tmock.SQL.\n\t\t\t\t\tExpectExec(`INSERT INTO books (title, isbn) VALUES (?, ?)`).\n\t\t\t\t\tWithArgs(\"Book Title\", 12345).\n\t\t\t\t\tWillReturnResult(sqlmock.NewResult(12, 1))\n\t\t\t},\n\t\t\texpectedResponse: gofrResponse{\n\t\t\t\tint64(12),\n\t\t\t\tnil,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:        \"Error on Insertion\",\n\t\t\trequestBody: `{\"title\":\"Book Title\",\"isbn\":12345}`,\n\t\t\tmockExpect: func() {\n\t\t\t\tmock.SQL.\n\t\t\t\t\tExpectExec(`INSERT INTO books (title, isbn) VALUES (?, ?)`).\n\t\t\t\t\tWithArgs(\"Book Title\", 12345).\n\t\t\t\t\tWillReturnError(sql.ErrConnDone)\n\t\t\t},\n\t\t\texpectedResponse: gofrResponse{\n\t\t\t\tnil,\n\t\t\t\tsql.ErrConnDone},\n\t\t},\n\t\t{\n\t\t\tname:        \"Error while fetching LastInsertId\",\n\t\t\trequestBody: `{\"title\":\"Book Title\",\"isbn\":12345}`,\n\t\t\tmockExpect: func() {\n\t\t\t\tmock.SQL.\n\t\t\t\t\tExpectExec(`INSERT INTO books (title, isbn) VALUES (?, ?)`).\n\t\t\t\t\tWithArgs(\"Book Title\", 12345).\n\t\t\t\t\tWillReturnError(errors.New(\"mocked result error\"))\n\t\t\t},\n\t\t\texpectedResponse: gofrResponse{\n\t\t\t\tnil,\n\t\t\t\terrors.New(\"mocked result error\")},\n\t\t},\n\t}\n\n\tfor i, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ttt.mockExpect()\n\n\t\t\tvar req *http.Request\n\n\t\t\treq = httptest.NewRequest(\n\t\t\t\thttp.MethodPost,\n\t\t\t\t\"/book\",\n\t\t\t\tbytes.NewBuffer([]byte(tt.requestBody)),\n\t\t\t)\n\n\t\t\treq.Header.Set(\"Content-Type\", \"application/json\")\n\n\t\t\trequest := gofrHttp.NewRequest(req)\n\n\t\t\tctx.Request = request\n\n\t\t\tval, err := Add(ctx)\n\n\t\t\tresponse := gofrResponse{val, err}\n\n\t\t\tassert.Equal(t, tt.expectedResponse, response, \"TEST[%d], Failed.\\n%s\", i, tt.name)\n\t\t})\n\t}\n}\n\n```\n\n## Testing HTTP Handlers with Mock Services\n\nWhen you register multiple services with `WithMockHTTPService`, each service gets its own separate mock instance. This allows you to set different expectations for each service using the `mocks.HTTPServices` map. Use table-driven tests to cover multiple scenarios:\n\n### Important Notes\n\n- **Context Matching**: Always use the exact context from your `gofr.Context` (`ctx.Context`) in expectations. gomock compares contexts by reference, not value, so using `t.Context()` or `context.Background()` will fail.\n- **Service Registration**: `WithMockHTTPService(\"serviceName\")` registers the service with the specified name. Each service gets its own separate mock instance.\n- **Multiple Services**: Use `mocks.HTTPServices[\"serviceName\"]` to access and set different expectations for each service. Each service has its own mock instance, so expectations are independent.\n- **Tests will fail** if the mocked HTTPService is not called as expected or if the context doesn't match.\n\n```go\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gofr.dev/pkg/gofr\"\n\t\"gofr.dev/pkg/gofr/container\"\n\tgofrHttp \"gofr.dev/pkg/gofr/http\"\n)\n\n// Handler that calls multiple HTTP services\n// This handler demonstrates calling two different services (paymentService and shippingService)\n// to fetch order details from different parts of the system.\nfunc OrderDetailsHandler(ctx *gofr.Context) (any, error) {\n\torderID := ctx.PathParam(\"id\")\n\tif orderID == \"\" {\n\t\treturn nil, errors.New(\"order ID is required\")\n\t}\n\n\t// First HTTP service call: Get payment details from paymentService\n\tpaymentService := ctx.GetHTTPService(\"paymentService\")\n\tpaymentResp, err := paymentService.Get(ctx.Context, \"/payments/\"+orderID, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to fetch payment details: %w\", err)\n\t}\n\tdefer paymentResp.Body.Close()\n\n\tvar paymentData struct {\n\t\tStatus string `json:\"status\"`\n\t\tAmount int    `json:\"amount\"`\n\t}\n\n\tpaymentBody, err := io.ReadAll(paymentResp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read payment response: %w\", err)\n\t}\n\n\tif err := json.Unmarshal(paymentBody, &paymentData); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse payment response: %w\", err)\n\t}\n\n\t// Second HTTP service call: Get shipping details from shippingService\n\tshippingService := ctx.GetHTTPService(\"shippingService\")\n\tshippingResp, err := shippingService.Get(ctx.Context, \"/shipping/\"+orderID, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to fetch shipping details: %w\", err)\n\t}\n\tdefer shippingResp.Body.Close()\n\n\tvar shippingData struct {\n\t\tStatus           string `json:\"status\"`\n\t\tTracking         string `json:\"tracking\"`\n\t\tEstimatedDelivery string `json:\"estimated_delivery\"`\n\t}\n\n\tshippingBody, err := io.ReadAll(shippingResp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read shipping response: %w\", err)\n\t}\n\n\tif err := json.Unmarshal(shippingBody, &shippingData); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse shipping response: %w\", err)\n\t}\n\n\t// Combine results from both services\n\treturn map[string]any{\n\t\t\"order_id\":          orderID,\n\t\t\"payment_status\":    paymentData.Status,\n\t\t\"payment_amount\":    paymentData.Amount,\n\t\t\"shipping_status\":   shippingData.Status,\n\t\t\"tracking_number\":   shippingData.Tracking,\n\t\t\"estimated_delivery\": shippingData.EstimatedDelivery,\n\t}, nil\n}\n\nfunc TestOrderDetailsHandler(t *testing.T) {\n\t// Helper function to create test context with path parameters\n\tcreateTestContext := func(path string, container *container.Container) *gofr.Context {\n\t\treq := httptest.NewRequest(http.MethodGet, path, nil)\n\t\t\n\t\t// Set path parameters using mux.SetURLVars (required for ctx.PathParam to work)\n\t\tif strings.Contains(path, \"/orders/\") {\n\t\t\tparts := strings.Split(strings.Trim(path, \"/\"), \"/\")\n\t\t\tif len(parts) >= 2 && parts[1] != \"\" {\n\t\t\t\treq = mux.SetURLVars(req, map[string]string{\"id\": parts[1]})\n\t\t\t}\n\t\t}\n\n\t\treturn &gofr.Context{\n\t\t\tContext:   req.Context(),\n\t\t\tRequest:   gofrHttp.NewRequest(req),\n\t\t\tContainer: container,\n\t\t}\n\t}\n\n\tconst testOrderID = \"12345\" // Reusable order ID for tests\n\n\ttests := []struct {\n\t\tname           string\n\t\tsetupMocks     func(*container.Mocks, *gofr.Context)\n\t\trequestPath    string\n\t\twantErr        bool\n\t\twantErrMsg     string\n\t\tvalidateResult func(*testing.T, any)\n\t}{\n\t\t{\n\t\t\tname: \"successful order details retrieval\",\n\t\t\tsetupMocks: func(mocks *container.Mocks, ctx *gofr.Context) {\n\t\t\t\t// Set up expectation for paymentService - this is the first HTTP call in the handler\n\t\t\t\tpaymentResp := &http.Response{\n\t\t\t\t\tStatusCode: http.StatusOK,\n\t\t\t\t\tBody:       io.NopCloser(strings.NewReader(`{\"status\":\"completed\",\"amount\":1500}`)),\n\t\t\t\t}\n\t\t\t\tmocks.HTTPServices[\"paymentService\"].EXPECT().Get(\n\t\t\t\t\tctx.Context,\n\t\t\t\t\t\"/payments/\"+testOrderID,\n\t\t\t\t\tnil,\n\t\t\t\t).Return(paymentResp, nil)\n\n\t\t\t\t// Set up expectation for shippingService - this is the second HTTP call in the handler\n\t\t\t\t// Note: Each service has its own independent mock instance\n\t\t\t\tshippingResp := &http.Response{\n\t\t\t\t\tStatusCode: http.StatusOK,\n\t\t\t\t\tBody:       io.NopCloser(strings.NewReader(`{\"status\":\"in_transit\",\"tracking\":\"TRACK123\",\"estimated_delivery\":\"2024-12-25\"}`)),\n\t\t\t\t}\n\t\t\t\tmocks.HTTPServices[\"shippingService\"].EXPECT().Get(\n\t\t\t\t\tctx.Context,\n\t\t\t\t\t\"/shipping/\"+testOrderID,\n\t\t\t\t\tnil,\n\t\t\t\t).Return(shippingResp, nil)\n\t\t\t},\n\t\t\trequestPath: \"/orders/\" + testOrderID,\n\t\t\twantErr:     false,\n\t\t\tvalidateResult: func(t *testing.T, result any) {\n\t\t\t\tresultMap := result.(map[string]any)\n\t\t\t\tassert.Equal(t, testOrderID, resultMap[\"order_id\"])\n\t\t\t\tassert.Equal(t, \"completed\", resultMap[\"payment_status\"])\n\t\t\t\tassert.Equal(t, 1500, resultMap[\"payment_amount\"])\n\t\t\t\tassert.Equal(t, \"in_transit\", resultMap[\"shipping_status\"])\n\t\t\t\tassert.Equal(t, \"TRACK123\", resultMap[\"tracking_number\"])\n\t\t\t\tassert.Equal(t, \"2024-12-25\", resultMap[\"estimated_delivery\"])\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"payment service error\",\n\t\t\tsetupMocks: func(mocks *container.Mocks, ctx *gofr.Context) {\n\t\t\t\t// Payment service returns an error - handler should fail before calling shipping service\n\t\t\t\tmocks.HTTPServices[\"paymentService\"].EXPECT().Get(\n\t\t\t\t\tctx.Context,\n\t\t\t\t\t\"/payments/\"+testOrderID,\n\t\t\t\t\tnil,\n\t\t\t\t).Return(nil, errors.New(\"payment service unavailable\"))\n\n\t\t\t\t// Shipping service should NOT be called when payment service fails\n\t\t\t\t// No expectation set for shippingService - test will fail if it's called\n\t\t\t},\n\t\t\trequestPath: \"/orders/\" + testOrderID,\n\t\t\twantErr:     true,\n\t\t\twantErrMsg:  \"failed to fetch payment details\",\n\t\t},\n\t\t{\n\t\t\tname: \"shipping service error\",\n\t\t\tsetupMocks: func(mocks *container.Mocks, ctx *gofr.Context) {\n\t\t\t\t// Payment service succeeds\n\t\t\t\tpaymentResp := &http.Response{\n\t\t\t\t\tStatusCode: http.StatusOK,\n\t\t\t\t\tBody:       io.NopCloser(strings.NewReader(`{\"status\":\"completed\",\"amount\":1500}`)),\n\t\t\t\t}\n\t\t\t\tmocks.HTTPServices[\"paymentService\"].EXPECT().Get(\n\t\t\t\t\tctx.Context,\n\t\t\t\t\t\"/payments/\"+testOrderID,\n\t\t\t\t\tnil,\n\t\t\t\t).Return(paymentResp, nil)\n\n\t\t\t\t// Shipping service returns an error - this is the second HTTP call\n\t\t\t\tmocks.HTTPServices[\"shippingService\"].EXPECT().Get(\n\t\t\t\t\tctx.Context,\n\t\t\t\t\t\"/shipping/\"+testOrderID,\n\t\t\t\t\tnil,\n\t\t\t\t).Return(nil, errors.New(\"shipping service unavailable\"))\n\t\t\t},\n\t\t\trequestPath: \"/orders/\" + testOrderID,\n\t\t\twantErr:     true,\n\t\t\twantErrMsg:  \"failed to fetch shipping details\",\n\t\t},\n\t\t{\n\t\t\tname: \"missing order ID\",\n\t\t\tsetupMocks: func(mocks *container.Mocks, ctx *gofr.Context) {\n\t\t\t\t// No service calls should be made when order ID is missing\n\t\t\t},\n\t\t\trequestPath: \"/orders/\",\n\t\t\twantErr:     true,\n\t\t\twantErrMsg:  \"order ID is required\",\n\t\t},\n\t}\n\n\t// Register HTTP services once - each service gets its own separate mock instance\n\t// Since all test cases use the same services, we can create the mock container outside the loop\n\tmockContainer, mocks := container.NewMockContainer(t,\n\t\tcontainer.WithMockHTTPService(\"paymentService\", \"shippingService\"),\n\t)\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Create test context using helper function\n\t\t\tctx := createTestContext(tt.requestPath, mockContainer)\n\n\t\t\t// Set up mock expectations BEFORE calling the handler\n\t\t\t// Each service's expectations are independent\n\t\t\ttt.setupMocks(mocks, ctx)\n\n\t\t\t// Call the handler\n\t\t\tresult, err := OrderDetailsHandler(ctx)\n\n\t\t\tif tt.wantErr {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), tt.wantErrMsg)\n\t\t\t\tassert.Nil(t, result)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tif tt.validateResult != nil {\n\t\t\t\t\ttt.validateResult(t, result)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n```\n\n**Key Points**:\n- Each service registered via `WithMockHTTPService` gets its own separate mock instance\n- Always use `mocks.HTTPServices[\"serviceName\"]` to access and set expectations for a specific service\n- Always create the `gofr.Context` with the exact request context (`req.Context()`) that will be used in the handler\n- Set expectations on the mock services before calling the handler\n- Test both success and error scenarios to ensure your handlers handle all cases correctly\n\n### Summary\n\n- **Mocking Database Interactions**: Use GoFr mock container to simulate database interactions.\n- **Mocking HTTP Services**: Use `WithMockHTTPService(\"serviceName\")` to register and mock HTTP services.\n- **Context Matching**: Always use `ctx.Context` from your `gofr.Context` in mock expectations, not `t.Context()` or `context.Background()`.\n- **Define Test Cases**: Create table-driven tests to handle various scenarios.\n- **Run and Validate**: Ensure that your tests check for expected results, and handle errors correctly.\n\nThis approach guarantees that your database and HTTP service interactions are tested independently, allowing you to simulate different responses and errors hassle-free.\n","frontmatter":{"description":"Write unit and integration tests for GoFr REST APIs. Mock the container's dependencies and assert handler responses, status codes, and headers reliably.","nextjs":{"metadata":{"title":"Testing GoFr REST APIs — Handlers, Mocks, Assertions","description":"Write unit and integration tests for GoFr REST APIs. Mock the container's dependencies and assert handler responses, status codes, and headers reliably."}}},"isInternal":false,"tokens":3914,"sizeBytes":15722}],"systemPromptSnippet":"<yakaai_skills repo=\"gofr-dev/gofr\">\n<!-- File: docs/AGENTS.md (Tokens: ~2605 | Category: root-instruction) -->\n# GoFr — guide for AI coding assistants\n\nFor Claude Code, Cursor, Aider, Codex, etc. Hand\n[https://gofr.dev/AGENTS.md](https://gofr.dev/AGENTS.md) to your assistant\nwhen working on a GoFr project. It points at the specific docs you'll\nactually need rather than inlining everything.\n\nGoFr is an opinionated Go framework for microservices. Apache 2.0.\nRequires Go 1.26+. Repo: <https://github.com/gofr-dev/gofr>.\n\n## Core rules an assistant must know\n\n1. **One handler signature** for HTTP / gRPC / GraphQL / WebSocket / cron / CLI:\n   `func(c *gofr.Context) (any, error)`. Return value → `{\"data\": ...}`. Return error → error response.\n2. **Path params use `{name}`**, not `:name`. `app.GET(\"/users/{id}\", h)`.\n3. **`c.PathParam(\"id\")`** for path; **`c.Param(\"q\")`** for query; **`c.Bind(&v)`** for body.\n4. **Don't manually wire OpenTelemetry, Prometheus, or structured logging.** `gofr.New()` does it.\n5. **Pass `*gofr.Context`** (not `context.Background()`) to every downstream call so trace propagation and cancellation work.\n6. **Configuration comes from `configs/.env`** via `c.Config.Get(key)`. No hardcoded ports / hosts / secrets.\n7. **No ORM bundled.** Use plain SQL via `c.SQL`, or pair with `sqlc`/`gorm` yourself.\n8. **Middleware is standard `net/http`**: `func(http.Handler) http.Handler`, registered with `app.UseMiddleware(...)`.\n9. **Health is auto-exposed** at `/.well-known/health` and `/.well-known/alive`. Don't hand-roll `/healthz`.\n10. **Don't `panic()` for control flow.** Return errors.\n\n## Minimal app\n\n```go\npackage main\n\nimport \"gofr.dev/pkg/gofr\"\n\nfunc main() {\n    app := gofr.New()\n    app.GET(\"/hello\", func(c *gofr.Context) (any, error) {\n        return \"Hello, world\", nil\n    })\n    app.Run()\n}\n```\n\n## Migrations (schema + seed data, versioned)\n\nGoFr has a built-in migration runner — use it instead of `golang-migrate` / `goose`. Works for SQL, Redis, Mongo, Cassandra, ClickHouse, DGraph, SurrealDB.\n\n**Before writing a migration, fetch the full reference:** <https://gofr.dev/docs/advanced-guide/handling-data-migrations>. Runnable shape: <https://github.com/gofr-dev/gofr/tree/main/examples/using-migrations>.\n\nFive rules to keep in your head so you don't have to re-fetch on every change:\n\n1. Files live in `migrations/<unix-ts>_<name>.go`. Versions are `int64`, monotonic. Use `date +%s` for new ones.\n2. `migrations/all.go` exports `All() map[int64]migration.Migrate`. Wire with `a.Migrate(migrations.All())` once in `main.go`.\n3. Each migration is `migration.Migrate{ UP: func(d migration.Datasource) error { ... } }`. Inside `UP`, act on `d.SQL`, `d.Redis`, `d.MongoDB`, `d.Cassandra`, `d.Clickhouse`, `d.DGraph`, `d.SurrealDB`, `d.Logger`.\n4. Each migration runs **exactly once** per environment — don't add idempotent guards. There is **no down migration**; rollback = new forward migration.\n5. One purpose per file. Don't combine \"create table + backfill + drop column\" in one `UP`.\n\n## AI features: LLMs and MCP\n\nGoFr ships LLM and agent support. Use it instead of importing a provider SDK or hand-rolling HTTP, tracing and metrics\naround model calls. **Before writing this code, fetch the full guides:** <https://gofr.dev/docs/advanced-guide/llm> and\n<https://gofr.dev/docs/advanced-guide/mcp>. Runnable shape: <https://github.com/gofr-dev/gofr/tree/main/examples/using-ai>.\n\nRules to keep in your head so you don't have to re-fetch on every change:\n\n1. **Register a model once** with `app.AddLLM(&llm.Client{Provider: llm.Groq, Model: \"...\"})`\n   (`gofr.dev/pkg/gofr/ai/llm`). Providers: `llm.OpenAI`, `llm.Groq`, `llm.DeepSeek`, `llm.Together`, `llm.Ollama`;\n   set `BaseURL` for any other OpenAI-compatible endpoint. Or skip the call and set `LLM_PROVIDER`, `LLM_MODEL` and\n   `LLM_API_KEY` (optional `LLM_BASE_URL`) in `configs/.env`.\n2. **Never hardcode the API key.** It comes from `LLM_API_KEY`, then the provider's own variable (`OPENAI_API_KEY`,\n   `GROQ_API_KEY`, ...).\n3. **Call the model through `c.LLM()`**: `Generate`, `Chat`, `Stream`, `Embed`. It is already traced and metered. Extra\n   models: `app.AddLLM(m, gofr.WithName(\"fast\"))`, used as `c.LLM(\"fast\")`. Not every provider supports every method;\n   handle `ai.ErrEmbedNotSupported` / `ai.ErrStreamNotSupported` as ordinary errors.\n4. **Stream tokens** by returning `response.Stream{Source: stream}` from the handler\n   (`gofr.dev/pkg/gofr/http/response`).\n5. **Expose handlers to agents with `app.EnableMCP()`.** It serves the *read-only* handlers (`GET`, `HEAD`, `OPTIONS`,\n   `QUERY`) as MCP tools. `POST`/`PUT`/`PATCH`/`DELETE` are never exposed. Hide a route with\n   `gofr.WithExcludedRoutes(\"/internal/{id}\")`.\n6. **MCP binds to loopback on `MCP_PORT` (default `8200`).** `MCP_PORT=0` turns the transport off but keeps tools\n   available in-process. A port that cannot be claimed fails startup. `8200` is also Vault's default port.\n7. **Build agent loops in your own handler** with `c.LLM().Tools()` (`List`, `Call`, `Only`). GoFr has no built-in agent\n   loop; turns, stopping conditions and memory stay in your code.\n\n```go\npackage main\n\nimport (\n    \"gofr.dev/pkg/gofr\"\n    \"gofr.dev/pkg/gofr/ai/llm\"\n)\n\nfunc main() {\n    app := gofr.New()\n\n    app.AddLLM(&llm.Client{Provider: llm.Groq, Model: \"llama-3.3-70b-versatile\"})\n    app.EnableMCP() // exposes the GET handlers below to MCP clients\n\n    app.GET(\"/products/{id}\", func(c *gofr.Context) (any, error) {\n        return map[string]any{\"id\": c.PathParam(\"id\")}, nil\n    })\n\n    app.POST(\"/summarize\", func(c *gofr.Context) (any, error) {\n        var in struct {\n            Text string `json:\"text\"`\n        }\n        if err := c.Bind(&in); err != nil {\n            return nil, err\n        }\n\n        return c.LLM().Generate(c, \"Summarize the following:\\n\"+in.Text)\n    })\n\n    app.Run()\n}\n```\n\n## Where to look (fetch only what you need)\n\nEach link is a self-contained doc page. Fetch lazily.\n\n- Quick start: <https://gofr.dev/docs/quick-start/introduction>\n- Configuration: <https://gofr.dev/docs/quick-start/configuration>\n- Routing + REST handlers: <https://gofr.dev/docs/quick-start/add-rest-handlers>\n- Context reference (the central abstraction): <https://gofr.dev/docs/references/context>\n- Configs reference (every env var): <https://gofr.dev/docs/references/configs>\n- Testing patterns + mocks: <https://gofr.dev/docs/references/testing>\n- Observability (auto-wired): <https://gofr.dev/docs/quick-start/observability>\n- Custom OTel spans: <https://gofr.dev/docs/advanced-guide/custom-spans-in-tracing>\n- Custom Prometheus metrics: <https://gofr.dev/docs/advanced-guide/publishing-custom-metrics>\n- Datasources index (MySQL, Postgres, Mongo, Redis, Cassandra, ClickHouse, etc.): <https://gofr.dev/docs/datasources/getting-started>\n- Pub/Sub (Kafka, NATS, GCP, MQTT, SQS, Azure): <https://gofr.dev/docs/advanced-guide/using-publisher-subscriber>\n- gRPC: <https://gofr.dev/docs/advanced-guide/grpc>\n- GraphQL: <https://gofr.dev/docs/advanced-guide/graphql>\n- WebSockets: <https://gofr.dev/docs/advanced-guide/websocket>\n- Cron: <https://gofr.dev/docs/advanced-guide/using-cron>\n- Service-to-service HTTP w/ circuit breaker: <https://gofr.dev/docs/advanced-guide/http-communication>\n- Auth (Basic / API key / OAuth-JWT): <https://gofr.dev/docs/advanced-guide/authentication>\n- RBAC (config-driven): <https://gofr.dev/docs/advanced-guide/rbac>\n- Migrations (SQL + NoSQL, versioned): <https://gofr.dev/docs/advanced-guide/handling-data-migrations>\n- File storage (local / S3 / GCS / Azure / FTP / SFTP): <https://gofr.dev/docs/advanced-guide/handling-file>\n- Startup hooks: <https://gofr.dev/docs/advanced-guide/startup-hooks>\n- Errors: <https://gofr.dev/docs/advanced-guide/gofr-errors>\n- Custom DB drivers: <https://gofr.dev/docs/advanced-guide/injecting-databases-drivers>\n- Calling LLMs (`app.AddLLM`, `c.LLM()`, env config, multiple models, embeddings): <https://gofr.dev/docs/advanced-guide/llm>\n- MCP server and agent loops (`app.EnableMCP`, `c.LLM().Tools()`): <https://gofr.dev/docs/advanced-guide/mcp>\n- Streaming responses (SSE / NDJSON, `response.Stream`): <https://gofr.dev/docs/advanced-guide/streaming>\n\n## Migrating to GoFr\n\nEach migration page has the full mapping table for that source framework — fetch only the one that matches:\n\n- From Gin: <https://gofr.dev/migrate/from-gin>\n- From Fiber: <https://gofr.dev/migrate/from-fiber>\n- From Echo: handler shape similar to Gin; see <https://gofr.dev/comparison/gofr-vs-echo>\n- From Chi: see <https://gofr.dev/comparison/gofr-vs-chi>\n- From Express (Node.js): <https://gofr.dev/migrate/from-express>\n- From Flask (Python): <https://gofr.dev/migrate/from-flask>\n- From Spring Boot (Java): <https://gofr.dev/migrate/from-spring-boot>\n\n## Other entry points\n\n- Examples (runnable projects): <https://github.com/gofr-dev/gofr/tree/main/examples>\n- Full docs index: <https://gofr.dev/docs>\n- Concatenated full docs (one plaintext file): <https://gofr.dev/llms-full.txt>\n- Curated link index: <https://gofr.dev/llms.txt>\n- Changelog: <https://gofr.dev/changelog>\n\n<!-- File: docs/references/configs/page.md (Tokens: ~5070 | Category: anthropic-skill) -->\n---\ndescription: \"Reference of every GoFr configuration variable, grouped by category: HTTP, gRPC, datasources, observability, auth, and more — with defaults and value formats.\"\nnextjs:\n  metadata:\n    title: \"GoFr Configuration Reference — Env Vars and Defaults\"\n    description: \"Reference of every GoFr configuration variable, grouped by category: HTTP, gRPC, datasources, observability, auth, and more — with defaults and value formats.\"\n---\n\n# GoFr Configuration Options\n\nThis document lists all the configuration options supported by the GoFr framework. The configurations are grouped by category for better organization.\n\n## App\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  APP_NAME\n-  Name of the application. It is also the `service.name` on the resource attached to exported traces and metrics; OTEL_SERVICE_NAME and a service.name= entry in OTEL_RESOURCE_ATTRIBUTES are ignored.\n-  gofr-app\n\n---\n\n-  APP_ENV\n-  Name of the environment file to use (e.g., stage.env, prod.env, or local.env).\n\n---\n\n-  APP_VERSION\n-  Application version\n-  dev\n\n---\n\n-  LOG_LEVEL\n-  Level of verbosity for application logs. Supported values are **DEBUG, INFO, NOTICE, WARN, ERROR, FATAL**\n-  INFO\n\n---\n\n-  REMOTE_LOG_URL\n-  URL to remotely change the log level\n\n---\n\n-  REMOTE_LOG_FETCH_INTERVAL\n-  Time interval (in seconds) to check for remote log level updates\n-  15\n\n---\n\n-  METRICS_PORT\n-  Port on which the application exposes the Prometheus pull endpoint. Set to 0 to disable it (e.g. push-only serverless).\n-  2121\n\n---\n\n-  METRICS_EXPORTER\n-  Enables push-based metrics export alongside the pull endpoint. Supported values: otlp, gcp. Unset (or prometheus) keeps pull-only behavior.\n\n---\n\n-  METRICS_URL\n-  Endpoint of the OTLP metrics collector/backend. host:port for gRPC, full URL for HTTP. Required when METRICS_EXPORTER is otlp (gcp defaults to telemetry.googleapis.com:443).\n\n---\n\n-  METRICS_PROTOCOL\n-  OTLP transport for pushed metrics. Supported values: grpc, http.\n-  grpc\n\n---\n\n-  METRICS_EXPORT_INTERVAL\n-  Interval (in seconds) at which metrics are pushed to the collector/backend.\n-  30\n\n---\n\n-  METRICS_TEMPORALITY\n-  OTLP temporality preference. Supported values: cumulative, delta, lowmemory. Use delta for Datadog; cumulative for Prometheus/GMP/Grafana.\n-  cumulative\n\n---\n\n-  METRICS_HEADERS\n-  Custom headers for metric export requests in comma-separated key=value format (e.g., \"dd-api-key=secret\"). Takes priority over METRICS_AUTH_KEY.\n\n---\n\n-  METRICS_AUTH_KEY\n-  Authorization header value for metric export requests. Used when METRICS_HEADERS is unset.\n\n---\n\n-  METRICS_INSECURE\n-  Disables transport security for the OTLP metrics connection. Set to false for managed backends over TLS. Ignored by the gcp exporter (always TLS).\n-  true\n\n---\n\n-  METRICS_CARDINALITY_LIMIT\n-  Per-instrument attribute-set limit, inclusive of the overflow slot: an instrument keeps up to one fewer than this many distinct label sets per collection cycle, and the remaining series collapse into a single otel.metric.overflow series (so a value of n keeps n-1 real label sets). Set 0 or negative for unlimited. When unset, the OpenTelemetry SDK default applies (2000, or OTEL_GO_X_CARDINALITY_LIMIT if set); a set value takes precedence over OTEL_GO_X_CARDINALITY_LIMIT. HTTP metrics give requests that match no route (and unknown methods) at most a quarter of this limit, capped at 500 distinct (path, method, status) label sets; past that they are recorded as `__unmatched__` / `__other__`, so scanner traffic cannot push real routes into the overflow series.\n-  2000\n\n---\n\n-  OTEL_RESOURCE_ATTRIBUTES\n-  Standard OpenTelemetry resource attributes, comma-separated key=value. Merged into the resource attached to every exported metric and span, except service.name, which comes from APP_NAME (a service.name= entry is ignored with a warning), and framework_version, which cannot be overridden. Required for the gcp exporter outside Google Cloud: its ingest rejects any point whose prometheus_target has no location (e.g. \"location=us-central1\").\n\n---\n\n-  OTEL_SERVICE_NAME\n-  Standard OpenTelemetry service name. Ignored: GoFr sets service.name on exported traces and metrics from APP_NAME, and logs a warning at startup when this is set to a different value. Tracing and metrics each log it, so with both enabled the warning appears twice, once prefixed \"traces:\" and once \"metrics:\". Set APP_NAME to rename the service.\n\n---\n\n-  HTTP_PORT\n-  Port on which the HTTP server listens\n-  8000\n\n---\n\n-  GRPC_PORT\n-  Port on which the gRPC server listens\n-  9000\n\n---\n\n-  MCP_PORT\n-  Port on which the MCP server listens, bound to loopback. Only used when `app.EnableMCP()` is called; a port that cannot be claimed fails startup. Set to `0` to keep tools available in-process while serving no MCP transport. A non-numeric or out-of-range value refuses startup. Note the default collides with Vault's — see [MCP](/docs/advanced-guide/mcp).\n-  8200\n\n---\n\n-  TRACE_EXPORTER\n-  Tracing exporter to use. Supported values: gofr, zipkin, jaeger, otlp, gcp. `gcp` exports directly to Google Cloud's Telemetry (OTLP) API using Application Default Credentials, and requires the blank import `_ \"gofr.dev/pkg/gofr/traces/exporters/gcp\"`.\n\n---\n\n-  TRACER_HOST\n-  Hostname of the tracing collector. Required if TRACE_EXPORTER is set to zipkin or jaeger.\n-  **DEPRECATED**\n\n---\n\n-  TRACER_PORT\n-  Port of the tracing collector. Required if TRACE_EXPORTER is set to zipkin or jaeger.\n-  9411\n-  **DEPRECATED**\n\n---\n\n-  TRACER_URL\n-  URL of the trace collector. Required if TRACE_EXPORTER is set to zipkin, jaeger or otlp; optional for gcp, which defaults to `telemetry.googleapis.com:443`. For zipkin, jaeger and otlp an `http://` or `https://` scheme selects the transport, and a schemeless `host:port` is governed by TRACER_INSECURE. For gcp the value must be a schemeless `host:port` — that destination is always TLS on 443, so a scheme is rejected at startup rather than interpreted.\n\n---\n\n-  TRACER_INSECURE\n-  Whether a schemeless TRACER_URL (`host:port`) is exported over plaintext. Set to `false` to use TLS with the system root CAs. Ignored when TRACER_URL carries an `http://` or `https://` scheme, which selects the transport itself. Takes precedence over the OTel standard OTEL_EXPORTER_OTLP_INSECURE / OTEL_EXPORTER_OTLP_TRACES_INSECURE. Supported for otlp, jaeger.\n-  true\n\n---\n\n-  TRACER_RATIO\n-  Refers to the proportion of traces that are exported through sampling. It is optional configuration. By default, this ratio is set to 1. A value that is not a valid number is rejected with an error log and also resolves to 1, so a typo over-samples rather than silently disabling tracing.\n\n---\n\n-  TRACER_AUTH_KEY\n-  Authorization header for trace exporter requests. Supported for zipkin, jaeger, otlp.\n\n---\n\n-  TRACER_HEADERS\n-  Custom authentication headers for trace exporter requests in comma-separated key=value format (e.g., \"X-Api-Key=secret,Authorization=Bearer token\"). Supported for zipkin, jaeger, otlp. Takes priority over TRACER_AUTH_KEY.\n\n---\n\n-  CMD_LOGS_FILE\n-  File to save the logs in case of a CMD application\n\n---\n\n-  SHUTDOWN_GRACE_PERIOD\n-  Timeout duration for server shutdown process\n-  30s\n\n---\n\n-  GOFR_TELEMETRY\n-  Enable telemetry for GoFr framework usage\n-  true\n\n---\n\n-  GOFR_ROUTER\n-  Route matcher for the HTTP server. Set to `trie` to opt into the O(path length) trie index instead of the default linear scan — see [Routing Performance](/docs/advanced-guide/routing-performance). Any other value falls back to `mux`.\n-  mux\n\n---\n\n-  GOFR_RBAC_ROUTE_CHECK\n-  What the startup check does when the RBAC config and the registered routes disagree — see [Startup Route Check](/docs/advanced-guide/rbac#startup-route-check). `warn` logs each mismatch as an error and keeps starting, `fail` logs them and stops startup with exit status 1, `off` skips the check. Any other value is logged as an error and treated as `warn`.\n-  warn\n\n---\n\n-  LOG_DISABLE_PROBES\n-  Disable log probes for health checks\n-  false\n\n---\n\n-  GRPC_ENABLE_REFLECTION\n-  Enable gRPC server reflection\n-  false\n\n---\n\n-  HEALTH_CACHE_TTL\n-  How long a health result may be served without re-checking the backends, as a duration (`5s`, `10s`, `1m`). Unset, `0` or `disabled` turns caching off, which is the default: within a TTL a recovered backend still reports DOWN and a failed one still reports UP, so it is a trade to opt into rather than inherit.\n-  disabled\n\n---\n\n-  HEALTH_CHECK_TIMEOUT\n-  Upper bound on one round of health checks, as a duration (`2s`). Backends that have not answered by then are left out of the response and the aggregate status is DEGRADED. Datasources whose health check honors its context are canceled at that deadline. Once every outstanding check has returned, the next probe checks them again. Checks that cannot be canceled keep running after the round is abandoned: the SQL, Redis and PubSub health checks take no context, and a few datasources (such as Couchbase and NATS KV) don't yet honor the one they receive. While one of those is still running, a probe reports DEGRADED with no per-dependency detail rather than starting a second round against the same unresponsive backend. Unset or `0` means the round is bounded only by each backend client's own timeout.\n-  disabled\n\n{% /table %}\n\n## HTTP\n\n{% table %}\n\n- Name\n- Description\n\n---\n\n-  REQUEST_TIMEOUT\n-  Set the request timeouts (in seconds) for HTTP server.\n\n---\n\n- CERT_FILE\n- Set the path to your PEM certificate file for the HTTPS server to establish a secure connection.\n\n--- \n\n- KEY_FILE\n- Set the path to your PEM key file for the HTTPS server to establish a secure connection.\n\n{% /table %}\n\n### CORS\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n- ACCESS_CONTROL_ALLOW_ORIGIN\n- Allowed origin(s) for cross-origin requests. Supports comma-separated values for multiple origins (e.g., `https://app.example.com,https://admin.example.com`).\n- `*`\n\n---\n\n- ACCESS_CONTROL_ALLOW_HEADERS\n- Allowed request headers for cross-origin requests.\n- Authorization, Content-Type, x-requested-with, origin, true-client-ip, X-Correlation-ID\n\n---\n\n- ACCESS_CONTROL_ALLOW_METHODS\n- Allowed HTTP methods. Automatically set from registered routes if not provided.\n\n---\n\n- ACCESS_CONTROL_ALLOW_CREDENTIALS\n- Allow credentials (cookies, HTTP authentication) in cross-origin requests.\n\n---\n\n- ACCESS_CONTROL_EXPOSE_HEADERS\n- Additional headers exposed to the client in cross-origin responses.\n\n---\n\n- ACCESS_CONTROL_MAX_AGE\n- Maximum time (in seconds) browsers can cache preflight responses.\n\n{% /table %}\n\n## Datasource\n\n### SQL\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  DB_DIALECT\n-  Database dialect. Supported values: mysql, postgres, supabase\n\n---\n\n-  DB_HOST\n-  Hostname of the database server.\n\n---\n\n-  DB_PORT\n-  Port of the database server.\n-  3306\n\n---\n\n-  DB_USER\n-  Username for the database.\n\n---\n\n-  DB_PASSWORD\n-  Password for the database.\n\n---\n\n-  DB_NAME\n-  Name of the database to use.\n\n---\n\n-  DB_MAX_IDLE_CONNECTION\n-  Number of maximum idle connection.\n-  2\n\n---\n\n-  DB_MAX_OPEN_CONNECTION\n-  Number of maximum connections which can be used with database.\n-  0 (unlimited)\n---\n\n-  DB_SSL_MODE\n-  TLS/SSL mode for database connections. Supported modes: **disable** (no TLS), **preferred** (attempts TLS, falls back to plain), **require** (enforces TLS, skips validation), **skip-verify** (enforces TLS, no certificate validation), **verify-ca** (enforces TLS, validates certificate against CA), **verify-full** (enforces TLS with full validation including hostname). Currently supported for MySQL/MariaDB and PostgreSQL.\n-  disable\n\n---\n\n- DB_TLS_CA_CERT\n- Path to CA certificate file for TLS connections. Required for **verify-ca** and **verify-full** SSL modes.\n- None\n\n---\n\n- DB_TLS_CLIENT_CERT\n- Path to client certificate file for mutual TLS authentication.\n- None\n\n---\n\n- DB_TLS_CLIENT_KEY\n- Path to client private key file for mutual TLS authentication.\n- None\n\n---\n\n- DB_REPLICA_HOSTS\n- Comma-separated list of replica database hosts. Used for read replicas.\n- None\n\n---\n\n- DB_REPLICA_PORTS\n- Comma-separated list of replica database ports. Used for read replicas.\n- None\n\n---\n\n- DB_REPLICA_USERS\n- Comma-separated list of replica database users. Used for read replicas.\n- None\n\n---\n\n- DB_REPLICA_PASSWORDS\n- Comma-separated list of replica database passwords. Used for read replicas.\n- None\n\n---\n\n- DB_REPLICA_MAX_IDLE_CONNECTIONS\n- Maximum idle connections allowed for a replica\n- 50\n\n---\n\n- DB_REPLICA_MIN_IDLE_CONNECTIONS\n- Minimum idle connections for a replica\n- 10\n\n---\n\n- DB_REPLICA_DEFAULT_IDLE_CONNECTIONS\n- Idle connections used if no primary setting is provided\n- 10\n\n---\n\n- DB_REPLICA_MAX_OPEN_CONNECTIONS\n- Maximum open connections allowed for a replica\n- 200\n\n---\n\n- DB_REPLICA_MIN_OPEN_CONNECTIONS\n- Minimum open connections for a replica\n- 50\n\n---\n\n- DB_REPLICA_DEFAULT_OPEN_CONNECTIONS\n- Open connections used if no primary setting is provided\n- 100\n\n---\n\n\n- DB_CHARSET\n- The character set for database connection\n- utf8\n\n---\n\n- SUPABASE_CONNECTION_TYPE \n- Connection type to Supabase. Supported values: direct, session, transaction \n- direct\n\n---\n\n- SUPABASE_PROJECT_REF \n- Supabase project reference ID\n\n---\n\n- SUPABASE_REGION \n- Supabase region for pooled connections\n\n---\n\n- DB_URL \n- Full PostgreSQL connection string for Supabase (alternative to separate config parameters)\n\n{% /table %}\n\n### Redis\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  REDIS_HOST\n-  Hostname of the Redis server.\n-  localhost\n\n---\n\n-  REDIS_PORT\n-  Port of the Redis server.\n-  6379\n\n---\n\n- REDIS_USER\n- Username for the Redis server (optional).\n-  \"\"\n\n---\n\n- REDIS_PASSWORD\n- Password for the Redis server (optional).\n-  \"\"\n\n---\n\n- REDIS_DB\n- Database number to use for the Redis server.\n-  0\n\n---\n\n- REDIS_TLS_ENABLED\n- Enable TLS for Redis connections.\n-  false\n\n---\n\n- REDIS_TLS_CA_CERT\n- Path to the TLS CA certificate file for Redis (or PEM-encoded string).\n-  \"\"\n\n---\n\n- REDIS_TLS_CERT\n- Path to the TLS certificate file for Redis (or PEM-encoded string).\n-  \"\"\n\n---\n\n- REDIS_TLS_KEY\n- Path to the TLS key file for Redis (or PEM-encoded string).\n-  \"\"\n\n{% /table %}\n\n**Redis PubSub Configuration:**\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n- REDIS_PUBSUB_DB\n- Redis database number to use only for Redis Pub/Sub (when `PUBSUB_BACKEND=REDIS`). Use a different DB than `REDIS_DB` when running GoFr migrations with Redis Streams mode to avoid `gofr_migrations` key-type collisions.\n- Default: `15` (highest default Redis database, 0-15)\n\n---\n\n- REDIS_PUBSUB_MODE\n- Operation mode: `pubsub` or `streams`.\n- streams\n\n---\n\n- REDIS_STREAMS_CONSUMER_GROUP\n- Consumer group name (required for streams mode).\n-  \"\"\n\n---\n\n- REDIS_STREAMS_CONSUMER_NAME\n- Unique consumer name (optional, auto-generated if empty).\n-  \"\"\n\n---\n\n- REDIS_STREAMS_BLOCK_TIMEOUT\n- Blocking duration for reading new messages using Redis `XREADGROUP`. Lower values (1s-2s) provide faster detection but increase CPU usage. Higher values (10s-30s) reduce CPU usage, ideal for batch processing.\n- 5s\n\n---\n\n- REDIS_STREAMS_PEL_RATIO\n- Ratio of PEL (pending) messages to read vs new messages (0.0-1.0). Controls balance between retry and fresh messages. 0.7 = 70% PEL, 30% new.\n- 0.7\n\n---\n\n- REDIS_STREAMS_MAXLEN\n- Maximum length of the stream (approximate). Prevents streams from growing indefinitely. Set to `0` for unlimited.\n- 0 (unlimited)\n\n{% /table %}\n\n> **Note**: When using GoFr migrations with Streams mode, keep `REDIS_DB` and `REDIS_PUBSUB_DB` separate (defaults: 0 and 15). For `REDIS_STREAMS_BLOCK_TIMEOUT`: use 1s-2s for real-time or 10s-30s for batch processing.\n\n### Pub/Sub\n\n{% table %}\n\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  PUBSUB_BACKEND\n-  Pub/Sub message broker backend wired automatically by `gofr.New()`. Accepted values: `kafka`, `google`, `mqtt`, `redis` (case-insensitive). Other backends (NATS JetStream, AWS SQS, Azure Event Hub) are wired explicitly via `app.AddPubSub(...)`.\n-  \n\n{% /table %}\n\n**Kafka**\n\n{% table %}\n\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  PUBSUB_BROKER\n-  Comma-separated list of broker addresses\n-  localhost:9092\n\n---\n\n-  PARTITION_SIZE\n-  Size of each message partition (in bytes)\n-  0\n\n---\n\n-  PUBSUB_OFFSET\n-  Offset to start consuming messages from. -1 for earliest, 0 for latest.\n-  -1\n\n---\n\n- KAFKA_BATCH_SIZE\n- Number of messages to batch before sending to Kafka\n- 1\n\n---\n\n- KAFKA_BATCH_BYTES\n- Number of bytes to batch before sending to Kafka\n- 1048576\n\n---\n\n- KAFKA_BATCH_TIMEOUT\n- Time to wait before sending a batch to Kafka\n- 100ms\n\n---\n\n-  CONSUMER_ID\n-  Unique identifier for this consumer\n-  gofr-consumer\n\n---\n\n---\n\n- KAFKA_SECURITY_PROTOCOL\n- Security protocol used to communicate with Kafka (e.g., PLAINTEXT, SSL, SASL_PLAINTEXT, SASL_SSL)\n- PLAINTEXT\n\n---\n\n\n- KAFKA_SASL_MECHANISM\n- SASL mechanism for authentication (e.g. PLAIN, SCRAM-SHA-256, SCRAM-SHA-512)\n- None\n\n---\n\n- KAFKA_SASL_USERNAME\n- Username for SASL authentication\n- None\n\n---\n\n- KAFKA_SASL_PASSWORD\n- Password for SASL authentication\n- None\n\n---\n\n- KAFKA_TLS_CERT_FILE\n- Path to the TLS certificate file\n- None\n\n---\n\n- KAFKA_TLS_KEY_FILE\n- Path to the TLS key file\n- None\n\n---\n\n- KAFKA_TLS_CA_CERT_FILE\n- Path to the TLS CA certificate file\n- None\n\n---\n\n- KAFKA_TLS_INSECURE_SKIP_VERIFY\n- Skip TLS certificate verification\n- false\n\n{% /table %}\n\n**Google**\n\n{% table %}\n\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  GOOGLE_PROJECT_ID\n-  ID of the Google Cloud project. Required for Google Pub/Sub.\n-  None\n\n---\n\n-  GOOGLE_SUBSCRIPTION_NAME\n-  Name of the Google Pub/Sub subscription. Required for Google Pub/Sub.\n-  None\n\n---\n\n-  GOOGLE_MAX_OUTSTANDING_MESSAGES\n-  Max messages the client holds waiting for delivery to the handler, per subscribed topic (the memory/goroutine bound, not the handler concurrency). 0 uses the default; a negative value means no limit.\n-  1000\n\n---\n\n-  GOOGLE_MAX_OUTSTANDING_BYTES\n-  Max total size (bytes) of messages held waiting for delivery, per subscribed topic. 0 uses the default; a negative value means no limit.\n-  1000000000\n\n---\n\n-  GOOGLE_NUM_GOROUTINES\n-  Number of StreamingPull streams opened by the subscriber, per subscribed topic. It is the stream count, not handler concurrency, and does not raise throughput under GoFr's one-message-at-a-time delivery. 0 or a negative value uses the default.\n-  10\n\n{% /table %}\n\n**MQTT**\n\n{% table %}\n\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  MQTT_PORT\n-  Port of the MQTT broker\n-  1883\n\n---\n\n-  MQTT_MESSAGE_ORDER\n-  Enable guaranteed message order\n-  false\n\n---\n\n-  MQTT_PROTOCOL\n-  Communication protocol. Supported values: tcp, ssl.\n-  tcp\n\n---\n\n-  MQTT_HOST\n-  Hostname of the MQTT broker\n-  localhost\n\n---\n\n-  MQTT_USER\n-  Username for the MQTT broker\n\n---\n\n-  MQTT_PASSWORD\n-  Password for the MQTT broker\n\n---\n\n-  MQTT_CLIENT_ID_SUFFIX\n-  Suffix appended to the client ID\n\n---\n\n-  MQTT_QOS\n-  Quality of Service Level\n\n---\n\n-  MQTT_KEEP_ALIVE\n-  Sends regular messages to check the link is active. May not work as expected if handling func is blocking execution\n\n- MQTT_RETRIEVE_RETAINED\n- Retrieve retained messages on subscription\n\n{% /table %}\n\n**NATS JetStream**\n\n{% table %}\n\n- Name\n- Description\n- Default Value\n\n---\n\n-  NATS_SERVER\n-  URL of the NATS server. The NATS driver is wired explicitly via `app.AddPubSub(...)`; this row is a convention only — the actual env-var name is whatever you read from `app.Config.Get(...)` and pass into `nats.Config.Server`.\n-  nats://localhost:4222\n\n---\n\n-  NATS_CREDS_FILE\n-  File containing the NATS credentials\n- creds.json\n\n{% /table %}\n\n\n\n## Related production guides\n\n- **12-Factor Configuration**: [Env-driven config, secrets, and environment parity](/docs/guides/twelve-factor-config) — apply 12-factor methodology to the configs documented above.\n\n<!-- File: docs/references/context/page.md (Tokens: ~1395 | Category: anthropic-skill) -->\n---\ndescription: \"GoFr's ctx is injected into every handler. It carries request data plus the container of dependencies — DBs, logger, HTTP clients, and metrics — for the cycle.\"\nnextjs:\n  metadata:\n    title: \"GoFr Context Reference — Request Container API\"\n    description: \"GoFr's ctx is injected into every handler. It carries request data plus the container of dependencies — DBs, logger, HTTP clients, and metrics — for the cycle.\"\n---\n\n# GoFr Context\n\nGoFr context is an object injected by the GoFr handler. It contains all the request-specific data, for each\nrequest-response cycle a new context is created. The request can be either an HTTP request, gRPC call or\na message from Pub-Sub.\nGoFr Context also embeds the **_container_** which maintains all the dependencies like databases, logger, HTTP service clients,\nmetrics manager, etc. This reduces the complexity of the application as users don't have to maintain and keep track of\nall the dependencies by themselves.\n\nGoFr context is an extension of the Go context, providing a wrapper around the request and response providing\nuser access to dependencies.\n\n# Usage\n\n## Reading HTTP requests\n\n`ctx.Request` can be used to access the underlying request which provides the following methods to access different\nparts of the request.\n\n- `Context()` - to access the context associated with the incoming request\n\n```go\nctx.Request.Context()\n```\n\n- `Param(string)` - to access the query parameters present in the request, it returns the value of the key provided\n\n```go\n// Example: Request is /configs?key1=value1&key2=value2\nvalue := ctx.Request.Param(\"key1\")\n// value = \"value1\"\n```\n\n- `PathParam(string)` - to retrieve the path parameters\n  ```go\n  // Consider the path to be /employee/{id}\n  id := ctx.Request.PathParam(\"id\")\n  ```\n- `Bind(any)` - to access a decoded format of the request body, the body is mapped to the interface provided\n\n```go\n// incoming request body is\n// {\n//    \"name\" : \"trident\",\n//    \"category\" : \"snacks\"\n// }\n\ntype product struct{\n  Name string `json:\"name\"`\n  Category string `json:\"category\"`\n}\n\nvar p product\nctx.Bind(&p)\n// the Bind() method will map the incoming request to variable p\n```\n\n> **Pass a pointer.** `Bind` needs the address of your variable (`&p`) so it can write into it.\n> For an HTTP request, passing a value (`ctx.Bind(p)`) returns an error rather than silently\n> leaving your variable untouched. Always check the returned error:\n>\n> ```go\n> if err := ctx.Bind(&p); err != nil {\n>     return nil, err\n> }\n> ```\n\nThe `Content-Type` header selects how the body is decoded. It is matched case-insensitively and\nany parameters are ignored, so `application/json`, `Application/JSON` and\n`application/json; charset=utf-8` are all treated the same.\n\nIf a request carries a body whose `Content-Type` GoFr has no decoder for — `text/plain`,\n`application/xml`, or no header at all — `Bind` is a **no-op**: it returns no error and leaves\nyour target zeroed, and the body is discarded. Check the `Content-Type` your clients actually\nsend. `fetch(url, {method: \"POST\", body: str})` with no headers sends `text/plain`, not JSON, so\na request that looks correct can bind nothing.\n\n- `Binding multipart-form data / urlencoded form data `\n  - To bind multipart-form data or url-encoded form, we can use the Bind method similarly. The struct fields should be tagged appropriately\n    to map the form fields to the struct fields. The supported content types are `multipart/form-data` and `application/x-www-form-urlencoded`\n\n```go\ntype Data struct {\n\tName string `form:\"name\"`\n\n\tCompressed file.Zip `file:\"upload\"`\n\n\tFileHeader *multipart.FileHeader `file:\"file_upload\"`\n}\n```\n\n  - The `form` tag is used to bind non-file fields.\n  - The `file` tag is used to bind file fields. If the tag is not present, the field name is used as the key.\n\n\n- `HostName()` - to access the host name for the incoming request\n\n```go\n// for example if request is made from xyz.com\n  host := ctx.Request.HostName()\n  // the host would be http://xyz.com\n  // Note: the protocol if not provided in the headers will be set to http by default\n```\n\n- `Params(string)` - to access all query parameters for a given key returning slice of strings.\n\n```go\n// Example: Request is /search?category=books,electronics&category=tech\nvalues := ctx.Request.Params(\"category\")\n// values = []string{\"books\", \"electronics\", \"tech\"}\n```\n\n\n## Accessing Authentication Information\n\nGoFr provides a helper method to access authentication details from the context.\nThese values are populated when the respective authentication middleware is enabled (see [HTTP Auth Middleware](https://github.com/gofr-dev/gofr/blob/0845d19181d2cc55e12c557fc9ad51adb4ab44fd/examples/using-http-auth-middleware/ReadMe.md) section).\n\n```go\ninfo := ctx.GetAuthInfo()\n```\n\n### Methods\n\n* **`GetClaims()`** – Returns the JWT claims containing standard fields such as:\n\n  * `Issuer` – identifies who issued the token.\n  * `Subject` – identifies the principal that is the subject of the token.\n  * `Audience` – identifies the intended recipients of the token.\n  * `NotBefore` – time before which the token is not valid.\n  * `IssuedAt` – time at which the token was issued.\n  * `ExpirationTime` – time after which the token expires.\n\n  **Requires:** OAuth middleware (`EnableOAuth`)\n\n* **`GetUsername()`** – Returns the authenticated username when using Basic Authentication.\n\n  **Requires:** Basic Auth middleware (`EnableBasicAuthWithValidator`)\n\n* **`GetAPIKey()`** – Returns the API key used for authentication.\n\n  **Requires:** API Key middleware (`EnableAPIKeyAuthWithValidator`)\n\n> Note: These values will be available only if the respective authentication middleware is enabled in the application.\n\n\n## Accessing dependencies\n\nGoFr context embeds the container object which provides access to\nall the injected dependencies by the users. Users can access the fields and methods provided\nby the **_container_**.\n\n<!-- File: docs/references/gofrcli/init/page.md (Tokens: ~222 | Category: anthropic-skill) -->\n---\ndescription: \"Initialize a new GoFr project with the standard layout and a Hello World starter program using the gofr init command.\"\nnextjs:\n  metadata:\n    title: \"gofr init — Initialize a New GoFr Project\"\n    description: \"Initialize a new GoFr project with the standard layout and a Hello World starter program using the gofr init command.\"\n---\n\n# gofr init\n\nThe init command initializes a new GoFr project. It sets up the foundational structure for the project and generates a basic \"Hello World!\" program as a starting point. This allows developers to quickly dive into building their application with a ready-made structure.\n\n## Command Usage\n```bash\n  gofr init\n```\n\n---\n\n## See also\n\n- [GoFr CLI overview](/docs/references/gofrcli)\n- [`gofr migrate`](/docs/references/gofrcli/migrate)\n- [`gofr wrap grpc`](/docs/references/gofrcli/wrap-grpc)\n- [`gofr store`](/docs/references/gofrcli/store)\n\n<!-- File: docs/references/gofrcli/migrate/page.md (Tokens: ~534 | Category: anthropic-skill) -->\n---\ndescription: \"Generate timestamped database migration templates with an auto-maintained registry using the gofr migrate create command.\"\nnextjs:\n  metadata:\n    title: \"gofr migrate create — Generate Database Migration Templates\"\n    description: \"Generate timestamped database migration templates with an auto-maintained registry using the gofr migrate create command.\"\n---\n\n# gofr migrate create\n\nThe migrate create command generates a migration template file with pre-defined structure in your migrations directory.\nThis boilerplate code helps you maintain consistent patterns when writing database schema modifications across your project.\n\n\n## Command Usage\n```bash\n  gofr migrate create -name=<migration-name>\n```\n\n## Example Usage\n\n```bash\ngofr migrate create -name=create_employee_table\n```\nThis command generates a migration directory which has the below files:\n\n1. A new migration file with timestamp prefix (e.g., `20250127152047_create_employee_table.go`) containing:\n```go\npackage migrations\n\nimport (\n  \"gofr.dev/pkg/gofr/migration\"\n)\n\nfunc create_employee_table() migration.Migrate {\n  return migration.Migrate{\n    UP: func(d migration.Datasource) error {\n      // write your migrations here\n      return nil\n    },\n  }\n}\n```\n2. An auto-generated all.go file that maintains a registry of all migrations:\n```go\n// This is auto-generated file using 'gofr migrate' tool. DO NOT EDIT.\npackage migrations\n\nimport (\n  \"gofr.dev/pkg/gofr/migration\"\n)\n\nfunc All() map[int64]migration.Migrate {\n  return map[int64]migration.Migrate {\n    20250127152047: create_employee_table(),\n  }\n}\n```\n\n> **💡 Best Practice:** Learn about [organizing migrations by feature](/docs/advanced-guide/handling-data-migrations#organizing-migrations-by-feature) to avoid creating one migration per table or operation.\n\nFor detailed instructions on handling database migrations, see the [handling-data-migrations documentation](/docs/advanced-guide/handling-data-migrations)\nFor more examples, see the [using-migrations](https://github.com/gofr-dev/gofr/tree/main/examples/using-migrations)\n\n---\n\n## See also\n\n- [GoFr CLI overview](/docs/references/gofrcli)\n- [`gofr init`](/docs/references/gofrcli/init)\n- [`gofr wrap grpc`](/docs/references/gofrcli/wrap-grpc)\n- [`gofr store`](/docs/references/gofrcli/store)\n\n<!-- File: docs/references/gofrcli/page.md (Tokens: ~466 | Category: anthropic-skill) -->\n---\ndescription: \"Use the GoFr CLI to scaffold projects, generate boilerplate, and run framework-aware tasks. Speeds up repetitive work and keeps services consistent.\"\nnextjs:\n  metadata:\n    title: \"GoFr CLI Reference — Project Scaffolding and Tooling\"\n    description: \"Use the GoFr CLI to scaffold projects, generate boilerplate, and run framework-aware tasks. Speeds up repetitive work and keeps services consistent.\"\n---\n\n# GoFR Command Line Interface\n\nManaging repetitive tasks and maintaining consistency across large-scale applications is challenging!\n\n**GoFr CLI provides the following:**\n\n* All-in-one command-line tool designed specifically for GoFr applications\n* Simplifies **database migrations** management\n* **Store Layer Generator** for type-safe data access code from YAML configurations\n* Abstracts **tracing**, **metrics** and structured **logging** for GoFr's gRPC server/client\n* Enforces standard **GoFr conventions** in new projects\n\n## Prerequisites\n\n- Go 1.25 or above. To check Go version use the following command:\n```bash\n  go version\n```\n\n## **Installation**\nTo get started with GoFr CLI, use the below commands\n\n```bash\n  go install gofr.dev/cli/gofr@latest\n```\n\nTo check the installation:\n```bash\n  gofr version\n```\n---\n\n## Usage\n\nThe CLI can be run directly from the terminal after installation. Here’s the general syntax:\n\n```bash\n  gofr <subcommand> [flags]=[arguments]\n```\n---\n\n## Commands\n\nThe CLI groups its functionality into four commands. See each subpage for full reference:\n\n- [`gofr init`](/docs/references/gofrcli/init) — initialize a new GoFr project with the standard layout.\n- [`gofr migrate`](/docs/references/gofrcli/migrate) — create database migration templates with timestamped filenames and an auto-generated registry.\n- [`gofr wrap grpc`](/docs/references/gofrcli/wrap-grpc) — generate gRPC server/client wrappers with built-in tracing, metrics, and logging.\n- [`gofr store`](/docs/references/gofrcli/store) — generate a type-safe data-access layer from YAML schema definitions.\n\n<!-- File: docs/references/gofrcli/store/page.md (Tokens: ~2669 | Category: anthropic-skill) -->\n---\ndescription: \"Generate a type-safe data-access layer from YAML schema definitions using the gofr store command, with built-in observability and registry support.\"\nnextjs:\n  metadata:\n    title: \"gofr store — Generate Type-Safe Data-Access Layers from YAML\"\n    description: \"Generate a type-safe data-access layer from YAML schema definitions using the gofr store command, with built-in observability and registry support.\"\n---\n\n# gofr store\n\n> **Available since:** `gofr-cli` **v0.8.1**\n\nThe `gofr store` command is a code generator that creates type-safe data access layers from YAML configuration files. It eliminates boilerplate code while maintaining GoFr's best practices for observability and context management.\n\n## **Features**\n\n* **YAML-Driven Configuration**: Define your data models and queries in a simple, declarative format.\n* **Type-Safe Code Generation**: Generates Go interfaces and implementation boilerplates.\n* **GoFr Context Integration**: Generated methods work with `*gofr.Context` for built-in observability.\n* **Multiple Stores**: Define all stores in a single YAML file — each gets its own directory.\n* **Store Registry**: Centralized factory management of all generated stores via `stores/all.go`.\n\n## **Commands**\n\n### **Initialize Store Configuration**\n\nCreate a new store directory and a `store.yaml` configuration template. **The `-name` flag is required.**\n\n```bash\ngofr store init -name=<store-name>\n```\n\n**Example:**\n```bash\ngofr store init -name=user\n```\n\nThis creates the following structure:\n- `stores/store.yaml` — Configuration file template (shared across all stores).\n- `stores/all.go` — Store registry factory (auto-generated, DO NOT EDIT).\n- `stores/user/interface.go` — Initial interface stub (DO NOT EDIT — regenerated by `generate`).\n- `stores/user/user.go` — Initial implementation stub (editable — add your SQL logic here).\n\n### **Generate Store Code**\n\nGenerate or update Go code from your store configuration file.\n\n```bash\ngofr store generate\n```\n\n> **💡 Note:** By default, this command looks for the configuration at **`stores/store.yaml`**. To use a different path, use the `-config` flag:\n> ```bash\n> gofr store generate -config=path/to/store.yaml\n> ```\n\n---\n\n## **Quick Start Example**\n\n**Step 1: Initialize Configuration**\n```bash\ngofr store init -name=user\n```\n\n**Step 2: Define Your Store in `stores/store.yaml`**\n```yaml\nversion: \"1.0\"\n\nstores:\n  - name: \"user\"\n    package: \"user\"\n    output_dir: \"stores/user\"\n    interface: \"UserStore\"\n    implementation: \"userStore\"\n    queries:\n      - name: \"GetUserByID\"\n        sql: \"SELECT id, name, email FROM users WHERE id = ?\"\n        type: \"select\"\n        model: \"User\"\n        returns: \"single\"\n        params:\n          - name: \"id\"\n            type: \"int64\"\n        description: \"Retrieves a user by their ID\"\n\n      - name: \"GetAllUsers\"\n        sql: \"SELECT id, name, email FROM users\"\n        type: \"select\"\n        model: \"User\"\n        returns: \"multiple\"\n        description: \"Retrieves all users\"\n\nmodels:\n  - name: \"User\"\n    fields:\n      - name: \"ID\"\n        type: \"int64\"\n        tag: 'db:\"id\" json:\"id\"'\n      - name: \"Name\"\n        type: \"string\"\n        tag: 'db:\"name\" json:\"name\"'\n      - name: \"Email\"\n        type: \"string\"\n        tag: 'db:\"email\" json:\"email\"'\n```\n\n**Step 3: Generate Store Code**\n```bash\ngofr store generate\n```\n\nThis generates:\n```text\nstores/\n├── store.yaml          # Central Configuration\n├── all.go              # Store registry factory (auto-generated)\n└── user/\n    ├── interface.go    # UserStore interface definition\n    ├── userStore.go    # userStore implementation boilerplate\n    └── user.go         # User model struct\n```\n\n**Step 4: Use in Your Application**\n```go\npackage main\n\nimport (\n    \"gofr.dev/pkg/gofr\"\n    \"your-project/stores/user\"\n)\n\nfunc main() {\n    app := gofr.New()\n\n    userStore := user.NewUserStore()\n\n    app.GET(\"/users/{id}\", func(ctx *gofr.Context) (interface{}, error) {\n        id, _ := strconv.ParseInt(ctx.PathParam(\"id\"), 10, 64)\n        return userStore.GetUserByID(ctx, id)\n    })\n\n    app.GET(\"/users\", func(ctx *gofr.Context) (interface{}, error) {\n        return userStore.GetAllUsers(ctx)\n    })\n\n    app.Run()\n}\n```\n\n---\n\n## **Multiple Stores in One File**\n\nYou can define all stores in a single YAML file. Each store gets its own output directory and all are registered into the same `stores/all.go` registry.\n\n```yaml\nversion: \"1.0\"\n\nstores:\n  - name: \"user\"\n    package: \"user\"\n    output_dir: \"stores/user\"\n    interface: \"UserStore\"\n    implementation: \"userStore\"\n    queries: [...]\n\n  - name: \"product\"\n    package: \"product\"\n    output_dir: \"stores/product\"\n    interface: \"ProductStore\"\n    implementation: \"productStore\"\n    queries: [...]\n\nmodels:\n  - name: \"User\"\n    fields: [...]\n  - name: \"Product\"\n    fields: [...]\n```\n\n**Generated structure:**\n```text\nstores/\n├── all.go\n├── user/\n│   ├── interface.go\n│   ├── userStore.go\n│   └── user.go\n└── product/\n    ├── interface.go\n    ├── productStore.go\n    └── product.go\n```\n\n**Using the registry with multiple stores:**\n```go\nimport (\n\"your-project/stores\"\n\"your-project/stores/user\"\n\"your-project/stores/product\"\n)\n\n// stores.GetStore returns a factory-created instance\nuserStore    := stores.GetStore(\"user\").(user.UserStore)\nproductStore := stores.GetStore(\"product\").(product.ProductStore)\n```\n\n> **💡 Note:** `stores.All()` returns a `map[string]func() any` — a map of **factory functions**, not active instances. `stores.GetStore(name)` calls the factory for you and returns the instance.\n\n---\n\n## **Configuration Reference**\n\n### **Store Configuration**\n\n| Field | Description | Required |\n|-------|-------------|----------|\n| `name` | Store identifier used in the registry key. | **Yes** |\n| `package` | Go package name for generated code. | **Yes** |\n| `output_dir` | Directory path where files will be generated. | Optional (defaults to `stores/<name>`) |\n| `interface` | Interface name — **recommended: `<Name>Store`** (e.g., `UserStore`). | Optional (defaults to `<Name>Store`) |\n| `implementation` | Private struct name for the implementation (e.g., `userStore`). | Optional (defaults to `<name>Store`) |\n| `queries` | List of database queries. | Optional |\n\n> **⚠️ Naming Convention:** The registry (`stores/all.go`) uses a hardcoded `<Name>Store` pattern when generating constructor calls (e.g., `NewUserStore()`). Always name your interface as `<Name>Store` to avoid compilation errors.\n\n### **Query Types**\n\n* **`select`** — SELECT queries.\n* **`insert`** — INSERT queries.\n* **`update`** — UPDATE queries.\n* **`delete`** — DELETE queries.\n\n### **Return Types**\n\n* **`single`** — Returns `(Model, error)`.\n* **`multiple`** — Returns `([]Model, error)`.\n* **`count`** — Returns `(int64, error)`.\n* **`custom`** — Returns `(any, error)`.\n\n### **Query Parameters**\n\n```yaml\nparams:\n  - name: \"id\"\n    type: \"int64\"\n  - name: \"email\"\n    type: \"string\"\n```\n\nSupported parameter types include all Go primitive types, `time.Time`, and pointer types (e.g., `*int64`).\n\n---\n\n## **Model Generation**\n\n### **Generate New Models**\n\n```yaml\nmodels:\n  - name: \"User\"\n    fields:\n      - name: \"ID\"\n        type: \"int64\"\n        tag: 'db:\"id\" json:\"id\"'\n      - name: \"Name\"\n        type: \"string\"\n        tag: 'db:\"name\" json:\"name\"'\n      - name: \"CreatedAt\"\n        type: \"time.Time\"\n        tag: 'db:\"created_at\" json:\"created_at\"'\n```\n\nThis generates:\n```go\ntype User struct {\nID        int64     `db:\"id\" json:\"id\"`\nName      string    `db:\"name\" json:\"name\"`\nCreatedAt time.Time `db:\"created_at\" json:\"created_at\"`\n}\n\nfunc (User) TableName() string {\nreturn \"user\"\n}\n```\n\n### **Reference Existing Models**\n\nIf you already have models defined elsewhere:\n\n```yaml\nmodels:\n  - name: \"User\"\n    path: \"../models/user.go\"\n    package: \"your-project/models\"\n```\n\n---\n\n## **Generated Code Structure**\n\n### **Interface (`interface.go`)**\n\n```go\n// Code generated by gofr.dev/cli/gofr. DO NOT EDIT.\npackage user\n\nimport \"gofr.dev/pkg/gofr\"\n\ntype UserStore interface {\n  GetUserByID(ctx *gofr.Context, id int64) (User, error)\n  GetAllUsers(ctx *gofr.Context) ([]User, error)\n}\n```\n\n### **Implementation (`userStore.go`)**\n\n```go\n// Code generated by gofr.dev/cli/gofr. DO NOT EDIT.\npackage user\n\ntype userStore struct{}\n\nfunc NewUserStore() UserStore {\n   return &userStore{}\n}\n\nfunc (s *userStore) GetUserByID(ctx *gofr.Context, id int64) (User, error) {\n   // TODO: Implement using ctx.SQL()\n   var result User\n   // err := ctx.SQL().QueryRowContext(ctx, sql, id).Scan(&result.ID, ...)\n   return result, nil\n}\n\nfunc (s *userStore) GetAllUsers(ctx *gofr.Context) ([]User, error) {\n   // TODO: Implement using ctx.SQL()\n   return []User{}, nil\n}\n```\n\n---\n\n## **Best Practices**\n\n1. **Implement the TODOs**: The generator creates method **signatures and boilerplate only**. You must fill in the `// TODO: Implement` sections with actual SQL execution using `ctx.SQL()` methods.\n2. **Use `<Name>Store` Interface Names**: The registry assumes this convention. E.g., `interface: \"UserStore\"` results in the constructor `NewUserStore()` and type assertion `.(user.UserStore)`.\n3. **One YAML, Many Stores**: Define all your stores in a single `store.yaml` to keep your data access layer centrally configured.\n4. **Know Which Files Are Auto-Generated**: Only `interface.go` and `all.go` are marked `DO NOT EDIT` and are overwritten on every `gofr store generate`. The implementation stub (`<name>.go`) created by `gofr store init` is editable — this is where you add your SQL logic. The `userStore.go` generated by `gofr store generate` is also editable boilerplate.\n5. **Version Control**: Always commit your `store.yaml`. Re-run `gofr store generate` after any configuration change to sync the generated interfaces.\n\n---\n\n## **Complete Example**\n\nFor a complete working example of the store generator, see the [store example](https://github.com/gofr-dev/gofr-cli/tree/main/store/example.yaml) in the gofr-cli repository.\n\nFor detailed configuration options and advanced usage, refer to the [Store Generator README](https://github.com/gofr-dev/gofr-cli/blob/main/store/README.md).\n\n---\n\n## See also\n\n- [GoFr CLI overview](/docs/references/gofrcli)\n- [`gofr init`](/docs/references/gofrcli/init)\n- [`gofr migrate`](/docs/references/gofrcli/migrate)\n- [`gofr wrap grpc`](/docs/references/gofrcli/wrap-grpc)\n\n<!-- File: docs/references/gofrcli/wrap-grpc/page.md (Tokens: ~949 | Category: anthropic-skill) -->\n---\ndescription: \"Generate gRPC server and client wrappers with built-in tracing, metrics, and logging using the gofr wrap grpc command.\"\nnextjs:\n  metadata:\n    title: \"gofr wrap grpc — Generate gRPC Server/Client Wrappers\"\n    description: \"Generate gRPC server and client wrappers with built-in tracing, metrics, and logging using the gofr wrap grpc command.\"\n---\n\n# gofr wrap grpc\n\n* The gofr wrap grpc command streamlines gRPC integration in a GoFr project by generating GoFr's context-aware structures.\n* It simplifies setting up gRPC handlers with minimal steps, and accessing datasources, adding tracing as well as custom metrics. Based on the proto file it creates the handler/client with GoFr's context.\n  For detailed instructions on using grpc with GoFr see the [gRPC documentation](/docs/advanced-guide/grpc)\n\n## Command Usage\n**gRPC Server**\n```bash\n  gofr wrap grpc server --proto=<path_to_the_proto_file>\n```\n## Generated Files\n**Server**\n- ```{serviceName}_gofr.go (auto-generated; do not modify)```\n- ```{serviceName}_server.go (example structure below)```\n\n## Example Usage\n**gRPC Server**\n\nThe command generates a server implementation template similar to this:\n```go\npackage server\n\nimport (\n   \"gofr.dev/pkg/gofr\"\n)\n\n// Register the gRPC service in your app using the following code in your main.go:\n//\n// service.Register{ServiceName}ServerWithGofr(app, &server.{ServiceName}Server{})\n//\n// {ServiceName}Server defines the gRPC server implementation.\n// Customize the struct with required dependencies and fields as needed.\ntype {ServiceName}Server struct {\n}\n\n// Example method (actual methods will depend on your proto file)\nfunc (s *MyServiceServer) MethodName(ctx *gofr.Context) (any, error) {\n   // Replace with actual logic if needed\n   return &ServiceResponse{\n   }, nil\n}\n```\nFor detailed instruction on setting up a gRPC server with GoFr see the [gRPC Server Documentation](https://gofr.dev/docs/advanced-guide/grpc#generating-g-rpc-server-handler-template-using)\n\n**gRPC Client**\n```bash\n  gofr wrap grpc client --proto=<path_to_the_proto_file>\n```\n\n**Client**\n- ```{serviceName}_client.go (example structure below)```\n\n\n## Example Usage:\nAssuming the service is named hello, after generating the hello_client.go file, you can seamlessly register and access the gRPC service using the following steps:\n\n```go\ntype GreetHandler struct {\n\thelloGRPCClient client.HelloGoFrClient\n}\n\nfunc NewGreetHandler(helloClient client.HelloGoFrClient) *GreetHandler {\n    return &GreetHandler{\n        helloGRPCClient: helloClient,\n    }\n}\n\nfunc (g GreetHandler) Hello(ctx *gofr.Context) (any, error) {\n    userName := ctx.Param(\"name\")\n    helloResponse, err := g.helloGRPCClient.SayHello(ctx, &client.HelloRequest{Name: userName})\n    if err != nil {\n        return nil, err\n    }\n\n    return helloResponse, nil\n}\n\nfunc main() {\n    app := gofr.New()\n\n// Create a gRPC client for the Hello service\n    helloGRPCClient, err := client.NewHelloGoFrClient(app.Config.Get(\"GRPC_SERVER_HOST\"), app.Metrics())\n    if err != nil {\n\t\tapp.Logger().Errorf(\"Failed to create Hello gRPC client: %v\", err)\n    return\n}\n\n    greetHandler := NewGreetHandler(helloGRPCClient)\n\n    // Register HTTP endpoint for Hello service\n    app.GET(\"/hello\", greetHandler.Hello)\n\n    // Run the application\n    app.Run()\n}\n```\nFor detailed instruction on setting up a gRPC server with GoFr see the [gRPC Client Documentation](https://gofr.dev/docs/advanced-guide/grpc#generating-tracing-enabled-g-rpc-client-using)\nFor more examples refer [gRPC Examples](https://github.com/gofr-dev/gofr/tree/main/examples/grpc)\n\n---\n\n## See also\n\n- [GoFr CLI overview](/docs/references/gofrcli)\n- [`gofr init`](/docs/references/gofrcli/init)\n- [`gofr migrate`](/docs/references/gofrcli/migrate)\n- [`gofr store`](/docs/references/gofrcli/store)\n\n<!-- File: docs/references/testing/page.md (Tokens: ~3914 | Category: anthropic-skill) -->\n---\ndescription: \"Write unit and integration tests for GoFr REST APIs. Mock the container's dependencies and assert handler responses, status codes, and headers reliably.\"\nnextjs:\n  metadata:\n    title: \"Testing GoFr REST APIs — Handlers, Mocks, Assertions\"\n    description: \"Write unit and integration tests for GoFr REST APIs. Mock the container's dependencies and assert handler responses, status codes, and headers reliably.\"\n---\n\n# Testing REST APIs with GoFr\n\nTesting REST APIs ensures that your endpoints function correctly under various conditions. This guide demonstrates how to write tests for GoFr-based REST APIs.\n\n## Mocking Databases in GoFr\n\nMocking databases allows for isolated testing by simulating various scenarios. GoFr's built-in mock container supports, not only SQL databases, but also extends to other data stores, including Redis, Cassandra, Key-Value stores, MongoDB, and ClickHouse.\n\n### Mocking `Select` Queries\n\n`Select` reads rows into a destination, so its mock takes the response you want written into that destination. Pass a pointer of the destination's type to `ExpectSelect`, along with the exact query text and arguments your handler uses, then set the rows with `ReturnsResponse`:\n\n```go\nvar users []User\n\nmock.SQL.ExpectSelect(ctx, &users, \"SELECT id, name FROM users WHERE status = ?\", \"active\").\n\tReturnsResponse([]User{{ID: 1, Name: \"John\"}})\n```\n\nWhen the handler calls `ctx.SQL.Select(ctx, &dest, \"SELECT id, name FROM users WHERE status = ?\", \"active\")`, `dest` is set to the response.\n\nThe query text must match exactly, and the arguments must have the same count, values and types (compared with `reflect.DeepEqual`, so slices such as `IN` lists are supported). If the query or arguments do not match, the destination is left untouched and the test fails with a message showing the expected and actual values.\n\n## Example of Unit Testing a REST API Using GoFr\n\nBelow is an example of how to test, say the `Add` method of a handler that interacts with a SQL database.\n\nHere’s an `Add` function for adding a book to the database using GoFr:\n\n```go\n// main.go\npackage main\n\nimport (\n\t\"gofr.dev/pkg/gofr\"\n\t\"gofr.dev/pkg/gofr/http\"\n)\n\ntype Book struct {\n\tId    int    `json:\"id\"`\n\tISBN  int    `json:\"isbn\"`\n\tTitle string `json:\"title\"`\n}\n\nfunc Add(ctx *gofr.Context) (any, error) {\n\tvar book Book\n\n\tif err := ctx.Bind(&book); err != nil {\n\t\tctx.Logger.Errorf(\"error in binding: %v\", err)\n\t\treturn nil, http.ErrorInvalidParam{Params: []string{\"body\"}}\n\t}\n\n\t// we assume the `id` column in the database is set to auto-increment.\n\tres, err := ctx.SQL.ExecContext(ctx, `INSERT INTO books (title, isbn) VALUES (?, ?)`, book.Title, book.ISBN)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tid, err := res.LastInsertId()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn id, nil\n}\n\nfunc main() {\n\t// initialize gofr object\n\tapp := gofr.New()\n\n\tapp.POST(\"/book\", Add)\n\n\t// Run the application\n\tapp.Run()\n}\n\n```\n\nHere’s how to write tests using GoFr:\n\n```go\n// main_test.go\npackage main\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"database/sql\"\n\t\"errors\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"gofr.dev/pkg/gofr\"\n\t\"gofr.dev/pkg/gofr/container\"\n\tgofrHttp \"gofr.dev/pkg/gofr/http\"\n)\n\nfunc TestAdd(t *testing.T) {\n\ttype gofrResponse struct {\n\t\tresult any\n\t\terr    error\n\t}\n\n\t// NewMockContainer provides mock implementations for various databases including:\n\t// Redis, SQL, ClickHouse, Cassandra, MongoDB, and KVStore.\n\t// These mock can be used to define database expectations in unit tests,\n\t// similar to the SQL example demonstrated here.\n\tmockContainer, mock := container.NewMockContainer(t)\n\n\tctx := &gofr.Context{\n\t\tContext:   context.Background(),\n\t\tRequest:   nil,\n\t\tContainer: mockContainer,\n\t}\n\n\ttests := []struct {\n\t\tname             string\n\t\trequestBody      string\n\t\tmockExpect       func()\n\t\texpectedResponse any\n\t}{\n\t\t{\n\t\t\tname:        \"Error while Binding\",\n\t\t\trequestBody: `title\":\"Book Title\",\"isbn\":12345}`,\n\t\t\tmockExpect: func() {\n\t\t\t},\n\t\t\texpectedResponse: gofrResponse{\n\t\t\t\tnil,\n\t\t\t\tgofrHttp.ErrorInvalidParam{Params: []string{\"body\"}}},\n\t\t},\n\t\t{\n\t\t\tname:        \"Successful Insertion\",\n\t\t\trequestBody: `{\"title\":\"Book Title\",\"isbn\":12345}`,\n\t\t\tmockExpect: func() {\n\t\t\t\tmock.SQL.\n\t\t\t\t\tExpectExec(`INSERT INTO books (title, isbn) VALUES (?, ?)`).\n\t\t\t\t\tWithArgs(\"Book Title\", 12345).\n\t\t\t\t\tWillReturnResult(sqlmock.NewResult(12, 1))\n\t\t\t},\n\t\t\texpectedResponse: gofrResponse{\n\t\t\t\tint64(12),\n\t\t\t\tnil,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:        \"Error on Insertion\",\n\t\t\trequestBody: `{\"title\":\"Book Title\",\"isbn\":12345}`,\n\t\t\tmockExpect: func() {\n\t\t\t\tmock.SQL.\n\t\t\t\t\tExpectExec(`INSERT INTO books (title, isbn) VALUES (?, ?)`).\n\t\t\t\t\tWithArgs(\"Book Title\", 12345).\n\t\t\t\t\tWillReturnError(sql.ErrConnDone)\n\t\t\t},\n\t\t\texpectedResponse: gofrResponse{\n\t\t\t\tnil,\n\t\t\t\tsql.ErrConnDone},\n\t\t},\n\t\t{\n\t\t\tname:        \"Error while fetching LastInsertId\",\n\t\t\trequestBody: `{\"title\":\"Book Title\",\"isbn\":12345}`,\n\t\t\tmockExpect: func() {\n\t\t\t\tmock.SQL.\n\t\t\t\t\tExpectExec(`INSERT INTO books (title, isbn) VALUES (?, ?)`).\n\t\t\t\t\tWithArgs(\"Book Title\", 12345).\n\t\t\t\t\tWillReturnError(errors.New(\"mocked result error\"))\n\t\t\t},\n\t\t\texpectedResponse: gofrResponse{\n\t\t\t\tnil,\n\t\t\t\terrors.New(\"mocked result error\")},\n\t\t},\n\t}\n\n\tfor i, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ttt.mockExpect()\n\n\t\t\tvar req *http.Request\n\n\t\t\treq = httptest.NewRequest(\n\t\t\t\thttp.MethodPost,\n\t\t\t\t\"/book\",\n\t\t\t\tbytes.NewBuffer([]byte(tt.requestBody)),\n\t\t\t)\n\n\t\t\treq.Header.Set(\"Content-Type\", \"application/json\")\n\n\t\t\trequest := gofrHttp.NewRequest(req)\n\n\t\t\tctx.Request = request\n\n\t\t\tval, err := Add(ctx)\n\n\t\t\tresponse := gofrResponse{val, err}\n\n\t\t\tassert.Equal(t, tt.expectedResponse, response, \"TEST[%d], Failed.\\n%s\", i, tt.name)\n\t\t})\n\t}\n}\n\n```\n\n## Testing HTTP Handlers with Mock Services\n\nWhen you register multiple services with `WithMockHTTPService`, each service gets its own separate mock instance. This allows you to set different expectations for each service using the `mocks.HTTPServices` map. Use table-driven tests to cover multiple scenarios:\n\n### Important Notes\n\n- **Context Matching**: Always use the exact context from your `gofr.Context` (`ctx.Context`) in expectations. gomock compares contexts by reference, not value, so using `t.Context()` or `context.Background()` will fail.\n- **Service Registration**: `WithMockHTTPService(\"serviceName\")` registers the service with the specified name. Each service gets its own separate mock instance.\n- **Multiple Services**: Use `mocks.HTTPServices[\"serviceName\"]` to access and set different expectations for each service. Each service has its own mock instance, so expectations are independent.\n- **Tests will fail** if the mocked HTTPService is not called as expected or if the context doesn't match.\n\n```go\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gorilla/mux\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gofr.dev/pkg/gofr\"\n\t\"gofr.dev/pkg/gofr/container\"\n\tgofrHttp \"gofr.dev/pkg/gofr/http\"\n)\n\n// Handler that calls multiple HTTP services\n// This handler demonstrates calling two different services (paymentService and shippingService)\n// to fetch order details from different parts of the system.\nfunc OrderDetailsHandler(ctx *gofr.Context) (any, error) {\n\torderID := ctx.PathParam(\"id\")\n\tif orderID == \"\" {\n\t\treturn nil, errors.New(\"order ID is required\")\n\t}\n\n\t// First HTTP service call: Get payment details from paymentService\n\tpaymentService := ctx.GetHTTPService(\"paymentService\")\n\tpaymentResp, err := paymentService.Get(ctx.Context, \"/payments/\"+orderID, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to fetch payment details: %w\", err)\n\t}\n\tdefer paymentResp.Body.Close()\n\n\tvar paymentData struct {\n\t\tStatus string `json:\"status\"`\n\t\tAmount int    `json:\"amount\"`\n\t}\n\n\tpaymentBody, err := io.ReadAll(paymentResp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read payment response: %w\", err)\n\t}\n\n\tif err := json.Unmarshal(paymentBody, &paymentData); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse payment response: %w\", err)\n\t}\n\n\t// Second HTTP service call: Get shipping details from shippingService\n\tshippingService := ctx.GetHTTPService(\"shippingService\")\n\tshippingResp, err := shippingService.Get(ctx.Context, \"/shipping/\"+orderID, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to fetch shipping details: %w\", err)\n\t}\n\tdefer shippingResp.Body.Close()\n\n\tvar shippingData struct {\n\t\tStatus           string `json:\"status\"`\n\t\tTracking         string `json:\"tracking\"`\n\t\tEstimatedDelivery string `json:\"estimated_delivery\"`\n\t}\n\n\tshippingBody, err := io.ReadAll(shippingResp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read shipping response: %w\", err)\n\t}\n\n\tif err := json.Unmarshal(shippingBody, &shippingData); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse shipping response: %w\", err)\n\t}\n\n\t// Combine results from both services\n\treturn map[string]any{\n\t\t\"order_id\":          orderID,\n\t\t\"payment_status\":    paymentData.Status,\n\t\t\"payment_amount\":    paymentData.Amount,\n\t\t\"shipping_status\":   shippingData.Status,\n\t\t\"tracking_number\":   shippingData.Tracking,\n\t\t\"estimated_delivery\": shippingData.EstimatedDelivery,\n\t}, nil\n}\n\nfunc TestOrderDetailsHandler(t *testing.T) {\n\t// Helper function to create test context with path parameters\n\tcreateTestContext := func(path string, container *container.Container) *gofr.Context {\n\t\treq := httptest.NewRequest(http.MethodGet, path, nil)\n\t\t\n\t\t// Set path parameters using mux.SetURLVars (required for ctx.PathParam to work)\n\t\tif strings.Contains(path, \"/orders/\") {\n\t\t\tparts := strings.Split(strings.Trim(path, \"/\"), \"/\")\n\t\t\tif len(parts) >= 2 && parts[1] != \"\" {\n\t\t\t\treq = mux.SetURLVars(req, map[string]string{\"id\": parts[1]})\n\t\t\t}\n\t\t}\n\n\t\treturn &gofr.Context{\n\t\t\tContext:   req.Context(),\n\t\t\tRequest:   gofrHttp.NewRequest(req),\n\t\t\tContainer: container,\n\t\t}\n\t}\n\n\tconst testOrderID = \"12345\" // Reusable order ID for tests\n\n\ttests := []struct {\n\t\tname           string\n\t\tsetupMocks     func(*container.Mocks, *gofr.Context)\n\t\trequestPath    string\n\t\twantErr        bool\n\t\twantErrMsg     string\n\t\tvalidateResult func(*testing.T, any)\n\t}{\n\t\t{\n\t\t\tname: \"successful order details retrieval\",\n\t\t\tsetupMocks: func(mocks *container.Mocks, ctx *gofr.Context) {\n\t\t\t\t// Set up expectation for paymentService - this is the first HTTP call in the handler\n\t\t\t\tpaymentResp := &http.Response{\n\t\t\t\t\tStatusCode: http.StatusOK,\n\t\t\t\t\tBody:       io.NopCloser(strings.NewReader(`{\"status\":\"completed\",\"amount\":1500}`)),\n\t\t\t\t}\n\t\t\t\tmocks.HTTPServices[\"paymentService\"].EXPECT().Get(\n\t\t\t\t\tctx.Context,\n\t\t\t\t\t\"/payments/\"+testOrderID,\n\t\t\t\t\tnil,\n\t\t\t\t).Return(paymentResp, nil)\n\n\t\t\t\t// Set up expectation for shippingService - this is the second HTTP call in the handler\n\t\t\t\t// Note: Each service has its own independent mock instance\n\t\t\t\tshippingResp := &http.Response{\n\t\t\t\t\tStatusCode: http.StatusOK,\n\t\t\t\t\tBody:       io.NopCloser(strings.NewReader(`{\"status\":\"in_transit\",\"tracking\":\"TRACK123\",\"estimated_delivery\":\"2024-12-25\"}`)),\n\t\t\t\t}\n\t\t\t\tmocks.HTTPServices[\"shippingService\"].EXPECT().Get(\n\t\t\t\t\tctx.Context,\n\t\t\t\t\t\"/shipping/\"+testOrderID,\n\t\t\t\t\tnil,\n\t\t\t\t).Return(shippingResp, nil)\n\t\t\t},\n\t\t\trequestPath: \"/orders/\" + testOrderID,\n\t\t\twantErr:     false,\n\t\t\tvalidateResult: func(t *testing.T, result any) {\n\t\t\t\tresultMap := result.(map[string]any)\n\t\t\t\tassert.Equal(t, testOrderID, resultMap[\"order_id\"])\n\t\t\t\tassert.Equal(t, \"completed\", resultMap[\"payment_status\"])\n\t\t\t\tassert.Equal(t, 1500, resultMap[\"payment_amount\"])\n\t\t\t\tassert.Equal(t, \"in_transit\", resultMap[\"shipping_status\"])\n\t\t\t\tassert.Equal(t, \"TRACK123\", resultMap[\"tracking_number\"])\n\t\t\t\tassert.Equal(t, \"2024-12-25\", resultMap[\"estimated_delivery\"])\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"payment service error\",\n\t\t\tsetupMocks: func(mocks *container.Mocks, ctx *gofr.Context) {\n\t\t\t\t// Payment service returns an error - handler should fail before calling shipping service\n\t\t\t\tmocks.HTTPServices[\"paymentService\"].EXPECT().Get(\n\t\t\t\t\tctx.Context,\n\t\t\t\t\t\"/payments/\"+testOrderID,\n\t\t\t\t\tnil,\n\t\t\t\t).Return(nil, errors.New(\"payment service unavailable\"))\n\n\t\t\t\t// Shipping service should NOT be called when payment service fails\n\t\t\t\t// No expectation set for shippingService - test will fail if it's called\n\t\t\t},\n\t\t\trequestPath: \"/orders/\" + testOrderID,\n\t\t\twantErr:     true,\n\t\t\twantErrMsg:  \"failed to fetch payment details\",\n\t\t},\n\t\t{\n\t\t\tname: \"shipping service error\",\n\t\t\tsetupMocks: func(mocks *container.Mocks, ctx *gofr.Context) {\n\t\t\t\t// Payment service succeeds\n\t\t\t\tpaymentResp := &http.Response{\n\t\t\t\t\tStatusCode: http.StatusOK,\n\t\t\t\t\tBody:       io.NopCloser(strings.NewReader(`{\"status\":\"completed\",\"amount\":1500}`)),\n\t\t\t\t}\n\t\t\t\tmocks.HTTPServices[\"paymentService\"].EXPECT().Get(\n\t\t\t\t\tctx.Context,\n\t\t\t\t\t\"/payments/\"+testOrderID,\n\t\t\t\t\tnil,\n\t\t\t\t).Return(paymentResp, nil)\n\n\t\t\t\t// Shipping service returns an error - this is the second HTTP call\n\t\t\t\tmocks.HTTPServices[\"shippingService\"].EXPECT().Get(\n\t\t\t\t\tctx.Context,\n\t\t\t\t\t\"/shipping/\"+testOrderID,\n\t\t\t\t\tnil,\n\t\t\t\t).Return(nil, errors.New(\"shipping service unavailable\"))\n\t\t\t},\n\t\t\trequestPath: \"/orders/\" + testOrderID,\n\t\t\twantErr:     true,\n\t\t\twantErrMsg:  \"failed to fetch shipping details\",\n\t\t},\n\t\t{\n\t\t\tname: \"missing order ID\",\n\t\t\tsetupMocks: func(mocks *container.Mocks, ctx *gofr.Context) {\n\t\t\t\t// No service calls should be made when order ID is missing\n\t\t\t},\n\t\t\trequestPath: \"/orders/\",\n\t\t\twantErr:     true,\n\t\t\twantErrMsg:  \"order ID is required\",\n\t\t},\n\t}\n\n\t// Register HTTP services once - each service gets its own separate mock instance\n\t// Since all test cases use the same services, we can create the mock container outside the loop\n\tmockContainer, mocks := container.NewMockContainer(t,\n\t\tcontainer.WithMockHTTPService(\"paymentService\", \"shippingService\"),\n\t)\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Create test context using helper function\n\t\t\tctx := createTestContext(tt.requestPath, mockContainer)\n\n\t\t\t// Set up mock expectations BEFORE calling the handler\n\t\t\t// Each service's expectations are independent\n\t\t\ttt.setupMocks(mocks, ctx)\n\n\t\t\t// Call the handler\n\t\t\tresult, err := OrderDetailsHandler(ctx)\n\n\t\t\tif tt.wantErr {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), tt.wantErrMsg)\n\t\t\t\tassert.Nil(t, result)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tif tt.validateResult != nil {\n\t\t\t\t\ttt.validateResult(t, result)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n```\n\n**Key Points**:\n- Each service registered via `WithMockHTTPService` gets its own separate mock instance\n- Always use `mocks.HTTPServices[\"serviceName\"]` to access and set expectations for a specific service\n- Always create the `gofr.Context` with the exact request context (`req.Context()`) that will be used in the handler\n- Set expectations on the mock services before calling the handler\n- Test both success and error scenarios to ensure your handlers handle all cases correctly\n\n### Summary\n\n- **Mocking Database Interactions**: Use GoFr mock container to simulate database interactions.\n- **Mocking HTTP Services**: Use `WithMockHTTPService(\"serviceName\")` to register and mock HTTP services.\n- **Context Matching**: Always use `ctx.Context` from your `gofr.Context` in mock expectations, not `t.Context()` or `context.Background()`.\n- **Define Test Cases**: Create table-driven tests to handle various scenarios.\n- **Run and Validate**: Ensure that your tests check for expected results, and handle errors correctly.\n\nThis approach guarantees that your database and HTTP service interactions are tested independently, allowing you to simulate different responses and errors hassle-free.\n</yakaai_skills>"}