## File: README.md

<h2>Listed in the [CNCF Landscape](https://landscape.cncf.io/?selected=go-fr)</h2>


## 🎯 **Goal**
GoFr is designed to **simplify microservice development**, with a key focus on **Kubernetes deployment** and **out-of-the-box observability**. While capable of building generic applications, **microservices** remain at its core.

---

## 💡 **Key Features**

1. **Simple API Syntax**
2. **REST Standards by Default**
3. **Configuration Management**
4. **[Observability](https://gofr.dev/docs/quick-start/observability)** (Logs, Traces, Metrics)
5. **Inbuilt [Auth Middleware](https://gofr.dev/docs/advanced-guide/http-authentication)** & Custom Middleware Support
6. **[gRPC Support](https://gofr.dev/docs/advanced-guide/grpc)**
7. **[HTTP Service](https://gofr.dev/docs/advanced-guide/http-communication)** with Circuit Breaker Support
8. **[Pub/Sub](https://gofr.dev/docs/advanced-guide/using-publisher-subscriber)**
9. **[Health Check](https://gofr.dev/docs/advanced-guide/monitoring-service-health)** for All Datasources
10. **[Database Migration](https://gofr.dev/docs/advanced-guide/handling-data-migrations)**
11. **[Cron Jobs](https://gofr.dev/docs/advanced-guide/using-cron)**
12. **Support for [Changing Log Level](https://gofr.dev/docs/advanced-guide/remote-log-level-change) Without Restarting**
13. **[Swagger Rendering](https://gofr.dev/docs/advanced-guide/swagger-documentation)**
14. **[Abstracted File Systems](https://gofr.dev/docs/advanced-guide/handling-file)**
15. **[Websockets](https://gofr.dev/docs/advanced-guide/websocket)**

---

## 🚀 **Getting Started**

### **Prerequisites**
- GoFr requires **[Go](https://go.dev/)** version **[1.24](https://go.dev/doc/devel/release#go1.24.0)** or above.

### **Installation**
To get started with GoFr, add the following import to your code and use Go’s module support to automatically fetch dependencies:

```go
import "gofr.dev/pkg/gofr"
```

Alternatively, use the command:

```bash
go get -u gofr.dev/pkg/gofr
```

---

## 🏃 **Running GoFr**

Here's a simple example to get a GoFr application up and running:

```go
package main

import "gofr.dev/pkg/gofr"

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

	app.GET("/greet", func(ctx *gofr.Context) (any, error) {
		return "Hello World!", nil
	})

	app.Run() // listens and serves on localhost:8000
}
```

To run this code:

```bash
$ go run main.go
```

Visit [`localhost:8000/greet`](http://localhost:8000/greet) to see the result.

---

## 📂 **More Examples**

Explore a variety of ready-to-run examples in the [GoFr examples directory](https://github.com/gofr-dev/gofr/tree/development/examples).

---

## 👩‍💻 **Documentation**

- **[GoDoc](https://pkg.go.dev/gofr.dev)**: Official API documentation.
- **[GoFr Documentation](https://gofr.dev/docs)**: Comprehensive guides and resources.

---

## 👍 **Contribute**

Join Us in Making GoFr Better

**Share your experience**: If you’ve found GoFr helpful, consider writing a review or tutorial on platforms like **[Medium](https://medium.com/)**, **[Dev.to](https://dev.to/)**, or your personal blog. 
Your insights could help others get started faster!

**Contribute to the project**: Want to get involved? Check out our **[CONTRIBUTING.md](CONTRIBUTING.md)**
guide to learn how you can contribute code, suggest improvements, or report issues.

---

## 🔒 **Secure Cloning**
To securely clone the GoFr repository, you can use HTTPS or SSH:

### Cloning with HTTPS
```bash
git clone https://github.com/gofr-dev/gofr.git
```
### Cloning with SSH
```bash
git clone git@github.com:gofr-dev/gofr.git
```

### 🎁 **Get a GoFr T-Shirt & Stickers!**

If your PR is merged, or if you contribute by writing articles or promoting GoFr, we invite you to fill out [this form](https://forms.gle/R1Yz7ZzY3U5WWTgy5) to claim your GoFr merchandise as a token of our appreciation! 

### Partners

---

## File: docs/datasources/surrealdb/page.md

---
nextjs:
  metadata:
    title: "SurrealDB in GoFr — Multi-Model Datasource Integration"
---

# SurrealDB

## Configuration
To connect to `SurrealDB`, you need to provide the following environment variables:
- `HOST`: The hostname or IP address of your SurrealDB server.
- `PORT`: The port number.
- `USERNAME`: The username for connecting to the database.
- `PASSWORD`: The password for the specified user.
- `NAMESPACE`: Top level container in SurrealDB that groups databases.
- `DATABASE`: The name of the database to connect to.
- `TLSENABLED`: TLS mode (e.g., disable, require)

## Setup 
GoFr supports injecting SurrealDB database that supports the following interface. Any driver that implements the interface can be added
using `app.AddSurrealDB()` method, and users can use Surreal DB across application through the `gofr.Context`.

```go
// SurrealDB defines an interface representing a SurrealDB client with common database operations.
type SurrealDB interface {
    // Query executes a Surreal query with the provided variables and returns the query results as a slice of interfaces{}.
    // It returns an error if the query execution fails.
    Query(ctx context.Context, query string, vars map[string]any) ([]any, error)

    // Create inserts a new record into the specified table and returns the created record as a map.
    // It returns an error if the operation fails.
    Create(ctx context.Context, table string, data any) (map[string]any, error)

    // Update modifies an existing record in the specified table by its ID with the provided data.
    // It returns the updated record as an interface and an error if the operation fails.
    Update(ctx context.Context, table string, id string, data any) (any, error)

    // Delete removes a record from the specified table by its ID.
    // It returns the result of the delete operation as an interface and an error if the operation fails.
    Delete(ctx context.Context, table string, id string) (any, error)

    // Select retrieves all records from the specified table.
    // It returns a slice of maps representing the records and an error if the operation fails.
    Select(ctx context.Context, table string) ([]map[string]any, error)

    HealthChecker
}

// SurrealDBProvider is an interface that extends SurrealDB with additional methods for logging, metrics, or connection management.
// It is typically used for initializing and managing SurrealDB-based data sources.
type SurrealDBProvider interface {
    SurrealDB

    provider
}
```
Import the gofr's external driver for SurrealDB:
```shell
  go get gofr.dev/pkg/gofr/datasource/surrealdb
```
The following example demonstrates injecting an SurrealDB instance into a GoFr application.

```go
package main

import (
	"gofr.dev/pkg/gofr"
	"gofr.dev/pkg/gofr/datasource/surrealdb"
)

type Person struct {
	ID    string `json:"id,omitempty"`
	Name  string `json:"name"`
	Age   int    `json:"age"`
	Email string `json:"email,omitempty"`
}

type ErrorResponse struct {
	Message string `json:"message"`
}

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

	client := surrealdb.New(&surrealdb.Config{
		Host:       app.Config.Get("HOST"),
		Port:       app.Config.Get("PORT"),
		Username:   app.Config.Get("USERNAME"),
		Password:   app.Config.Get("PASSWORD"),
		Namespace:  app.Config.Get("NAMESPACE"),
		Database:   app.Config.Get("DATABASE"),
		TLSEnabled: app.Config.Get("TLSENABLED"),
	})

	app.AddSurrealDB(client)

	// GET request to fetch person by ID
	app.GET("/person/{id}", func(ctx *gofr.Context) (any, error) {
		id := ctx.PathParam("id")

		query := "SELECT * FROM type::thing('person', $id)"
		vars := map[string]any{
			"id": id,
		}

		result, err := ctx.SurrealDB.Query(ctx, query, vars)
		if err != nil {
			return nil, err
		}

		return result, nil
	})

	// POST request to create a new person
	app.POST("/person", func(ctx *gofr.Context) (any, error) {
		var person Person

		if err := ctx.Bind(&person); err != nil {
			return ErrorResponse{Message: "Invalid request body"}, nil
		}

		result, err := ctx.SurrealDB.Create(ctx, "person", map[string]any{
			"name":  person.Name,
			"age":   person.Age,
			"email": person.Email,
		})

		if err != nil {
			return nil, err
		}

		return result, nil
	})

	app.Run()
}

```

---

## File: docs/datasources/solr/page.md

---
nextjs:
  metadata:
    title: "Solr in GoFr — Search Engine Datasource Integration"
---

# Solr

## Configuration
To connect to `Solr` DB, you need to provide the following environment variables:
- `HOST`: The hostname or IP address of your Solr DB server.
- `PORT`: The port number.

## Setup
GoFr supports injecting Solr database that supports the following interface. Any driver that implements the interface can be added
using `app.AddSolr()` method, and user's can use Solr DB across application with `gofr.Context`.

```go
type Solr interface {
	Search(ctx context.Context, collection string, params map[string]any) (any, error)
	Create(ctx context.Context, collection string, document *bytes.Buffer, params map[string]any) (any, error)
	Update(ctx context.Context, collection string, document *bytes.Buffer, params map[string]any) (any, error)
	Delete(ctx context.Context, collection string, document *bytes.Buffer, params map[string]any) (any, error)

	Retrieve(ctx context.Context, collection string, params map[string]any) (any, error)
	ListFields(ctx context.Context, collection string, params map[string]any) (any, error)
	AddField(ctx context.Context, collection string, document *bytes.Buffer) (any, error)
	UpdateField(ctx context.Context, collection string, document *bytes.Buffer) (any, error)
	DeleteField(ctx context.Context, collection string, document *bytes.Buffer) (any, error)
}
```

User's can easily inject a driver that supports this interface, this provides usability
without compromising the extensibility to use multiple databases.

Import the gofr's external driver for Solr:

```shell
go get gofr.dev/pkg/gofr/datasource/solr@latest
```
Note : This datasource package requires the user to create the collection before performing any operations.
While testing the below code create a collection using :
`curl --location 'http://localhost:2020/solr/admin/collections?action=CREATE&name=test&numShards=2&replicationFactor=1&wt=xml'`

```go
package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"gofr.dev/pkg/gofr"
	"gofr.dev/pkg/gofr/datasource/solr"
)

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

	app.AddSolr(solr.New(solr.Config{
		Host: app.Config.Get("HOST"),
		Port: app.Config.Get("PORT"),
	}))

	app.POST("/solr", post)
	app.GET("/solr", get)

	app.Run()
}

type Person struct {
	Name string
	Age  int
}

func post(c *gofr.Context) (any, error) {
	p := []Person{{Name: "Srijan", Age: 24}}
	body, _ := json.Marshal(p)

	resp, err := c.Solr.Create(c, "test", bytes.NewBuffer(body), nil)
	if err != nil {
		return nil, err
	}

	return resp, nil
}

func get(c *gofr.Context) (any, error) {
	resp, err := c.Solr.Search(c, "test", nil)
	if err != nil {
		return nil, err
	}

	res, ok := resp.(solr.Response)
	if !ok {
		return nil, errors.New("invalid response type")
	}

	b, _ := json.Marshal(res.Data)
	err = json.Unmarshal(b, &Person{})
	if err != nil {
		return nil, err
	}

	return resp, nil
}
```

---

## File: docs/datasources/scylladb/page.md

---
nextjs:
  metadata:
    title: "ScyllaDB in GoFr — Cassandra-Compatible Datasource"
---

# ScyllaDB

## Configuration
To connect to `ScyllaDB`, you need to provide the following environment variables:
- `HOST`: The hostname or IP address of your ScyllaDB server.
- `KEYSPACE`: The top level namespace.
- `PORT`: The port number.
- `USERNAME`: The username for connecting to the database.
- `PASSWORD`: The password for the specified user.

## Setup
GoFr supports pluggable ScyllaDB drivers. It defines an interface that specifies the required methods for interacting
with ScyllaDB. Any driver implementation that adheres to this interface can be integrated into GoFr using the
`app.AddScyllaDB()` method.

```
/* Detailed source-code truncated for AI context efficiency. */
```


Import the gofr's external driver for ScyllaDB:

```shell
go get gofr.dev/pkg/gofr/datasource/scylladb
```

```go
package main

import (
	"github.com/gocql/gocql"
	"gofr.dev/pkg/gofr"
	"gofr.dev/pkg/gofr/datasource/scylladb"
	"gofr.dev/pkg/gofr/http"
)

type User struct {
	ID    gocql.UUID `json:"id"`
	Name  string     `json:"name"`
	Email string     `json:"email"`
}

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

	client := scylladb.New(scylladb.Config{
		Host:     app.Config.Get("HOST"),
		Keyspace: app.Config.Get("KEYSPACE"),
		Port:     app.Config.Get("PORT"),
		Username: app.Config.Get("USERNAME"),
		Password: app.Config.Get("PASSWORD"),
	})

	app.AddScyllaDB(client)

	app.GET("/users/{id}", getUser)
	app.POST("/users", addUser)

	app.Run()
}

func addUser(c *gofr.Context) (any, error) {
	var newUser User
	err := c.Bind(&newUser)
	if err != nil {
		return nil, err
	}
	_ = c.ScyllaDB.ExecWithCtx(c, `INSERT INTO users (user_id, username, email) VALUES (?, ?, ?)`, newUser.ID, newUser.Name, newUser.Email)

	return newUser, nil
}

func getUser(c *gofr.Context) (any, error) {
	var user User
	id := c.PathParam("id")

	userID, err := gocql.ParseUUID(id)
	if err != nil {
		c.Logger.Error("Invalid UUID format:", err)
		return nil, err
	}

	err = c.ScyllaDB.QueryWithCtx(c, &user, "SELECT id, name, email FROM users WHERE id = ?", userID)
	if err != nil {
		c.Logger.Error("Error querying user:", err)
		return nil, err
	}

	return user, nil
}
```

---

## File: docs/datasources/oracle/page.md

---
nextjs:
  metadata:
    title: "Oracle Database in GoFr — Pluggable Driver Integration"
---

# OracleDB

## Configuration
To connect to `OracleDB`, you need to provide the following environment variables:
- `HOST`: The hostname or IP address of your OracleDB server.
- `PORT`: The port number.
- `USERNAME`: The username for connecting to the database.
- `PASSWORD`: The password for the specified user.
- `SERVICE`: The specific Oracle database instance or service on the server that the client should connect to.

## Setup
GoFr supports injecting OracleDB as a relational datasource through a clean, extensible interface. Any driver that implements the following interface can be added using the `app.AddOracle()` method, and users can access OracleDB throughout their application via `gofr.Context`.

```go
type Oracle interface {
 Exec(ctx context.Context, query string, args ...any) error
 Select(ctx context.Context, dest any, query string, args ...any) error
}
```

This approach allows users to easily inject any compatible Oracle driver, providing both usability and the flexibility to use multiple databases in a GoFr application.

## Important: Oracle Database Must Exist

**Before running your GoFr application, you must ensure that the Oracle database and the required schema (such as the `users` table) are already created.**

- Oracle does not allow creating a database (PDB or CDB) via a simple SQL query from a standard client connection.
- You must use Oracle tools (like DBCA, SQL\*Plus as SYSDBA, or Docker container initialization) to create the database and pluggable database (PDB) before connecting your app.
- Your application can create tables within an existing schema, but the database itself must be provisioned in advance.

## Setting Up OracleDB with Docker

To help new users, the following steps outline how to quickly set up an OracleDB instance using Docker.

### 1. Prerequisites

- **Docker** installed on your system.
- An **Oracle account** (free) with access to the Oracle Container Registry.

### 2. Create Your Oracle Account

Visit the Oracle Container Registry and create or sign in to your account:

👉 [https://container-registry.oracle.com/ords/f?p=113:10:14574461221664:::::](https://container-registry.oracle.com/ords/f?p=113:10:14574461221664:::::)

### 3. Pull the Oracle Free Database Docker Image

In your terminal:

1. Log in to the Oracle Container Registry using your Oracle account credentials:

```sh
docker login container-registry.oracle.com
```

2. After login, pull the Oracle Free Database image:

```sh
docker pull container-registry.oracle.com/database/free:latest
```

### 4. Run the Oracle Database Container

You can now run the OracleDB container (replace `YourPasswordHere` with a suitable strong password):

```sh
docker run -d --name oracle-free -p 1521:1521 -e ORACLE_PWD=YourPasswordHere container-registry.oracle.com/database/free:latest

```

- The database will be available on port **1521**
- The default Pluggable Database (PDB) is **FREEPDB1**
- The `system` user password is your `ORACLE_PWD`
- The service name for connecting is `FREEPDB1`

You can verify the container is running:

```sh
docker ps
```

### 5. Connect to the Oracle Database

Option 1: Direct SQL\*Plus session from within the container:

```sh
docker exec -it oracle-free sqlplus system/YourPasswordHere@localhost:1521/FREEPDB1
```

Option 2: Open bash shell inside the container and use SQL\*Plus from there:

```sh
docker exec -it oracle-free bash
sqlplus system/YourPasswordHere@localhost:1521/FREEPDB1
```

### 6. Create the `users` Table

Based on the Go struct:

```go
type User struct {
 Id   string `db:"ID"`
 Name string `db:"NAME"`
 Age  int    `db:"AGE"`
}
```

Run the following SQL command in SQL\*Plus:

```sql
CREATE TABLE users (
 id   VARCHAR2(36) PRIMARY KEY,
 name VARCHAR2(100),
 age  NUMBER
);
```

This will create the required table for the GoFr application to interact with.

### 7. Sample OracleDB Config for GoFr

| Setting     | Value              |
| :---------- | :----------------- |
| host        | `localhost`        |
| port        | `1521`             |
| username    | `system`           |
| password    | `YourPasswordHere` |
| service/SID | `FREEPDB1`         |

## Import the GoFr External Driver for OracleDB

```bash
go get gofr.dev/pkg/gofr/datasource/oracle@latest
```

## Example

```go
package main

import (
 "gofr.dev/pkg/gofr"
 "gofr.dev/pkg/gofr/datasource/oracle"
)

type User struct {
 Id   string `db:"ID"`
 Name string `db:"NAME"`
 Age  int    `db:"AGE"`
}

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

 app.AddOracle(oracle.New(oracle.Config{
  Host:     app.Config.Get("HOST"),
  Port:     app.Config.Get("PORT"),
  Username: app.Config.Get("USERNAME"),
  Password: app.Config.Get("PASSWORD")
  Service:  app.Config.Get("SERVICE"),
 }))

 app.POST("/user", Post)
 app.GET("/user", Get)

 app.Run()
}

func Post(ctx *gofr.Context) (any, error) {
 err := ctx.Oracle.Exec(ctx, "INSERT INTO users (id, name, age) VALUES (:1, :2, :3)",
  "8f165e2d-feef-416c-95f6-913ce3172e15", "aryan", 10)
 if err != nil {
  return nil, err
 }
 return "successfully inserted", nil
}

func Get(ctx *gofr.Context) (any, error) {
 var users []map[string]any
 err := ctx.Oracle.Select(ctx, &users, "SELECT id, name, age FROM users")
 if err != nil {
  return nil, err
 }
 return users, nil
}
```

## Example API Usage

You can create a user and get users using the following commands on the command prompt:

- **Create a user:**

```sh
curl -X POST http://localhost:8000/user
```

- **Get all users:**

```sh
curl http://localhost:8000/user
```

---

## File: docs/datasources/opentsdb/page.md

---
nextjs:
  metadata:
    title: "OpenTSDB in GoFr — Time-Series Metrics Datasource"
---

# OpenTSDB


## Configuration
To connect to `OpenTSDB`, you need to provide the following environment variables:
- `HOSTS`: The hostname or IP address of your OpenTSDB server.
- `MAXCONTENTLENGTH`: Max length of the request body in bytes.
- `MAXPUTPOINTSNUM`: Max number of data points that can be sent in a single `PUT` request.
- `DETECTDELTANUM`: The number of data points that OpenTSDB looks at to spot unusual time gaps.

## Setup
GoFr supports injecting OpenTSDB to facilitate interaction with OpenTSDB's REST APIs.
Implementations adhering to the `OpenTSDB` interface can be registered with `app.AddOpenTSDB()`,
enabling applications to leverage OpenTSDB for time-series data management through `gofr.Context`.

```
/* Detailed source-code truncated for AI context efficiency. */
```

Import the gofr's external driver for OpenTSDB:

```go
go get gofr.dev/pkg/gofr/datasource/opentsdb
```

The following example demonstrates injecting an OpenTSDB instance into a GoFr application
and using it to perform a health check on the OpenTSDB server.
```
/* Detailed source-code truncated for AI context efficiency. */
```

---

## File: docs/datasources/mongodb/page.md

---
nextjs:
  metadata:
    title: "MongoDB in GoFr — Document Database Integration"
---

# MongoDB

## Configuration
To connect to `MongoDB`, you need to provide the following environment variables:
- `URI`: Mongodb server URL that the client connects to.
- `DATABASE`: The name of the database to connect to.
- `CONNECTIONTIMEOUT`: The maximum time the client will wait while trying to establish a connection.
  

## Setup
GoFr supports injecting MongoDB that supports the following interface. Any driver that implements the interface can be added
using `app.AddMongo()` method, and users can use MongoDB across application with `gofr.Context`.
```go
type Mongo interface {
	Find(ctx context.Context, collection string, filter any, results any) error

	FindOne(ctx context.Context, collection string, filter any, result any) error

	InsertOne(ctx context.Context, collection string, document any) (any, error)

	InsertMany(ctx context.Context, collection string, documents []any) ([]any, error)

	DeleteOne(ctx context.Context, collection string, filter any) (int64, error)

	DeleteMany(ctx context.Context, collection string, filter any) (int64, error)

	UpdateByID(ctx context.Context, collection string, id any, update any) (int64, error)

	UpdateOne(ctx context.Context, collection string, filter any, update any) error

	UpdateMany(ctx context.Context, collection string, filter any, update any) (int64, error)

	CountDocuments(ctx context.Context, collection string, filter any) (int64, error)

	Drop(ctx context.Context, collection string) error
}
```

Users can easily inject a driver that supports this interface; this provides usability without compromising the extensibility to use multiple databases.

Import the gofr's external driver for MongoDB:

```shell
go get gofr.dev/pkg/gofr/datasource/mongo@latest
```

### Example
```go
package main

import (
	"time"
	"go.mongodb.org/mongo-driver/bson"
	"gofr.dev/pkg/gofr/datasource/mongo"

	"gofr.dev/pkg/gofr"
)

type Person struct {
	Name string `bson:"name" json:"name"`
	Age  int    `bson:"age" json:"age"`
	City string `bson:"city" json:"city"`
}

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

	db := mongo.New(mongo.Config{URI: app.Config.Get("URI"), Database: app.Config.Get("DATABASE"), ConnectionTimeout: app.Config.Get("CONNECTIONTIMEOUT")})

	// inject the mongo into gofr to use mongoDB across the application
	// using gofr context
	app.AddMongo(db)

	app.POST("/mongo", Insert)
	app.GET("/mongo/{name}", Get)

	app.Run()
}

func Insert(ctx *gofr.Context) (any, error) {
	var p Person
	err := ctx.Bind(&p)
	if err != nil {
		return nil, err
	}

	res, err := ctx.Mongo.InsertOne(ctx, "collection", p)
	if err != nil {
		return nil, err
	}

	return res, nil
}

func Get(ctx *gofr.Context) (any, error) {
	var result Person

	p := ctx.PathParam("name")

	err := ctx.Mongo.FindOne(ctx, "collection", bson.D{{"name", p}} /* valid filter */, &result)
	if err != nil {
		return nil, err
	}

	return result, nil
}
```

---

## File: docs/datasources/migrations/elasticsearch/page.md

---
nextjs:
  metadata:
    title: "Elasticsearch Migrations in GoFr — Versioned Index Schemas"
---

# Elasticsearch Migrations

Elasticsearch migrations in **GoFr** let you manage index schemas, mappings, settings and data in a *version-controlled* manner.
This guide explains how to implement and operate these migrations without breaking production.

## Overview

Elasticsearch migrations help you:

- Create and manage indices with proper mappings
- Update index settings and configurations
- Seed initial data or migrate existing data
- Perform bulk operations efficiently
- Maintain schema consistency across environments


## Migration Tracking

GoFr automatically creates a `gofr_migrations` index in Elasticsearch to track applied migrations.
The index stores:

- Migration version (timestamp)
- Execution method (UP)
- Start time and duration
- Migration status


## Basic Migration Structure

```go
package main

import (
	"context"
	"gofr.dev/pkg/gofr"
	"gofr.dev/pkg/gofr/datasource/elasticsearch"
	"gofr.dev/pkg/gofr/migration"
)

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

	// Configure Elasticsearch
	esClient := elasticsearch.New(elasticsearch.Config{
		Addresses: []string{"http://localhost:9200"},
	})
	app.AddElasticsearch(esClient)

	// Define migrations
	migrationsMap := map[int64]migration.Migrate{
		1640995200: {
			UP: func(d migration.Datasource) error {
				// Migration logic here
				return nil
			},
		},
	}

	// Register and run migrations
	app.Migrate(migrationsMap)
	app.Run()
}
```


## Available Operations

### Index Management

```go
// Create an index with mappings and settings
CreateIndex(ctx context.Context, index string, settings map[string]any) error

// Delete an index
DeleteIndex(ctx context.Context, index string) error
```


### Document Operations

```go
// Index a single document
IndexDocument(ctx context.Context, index, id string, document any) error

// Delete a document by ID
DeleteDocument(ctx context.Context, index, id string) error

// Bulk operations for multiple documents
Bulk(ctx context.Context, operations []map[string]any) (map[string]any, error)
```


## Migration Examples

### 1. Creating an Index with Mappings

```go
1640995200: {
	UP: func(d migration.Datasource) error {
		settings := map[string]any{
			"mappings": map[string]any{
				"properties": map[string]any{
					"title": map[string]any{
						"type":     "text",
						"analyzer": "standard",
					},
					"price": map[string]any{
						"type": "float",
					},
					"category": map[string]any{
						"type": "keyword",
					},
					"created_at": map[string]any{
						"type": "date",
					},
					"tags": map[string]any{
						"type": "keyword",
					},
				},
			},
			"settings": map[string]any{
				"number_of_shards":   1,
				"number_of_replicas": 0,
				"analysis": map[string]any{
					"analyzer": map[string]any{
						"custom_text_analyzer": map[string]any{
							"type":      "standard",
							"stopwords": "_english_",
						},
					},
				},
			},
		}

		return d.Elasticsearch.CreateIndex(context.Background(), "products", settings)
	},
},
```


### 2. Seeding Initial Data

```go
1640995300: {
	UP: func(d migration.Datasource) error {
		// Create sample products
		products := []map[string]any{
			{
				"title":      "Laptop",
				"price":      999.99,
				"category":   "electronics",
				"created_at": "2024-01-01T00:00:00Z",
				"tags":       []string{"computer", "portable"},
			},
			{
				"title":      "Coffee Mug",
				"price":      12.99,
				"category":   "kitchen",
				"created_at": "2024-01-01T00:00:00Z",
				"tags":       []string{"ceramic", "drink"},
			},
		}

		ctx := context.Background()
		for i, product := range products {
			err := d.Elasticsearch.IndexDocument(
				ctx,
				"products",
				fmt.Sprintf("%d", i+1),
				product,
			)
			if err != nil {
				return fmt.Errorf("failed to index product %d: %w", i+1, err)
			}
		}

		return nil
	},
},
```


### 3. Bulk Operations Migration

```go
1640995400: {
	UP: func(d migration.Datasource) error {
		// Bulk index multiple documents efficiently
		operations := []map[string]any{
			// Index operation metadata
			{
				"index": map[string]any{
					"_index": "products",
					"_id":    "bulk_1",
				},
			},
			// Document data
			{
				"title":    "Bulk Product 1",
				"price":    19.99,
				"category": "bulk",
			},
			// Another index operation
			{
				"index": map[string]any{
					"_index": "products",
					"_id":    "bulk_2",
				},
			},
			// Document data
			{
				"title":    "Bulk Product 2",
				"price":    29.99,
				"category": "bulk",
			},
			// Delete operation
			{
				"delete": map[string]any{
					"_index": "products",
					"_id":    "old_product",
				},
			},
		}

		ctx := context.Background()
		result, err := d.Elasticsearch.Bulk(ctx, operations)
		if err != nil {
			return fmt.Errorf("bulk operation failed: %w", err)
		}

		// Check for errors in bulk response
		if errors, ok := result["errors"].(bool); ok && errors {
			return fmt.Errorf("bulk operation had errors: %v", result)
		}

		return nil
	},
},
```


### 4. Index Settings Update

```go
1640995500: {
	UP: func(d migration.Datasource) error {
		// Create a new index with updated settings
		settings := map[string]any{
			"mappings": map[string]any{
				"properties": map[string]any{
					"title": map[string]any{
						"type":     "text",
						"analyzer": "custom_text_analyzer",
					},
					"description": map[string]any{
						"type":     "text",
						"analyzer": "standard",
					},
					"price": map[string]any{
						"type": "float",
					},
				},
			},
			"settings": map[string]any{
				"number_of_shards":   2, // Increased shards
				"number_of_replicas": 1, // Added replica
				"refresh_interval":   "30s",
			},
		}

		return d.Elasticsearch.CreateIndex(context.Background(), "products_v2", settings)
	},
},
```


### 5. Data Migration Between Indices

```go
1640995600: {
	UP: func(d migration.Datasource) error {
		ctx := context.Background()

		// This would typically involve:
		// 1. Reading data from old index (using Search - not shown in interface yet)
		// 2. Transforming data if needed
		// 3. Bulk indexing to new index
		// 4. Deleting old index

		// For now, we'll create the new index structure
		newSettings := map[string]any{
			"mappings": map[string]any{
				"properties": map[string]any{
					"product_name": map[string]any{ // Renamed from 'title'
						"type": "text",
					},
					"product_price": map[string]any{ // Renamed from 'price'
						"type": "float",
					},
					"product_category": map[string]any{ // Renamed from 'category'
						"type": "keyword",
					},
				},
			},
		}

		err := d.Elasticsearch.CreateIndex(ctx, "products_new_schema", newSettings)
		if err != nil {
			return fmt.Errorf("failed to create new schema index: %w", err)
		}

		// Clean up old index
		return d.Elasticsearch.DeleteIndex(ctx, "products_old")
	},
},
```


## Bulk Operations Format

### Index Operation

```go
{
	"index": map[string]any{
		"_index": "index_name",
		"_id":    "document_id",
	},
}
// Followed by document data
{
	"field1": "value1",
	"field2": "value2",
}
```


### Update Operation

```go
{
	"update": map[string]any{
		"_index": "index_name",
		"_id":    "document_id",
	},
}
// Followed by update data
{
	"doc": map[string]any{
		"field1": "new_value1",
	},
}
```


### Delete Operation

```go
{
	"delete": map[string]any{
		"_index": "index_name",
		"_id":    "document_id",
	},
}
// No document data needed for delete
```


## Best Practices

### 1. Index Naming

- Use descriptive names: `users`, `products`, `orders`
- Consider versioning: `products_v1`, `products_v2`
- Use consistent naming conventions


### 2. Mapping Design

- Define explicit mappings rather than relying on dynamic mapping
- Choose appropriate field types
- Consider analyzer requirements for text fields
- Plan for future field additions


### 3. Settings Configuration

- Set appropriate shard and replica counts
- Configure refresh intervals based on use case
- Set up custom analyzers if needed


### 4. Migration Safety

- Test migrations on non-production data first
- Use bulk operations for large data sets
- Implement proper error handling
- Consider index aliases for zero-downtime migrations


### 5. Performance Considerations

- Use bulk operations for multiple documents
- Batch operations appropriately (1 000 – 5 000 docs per batch)
- Monitor cluster health during migrations
- Consider disabling replicas during large data migrations


## Error Handling

```go
UP: func(d migration.Datasource) error {
	ctx := context.Background()

	// Check if index already exists (idempotent migration)
	settings := map[string]any{
		"mappings": map[string]any{
			"properties": map[string]any{
				"name": map[string]any{"type": "text"},
			},
		},
	}

	err := d.Elasticsearch.CreateIndex(ctx, "users", settings)
	if err != nil {
		// Handle specific Elasticsearch errors
		if strings.Contains(err.Error(), "resource_already_exists_exception") {
			// Index already exists, this is okay
			return nil
		}
		return fmt.Errorf("failed to create users index: %w", err)
	}

	return nil
},
```


## Monitoring Migration Logs

```plaintext
INFO [15:09:13] running migration 1640995200
DEBU [15:09:13] CREATE INDEX products            ELASTIC   215759µs products             {"mappings":{"properties":{"price":{"type":"float"},"title":{"type":"text"}}},"settings":{"number_of_replicas":0,"number_of_shards":1}}
DEBU [15:09:13] INDEX DOCUMENT products/1        ELASTIC    87374µs 1                    {"price":19.99,"title":"Sample Product"}
```

The logs show:

- **Operation type** – CREATE INDEX, INDEX DOCUMENT, BULK, etc.
- **Execution time** – In microseconds
- **Target** – Index name, document ID
- **Query/Data** – Full JSON of the operation (no base64 encoding)


## Complete Example

```
/* Detailed source-code truncated for AI context efficiency. */
```

**Enjoy consistent, version-controlled Elasticsearch migrations with GoFr!**

---

## File: docs/datasources/influxdb/page.md

---
nextjs:
  metadata:
    title: "InfluxDB in GoFr — Time-Series Datasource Integration"
---

# InfluxDB
GoFr supports injecting InfluxDB using an interface that defines the necessary methods to interact with InfluxDB v2+.  
Any driver that implements this interface can be injected via the `app.AddInfluxDB()` method.

---

## Interface

```go
// InfluxDB defines the methods for interacting with an InfluxDB database.
type InfluxDB interface {
    CreateOrganization(ctx context.Context, orgName string) (string, error)
    DeleteOrganization(ctx context.Context, orgID string) error
    ListOrganization(ctx context.Context) (map[string]string, error)

    CreateBucket(ctx context.Context, orgID, bucketName string) (string, error)
    DeleteBucket(ctx context.Context, bucketID string) error
    ListBuckets(ctx context.Context, org string) (map[string]string, error)

    Ping(ctx context.Context) (bool, error)
    HealthCheck(ctx context.Context) (any, error)

    Query(ctx context.Context, org string, fluxQuery string) ([]map[string]any, error)
    WritePoints(ctx context.Context, bucket string, org string, points []container.InfluxPoint) error
}
```

This structure supports all essential InfluxDB operations including organization/bucket management, health checks, and metrics ingestion.

Import the gofr's external driver for influxdb: 

```bash
go get gofr.dev/pkg/gofr/datasource/influxdb@latest
```

## Example
```go
package main

import (
"context"
"fmt"
"time"

	"gofr.dev/pkg/gofr"
	"gofr.dev/pkg/gofr/datasource/influxdb"
)

func main() {
	
    // Create a new GoFr application
    app := gofr.New() 
	
	// Initialize InfluxDB client
	client := influxdb.New(influxdb.Config{
		Url:      "http://localhost:8086",
		Username: "admin",
		Password: "admin1234",
		Token:    "<your-token>",
	})

	// Add InfluxDB to application context
	app.AddInfluxDB(client)

	// Sample route
	app.GET("/greet", func(ctx *gofr.Context) (any, error) {
		return "Hello World!", nil
	})

	// Ping InfluxDB
	ok, err := client.Ping(context.Background())
	if err != nil {
		app.Logger().Fatal(err)
	}
	app.Logger().Debug("InfluxDB connected: ", ok)

	// Create organization
	orgID, err := client.CreateOrganization(context.Background(), "demo-org")
	if err != nil {
		app.Logger().Fatal(err)
	}

	// List organizations
	orgs, _ := client.ListOrganization(context.Background())
	app.Logger().Debug("Organizations: ")
	for id, name := range orgs {
		app.Logger().Debug(id, name)
	}

	// Create bucket
	bucketID, err := client.CreateBucket(context.Background(), orgID, "demo-bucket")
	if err != nil {
		app.Logger().Fatal(err)
	}

	// List buckets for organization
	buckets, err := client.ListBuckets(context.Background(), "demo-org")
	if err != nil {
		app.Logger().Fatal(err)
	}
	app.Logger().Debug("Buckets:", buckets)

	// Delete bucket
	if err := client.DeleteBucket(context.Background(), bucketID); err != nil {
		app.Logger().Fatal(err)
	}
	app.Logger().Debug("Bucket deleted successfully")

	// Delete organization
	if err := client.DeleteOrganization(context.Background(), orgID); err != nil {
		app.Logger().Fatal(err)
	}
	app.Logger().Debug("Organization deleted successfully")
	// Start the server
	app.Run()
}
```

---

## File: docs/datasources/getting-started/page.md

---
nextjs:
  metadata:
    title: "GoFr Datasources — Getting Started with the Interface"
---

# Getting Started
GoFr adopts an interface-driven architecture for datasource integration, providing a consistent way to work with various databases.
Each datasource implements predefined interfaces that define core functionality, enabling you to inject any database client that satisfies these interface contracts.
Users can inject any client that satisfies the base interface defined by GoFr, making it easy to swap out or add new datasources as needed.


Keeping in mind the size of the framework in the final build, it felt counter-productive to keep all the database drivers within
the framework itself. Keeping only the most used MySQL and Redis within the framework, users can now inject databases
in the server that satisfies the base interface defined by GoFr. This helps in reducing the build size and in turn build time
as unnecessary database drivers are not being compiled and added to the build.

> We are planning to provide custom drivers for most common databases, and is in the pipeline for upcoming releases!

## Supported Databases

{% table %}

- Datasource
- Health-Check
- Logs
- Metrics
- Traces
- Version-Migrations

---

-  MySQL
- ✅
- ✅
- ✅
- ✅
- ✅

---

-  REDIS
- ✅
- ✅
- ✅
- ✅
- ✅

---

-  PostgreSQL
- ✅
- ✅
- ✅
- ✅
- ✅

---

-  CockroachDB
- ✅
- ✅
- ✅
- ✅
- ✅

---

-  ArangoDB
- ✅
- ✅
- ✅
- ✅
- ✅

---


-  BadgerDB
- ✅
- ✅
- ✅
- ✅
-

---

-  Cassandra
- ✅
- ✅
- ✅
- ✅
- ✅

---

-  ClickHouse
-
- ✅
- ✅
- ✅
- ✅

---

-  DGraph
- ✅
- ✅
- ✅
- ✅
- ✅

---

-  MongoDB
- ✅
- ✅
- ✅
- ✅
- ✅

---
-  NATS KV
- ✅
- ✅
- ✅
- ✅
-
---

-  OpenTSDB
- ✅
- ✅
-
- ✅
-
---

-  ScyllaDB
- ✅
- ✅
- ✅
- ✅
-
---

-  Solr
-
- ✅
- ✅
- ✅
-
---

-  SQLite
- ✅
- ✅
- ✅
- ✅
- ✅
---

-  SurrealDB
- ✅
- ✅
- ✅
- ✅
- ✅
---

-  Elasticsearch
- ✅
- ✅
- ✅
- ✅
- ✅

---