Skip to content

Commit

Permalink
Merge pull request #1247 from gofr-dev/release/v1.28.0
Browse files Browse the repository at this point in the history
Release/v1.28.0
  • Loading branch information
Umang01-hash authored Nov 27, 2024
2 parents 9a97ec5 + 89b51e1 commit 4df66c5
Show file tree
Hide file tree
Showing 86 changed files with 3,827 additions and 369 deletions.
4 changes: 4 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,12 @@ Some services will be required to pass the entire test suite. We recommend using

docker run --name mongodb -d -p 27017:27017 -e MONGO_INITDB_ROOT_USERNAME=user -e MONGO_INITDB_ROOT_PASSWORD=password mongodb/mongodb-community-server:latest
docker run -d -p 21:21 -p 21000-21010:21000-21010 -e USERS='user|password' delfer/alpine-ftp-server
// the docker image is relatively unstable. Alternatively, refer to official guide of OpenTSDB to locally setup OpenTSDB env.
// http://opentsdb.net/docs/build/html/installation.html#id1
docker run -d --name gofr-opentsdb -p 4242:4242 petergrace/opentsdb-docker:latest
docker run --name gofr-mysql -e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=test -p 2001:3306 -d mysql:8.0.30
docker run --name gofr-redis -p 2002:6379 -d redis:7.0.5
docker run --name gofr-solr -p 2020:8983 solr -DzkRun
docker run --name gofr-zipkin -d -p 2005:9411 openzipkin/zipkin:2
docker run --rm -it -p 4566:4566 -p 4510-4559:4510-4559 localstack/localstack
docker run --name cassandra-node -d -p 9042:9042 -v cassandra_data:/var/lib/cassandra cassandra:latest
Expand Down
246 changes: 244 additions & 2 deletions docs/advanced-guide/injecting-databases-drivers/page.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ type Clickhouse interface {

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 ClickHouse:

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

### Example
```go
package main
Expand Down Expand Up @@ -104,6 +111,13 @@ type Mongo interface {

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 MongoDB:

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

### Example
```go
package main
Expand All @@ -124,7 +138,7 @@ type Person struct {
func main() {
app := gofr.New()

db := mongo.New(Config{URI: "mongodb://localhost:27017", Database: "test"})
db := mongo.New(Config{URI: "mongodb://localhost:27017", Database: "test",ConnectionTimeout: 4*time.Second})

// inject the mongo into gofr to use mongoDB across the application
// using gofr context
Expand Down Expand Up @@ -197,6 +211,12 @@ type CassandraBatchWithContext interface {
GoFr simplifies Cassandra integration with a well-defined interface. Users can easily implement any driver that adheres
to this interface, fostering a user-friendly experience.

Import the gofr's external driver for Cassandra:

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

### Example

```go
Expand Down Expand Up @@ -291,6 +311,12 @@ type Dgraph interface {
Users can easily inject a driver that supports this interface, allowing for flexibility without compromising usability.
This structure supports both queries and mutations in Dgraph.

Import the gofr's external driver for DGraph:

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

### Example

```go
Expand Down Expand Up @@ -408,6 +434,15 @@ type Solr interface {
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

Expand Down Expand Up @@ -440,7 +475,7 @@ type Person struct {
}

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

resp, err := c.Solr.Create(c, "test", bytes.NewBuffer(body), nil)
Expand Down Expand Up @@ -471,3 +506,210 @@ func get(c *gofr.Context) (interface{}, error) {
return resp, nil
}
```

## OpenTSDB
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`.

```go
// OpenTSDB provides methods for GoFr applications to communicate with OpenTSDB
// through its REST APIs.
type OpenTSDB interface {

// HealthChecker verifies if the OpenTSDB server is reachable.
// Returns an error if the server is unreachable, otherwise nil.
HealthChecker

// PutDataPoints sends data to store metrics in OpenTSDB.
//
// Parameters:
// - ctx: Context for managing request lifetime.
// - data: A slice of DataPoint objects; must contain at least one entry.
// - queryParam: Specifies the response format:
// - client.PutRespWithSummary: Requests a summary response.
// - client.PutRespWithDetails: Requests detailed response information.
// - Empty string (""): No additional response details.
// - res: A pointer to PutResponse, where the server's response will be stored.
//
// Returns:
// - Error if parameters are invalid, response parsing fails, or if connectivity issues occur.
PutDataPoints(ctx context.Context, data any, queryParam string, res any) error

// QueryDataPoints retrieves data based on the specified parameters.
//
// Parameters:
// - ctx: Context for managing request lifetime.
// - param: An instance of QueryParam with query parameters for filtering data.
// - res: A pointer to QueryResponse, where the server's response will be stored.
QueryDataPoints(ctx context.Context, param any, res any) error

// QueryLatestDataPoints fetches the latest data point(s).
//
// Parameters:
// - ctx: Context for managing request lifetime.
// - param: An instance of QueryLastParam with query parameters for the latest data point.
// - res: A pointer to QueryLastResponse, where the server's response will be stored.
QueryLatestDataPoints(ctx context.Context, param any, res any) error

// GetAggregators retrieves available aggregation functions.
//
// Parameters:
// - ctx: Context for managing request lifetime.
// - res: A pointer to AggregatorsResponse, where the server's response will be stored.
GetAggregators(ctx context.Context, res any) error

// QueryAnnotation retrieves a single annotation.
//
// Parameters:
// - ctx: Context for managing request lifetime.
// - queryAnnoParam: A map of parameters for the annotation query, such as client.AnQueryStartTime, client.AnQueryTSUid.
// - res: A pointer to AnnotationResponse, where the server's response will be stored.
QueryAnnotation(ctx context.Context, queryAnnoParam map[string]any, res any) error

// PostAnnotation creates or updates an annotation.
//
// Parameters:
// - ctx: Context for managing request lifetime.
// - annotation: The annotation to be created or updated.
// - res: A pointer to AnnotationResponse, where the server's response will be stored.
PostAnnotation(ctx context.Context, annotation any, res any) error

// PutAnnotation creates or replaces an annotation.
// Fields not included in the request will be reset to default values.
//
// Parameters:
// - ctx: Context for managing request lifetime.
// - annotation: The annotation to be created or replaced.
// - res: A pointer to AnnotationResponse, where the server's response will be stored.
PutAnnotation(ctx context.Context, annotation any, res any) error

// DeleteAnnotation removes an annotation.
//
// Parameters:
// - ctx: Context for managing request lifetime.
// - annotation: The annotation to be deleted.
// - res: A pointer to AnnotationResponse, where the server's response will be stored.
DeleteAnnotation(ctx context.Context, annotation any, res any) error
}
```

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.
```go
package main

import (
"context"
"fmt"
"math/rand/v2"
"time"

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

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

// Initialize OpenTSDB connection
app.AddOpenTSDB(opentsdb.New(&opentsdb.Config{
Host: "localhost:4242",
MaxContentLength: 4096,
MaxPutPointsNum: 1000,
DetectDeltaNum: 10,
}))

// Register routes
app.GET("/health", opentsdbHealthCheck)
app.POST("/write", writeDataPoints)
app.GET("/query", queryDataPoints)
// Run the app
app.Run()
}

// Health check for OpenTSDB
func opentsdbHealthCheck(c *gofr.Context) (any, error) {
res, err := c.OpenTSDB.HealthCheck(context.Background())
if err != nil {
return nil, err
}
return res, nil
}

// Write Data Points to OpenTSDB
func writeDataPoints(c *gofr.Context) (any, error) {
PutDataPointNum := 4
name := []string{"cpu", "disk", "net", "mem"}
cpuDatas := make([]opentsdb.DataPoint, 0)

tags := map[string]string{
"host": "gofr-host",
"try-name": "gofr-sample",
"demo-name": "opentsdb-test",
}

for i := 0; i < PutDataPointNum; i++ {
data := opentsdb.DataPoint{
Metric: name[i%len(name)],
Timestamp: time.Now().Unix(),
Value: rand.Float64() * 100,
Tags: tags,
}
cpuDatas = append(cpuDatas, data)
}

resp := opentsdb.PutResponse{}

err := c.OpenTSDB.PutDataPoints(context.Background(), cpuDatas, "details", &resp)
if err != nil {
return resp.Errors, err
}

return fmt.Sprintf("%v Data points written successfully", resp.Success), nil
}

// Query Data Points from OpenTSDB
func queryDataPoints(c *gofr.Context) (any, error) {
st1 := time.Now().Unix() - 3600
st2 := time.Now().Unix()

queryParam := opentsdb.QueryParam{
Start: st1,
End: st2,
}

name := []string{"cpu", "disk", "net", "mem"}
subqueries := make([]opentsdb.SubQuery, 0)
tags := map[string]string{
"host": "gofr-host",
"try-name": "gofr-sample",
"demo-name": "opentsdb-test",
}

for _, metric := range name {
subQuery := opentsdb.SubQuery{
Aggregator: "sum",
Metric: metric,
Tags: tags,
}
subqueries = append(subqueries, subQuery)
}

queryParam.Queries = subqueries

queryResp := &opentsdb.QueryResponse{}

err := c.OpenTSDB.QueryDataPoints(c, &queryParam, queryResp)
if err != nil {
return nil, err
}
return queryResp.QueryRespCnts, nil
}
```
7 changes: 7 additions & 0 deletions docs/advanced-guide/key-value-store/page.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ using `app.AddKVStore()` method, and user's can use BadgerDB across application

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 BadgerDB:

```go
go get gofr.dev/pkg/gofr/datasource/kv-store/badger
```

### Example
```go
package main
Expand Down
53 changes: 0 additions & 53 deletions docs/advanced-guide/middlewares/page.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,56 +67,3 @@ func main() {
}
```

### Using UseMiddlewareWithContainer for Custom Middleware with Container Access

The UseMiddlewareWithContainer method allows middleware to access the application's container, providing access to
services like logging, configuration, and databases. This method is especially useful for middleware that needs access
to resources in the container to modify request processing flow.

#### Example:

```go
import (
"fmt"
"net/http"

"gofr.dev/pkg/gofr"
"gofr.dev/pkg/gofr/container"
)

func main() {
// Create a new GoFr application instance
a := gofr.New()

// Add custom middleware with container access
a.UseMiddlewareWithContainer(customMiddleware)

// Define the application's routes
a.GET("/hello", HelloHandler)

// Run the application
a.Run()
}

// Define middleware with container access
func customMiddleware(c *container.Container, handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
c.Logger.Log("Hey! Welcome to GoFr")

// Continue with the request processing
handler.ServeHTTP(w, r)
})
}

// Sample handler function
func HelloHandler(c *gofr.Context) (interface{}, error) {
name := c.Param("name")
if name == "" {
c.Log("Name came empty")
name = "World"
}

return fmt.Sprintf("Hello %s!", name), nil
}
```

Loading

0 comments on commit 4df66c5

Please sign in to comment.