Skip to content

Commit

Permalink
Merge pull request #1466 from gofr-dev/release/v1.33.0
Browse files Browse the repository at this point in the history
Release/v1.33.0
  • Loading branch information
Umang01-hash authored Feb 6, 2025
2 parents aae7488 + 7aee6ab commit d6cd85a
Show file tree
Hide file tree
Showing 64 changed files with 5,690 additions and 432 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ jobs:
uses: actions/checkout@v4

- name: Set up Go environment
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version: '1.22'
cache: false
Expand All @@ -251,7 +251,7 @@ jobs:
go mod tidy
- name: Lint Root Module
uses: golangci/golangci-lint-action@v3
uses: golangci/golangci-lint-action@v6
with:
version: v1.62
working-directory: .
Expand Down
5 changes: 5 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ docker pull scylladb/scylla
docker run --name scylla -d -p 2025:9042 scylladb/scylla
docker pull surrealdb/surrealdb:latest
docker run --name surrealdb -d -p 8000:8000 surrealdb/surrealdb:latest start --bind 0.0.0.0:8000
docker run -d --name arangodb \
-p 8529:8529 \
-e ARANGO_ROOT_PASSWORD=rootpassword \
--pull always \
arangodb:latest



Expand Down
6 changes: 3 additions & 3 deletions docs/advanced-guide/custom-spans-in-tracing/page.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Custom Spans In Tracing

GoFr's built-in tracing provides valuable insights into application's behavior. However, sometimes you might need
GoFr's built-in tracing provides valuable insights into application's behavior. However, sometimes we might need
even more granular details about specific operations within your application. This is where `custom spans` can be used.

## How it helps?
By adding custom spans in traces to your requests, you can:
By adding custom spans in traces to our requests, we can:

- **Gain granular insights:** Custom spans allow you to track specific operations or functions within your application,
- **Gain granular insights:** Custom spans allows us to track specific operations or functions within your application,
providing detailed performance data.
- **Identify bottlenecks:** Analyzing custom spans helps to pinpoint areas of your code that may be causing
performance bottlenecks or inefficiencies.
Expand Down
2 changes: 1 addition & 1 deletion docs/advanced-guide/gofr-errors/page.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ dbErr2 := datasource.ErrorDB{Message : "database connection timed out!"}
GoFr's error structs implements an interface with `Error() string` and `StatusCode() int` methods, users can override the
status code by implementing it for their custom error.

You can optionally define a log level for your error with the `LogLevel() logging.Level` methods
Users can optionally define a log level for your error with the `LogLevel() logging.Level` methods

#### Usage:
```go
Expand Down
45 changes: 40 additions & 5 deletions docs/advanced-guide/grpc/page.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
We have already seen how GoFr can help ease the development of HTTP servers, but there are cases where performance is primarily required sacrificing flexibility. In these types of scenarios gRPC protocol comes into picture. {% new-tab-link title="gRPC" href="https://grpc.io/docs/what-is-grpc/introduction/" /%} is an open-source RPC(Remote Procedure Call) framework initially developed by Google.

GoFr streamlines the creation of gRPC servers and clients with unified GoFr's context support.
It provides built-in tracing, metrics, and logging to ensure seamless performance monitoring for both
gRPC servers and inter-service gRPC communication. Using GoFr's context, you can easily define custom metrics and
traces across gRPC handlers, enabling consistent observability and simplified debugging throughout your system.
It provides built-in tracing, metrics, and logging to ensure seamless performance monitoring for both gRPC servers and inter-service gRPC communication.
With GoFr's context, you can seamlessly define custom metrics and traces across gRPC handlers, ensuring consistent observability and streamlined debugging throughout
your system. Additionally, GoFr provides a built-in health check for all your services and supports inter-service
health checks, allowing gRPC services to monitor each other effortlessly.

## Prerequisites

Expand Down Expand Up @@ -137,15 +138,15 @@ import (
func main() {
app := gofr.New()

packageName.Register{serviceName}ServerWithGofr(app, &{packageName}.{serviceName}GoFrServer{})
packageName.Register{serviceName}ServerWithGofr(app, &{packageName}.New{serviceName}GoFrServer())

app.Run()
}
```

>Note: By default, gRPC server will run on port 9000, to customize the port users can set `GRPC_PORT` config in the .env
## Generating tracing enabled gRPC Client using `gofr wrap grpc client`
## Generating gRPC Client using `gofr wrap grpc client`

**1. Use the `gofr wrap grpc client` Command:**
```bash
Expand Down Expand Up @@ -178,4 +179,38 @@ return nil, err
return res, nil
}
```

## HealthChecks in GoFr's gRPC Service/Clients
Health Checks in GoFr's gRPC Services

GoFr provides built-in health checks for gRPC services, enabling observability, monitoring, and inter-service health verification.

### Client Interface

```go
type {serviceName}GoFrClient interface {
SayHello(*gofr.Context, *HelloRequest, ...grpc.CallOption) (*HelloResponse, error)
health
}

type health interface {
Check(ctx *gofr.Context, in *grpc_health_v1.HealthCheckRequest, opts ...grpc.CallOption) (*grpc_health_v1.HealthCheckResponse, error)
Watch(ctx *gofr.Context, in *grpc_health_v1.HealthCheckRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[grpc_health_v1.HealthCheckResponse], error)
}
```

### Server Integration
```go
type {serviceName}GoFrServer struct {
health *healthServer
}
```
Supported Methods for HealthCheck :
```go
func (h *healthServer) Check(ctx *gofr.Context, req *grpc_health_v1.HealthCheckRequest) (*grpc_health_v1.HealthCheckResponse, error)
func (h *healthServer) Watch(ctx *gofr.Context, in *grpc_health_v1.HealthCheckRequest, stream grpc_health_v1.Health_WatchServer) error
func (h *healthServer) SetServingStatus(ctx *gofr.Context, service string, status grpc_health_v1.HealthCheckResponse_ServingStatus)
func (h *healthServer) Shutdown(ctx *gofr.Context)
func (h *healthServer) Resume(ctx *gofr.Context)
```
> ##### Check out the example of setting up a gRPC server/client in GoFr: [Visit GitHub](https://github.com/gofr-dev/gofr/tree/main/examples/grpc)
193 changes: 189 additions & 4 deletions docs/advanced-guide/injecting-databases-drivers/page.md
Original file line number Diff line number Diff line change
Expand Up @@ -908,11 +908,11 @@ func main() {
app.AddSurrealDB(client)

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

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

Expand All @@ -925,14 +925,14 @@ func main() {
})

// POST request to create a new person
app.POST("/person", func(ctx *gofr.Context) (interface{}, error) {
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]interface{}{
result, err := ctx.SurrealDB.Create(ctx, "person", map[string]any{
"name": person.Name,
"age": person.Age,
"email": person.Email,
Expand All @@ -949,3 +949,188 @@ func main() {
}

```


## ArangoDB

GoFr supports injecting `ArangoDB` that implements the following interface. Any driver that implements the interface can be
added using the `app.AddArangoDB()` method, and users can use ArangoDB across the application with `gofr.Context`.

```go
type ArangoDB interface {
// CreateDocument creates a new document in the specified collection.
CreateDocument(ctx context.Context, dbName, collectionName string, document any) (string, error)
// GetDocument retrieves a document by its ID from the specified collection.
GetDocument(ctx context.Context, dbName, collectionName, documentID string, result any) error
// UpdateDocument updates an existing document in the specified collection.
UpdateDocument(ctx context.Context, dbName, collectionName, documentID string, document any) error
// DeleteDocument deletes a document by its ID from the specified collection.
DeleteDocument(ctx context.Context, dbName, collectionName, documentID string) error

// GetEdges retrieves all the edge documents connected to a specific vertex in an ArangoDB graph.
GetEdges(ctx context.Context, dbName, graphName, edgeCollection, vertexID string, resp any) error

// Query executes an AQL query and binds the results
Query(ctx context.Context, dbName string, query string, bindVars map[string]any, result any) error

HealthCheck(context.Context) (any, error)
}
```

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

Import the GoFr's external driver for ArangoDB:

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

### Example

```go
package main

import (
"fmt"

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

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

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

// Configure the ArangoDB client
arangoClient := arangodb.New(arangodb.Config{
Host: "localhost",
User: "root",
Password: "root",
Port: 8529,
})
app.AddArangoDB(arangoClient)

// Example routes demonstrating different types of operations
app.POST("/setup", Setup)
app.POST("/users/{name}", CreateUserHandler)
app.POST("/friends", CreateFriendship)
app.GET("/friends/{collection}/{vertexID}", GetEdgesHandler)

app.Run()
}

// Setup demonstrates database and collection creation
func Setup(ctx *gofr.Context) (interface{}, error) {
_, err := ctx.ArangoDB.CreateDocument(ctx, "social_network", "", nil)
if err != nil {
return nil, fmt.Errorf("failed to create database: %w", err)
}

if err := createCollection(ctx, "social_network", "persons"); err != nil {
return nil, err
}
if err := createCollection(ctx, "social_network", "friendships"); err != nil {
return nil, err
}

// Define and create the graph
edgeDefs := arangodb.EdgeDefinition{
{Collection: "friendships", From: []string{"persons"}, To: []string{"persons"}},
}

_, err = ctx.ArangoDB.CreateDocument(ctx, "social_network", "social_graph", edgeDefs)
if err != nil {
return nil, fmt.Errorf("failed to create graph: %w", err)
}

return "Setup completed successfully", nil
}

// Helper function to create collections
func createCollection(ctx *gofr.Context, dbName, collectionName string) error {
_, err := ctx.ArangoDB.CreateDocument(ctx, dbName, collectionName, nil)
if err != nil {
return fmt.Errorf("failed to create collection %s: %w", collectionName, err)
}
return nil
}

// CreateUserHandler demonstrates user management and document creation
func CreateUserHandler(ctx *gofr.Context) (interface{}, error) {
name := ctx.PathParam("name")

// Create a person document
person := Person{
Name: name,
Age: 25,
}
docID, err := ctx.ArangoDB.CreateDocument(ctx, "social_network", "persons", person)
if err != nil {
return nil, fmt.Errorf("failed to create person document: %w", err)
}

return map[string]string{
"message": "User created successfully",
"docID": docID,
}, nil
}

// CreateFriendship demonstrates edge document creation
func CreateFriendship(ctx *gofr.Context) (interface{}, error) {
var req struct {
From string `json:"from"`
To string `json:"to"`
StartDate string `json:"startDate"`
}

if err := ctx.Bind(&req); err != nil {
return nil, err
}

edgeDocument := map[string]any{
"_from": fmt.Sprintf("persons/%s", req.From),
"_to": fmt.Sprintf("persons/%s", req.To),
"startDate": req.StartDate,
}

// Create an edge document for the friendship
edgeID, err := ctx.ArangoDB.CreateDocument(ctx, "social_network", "friendships", edgeDocument)
if err != nil {
return nil, fmt.Errorf("failed to create friendship: %w", err)
}

return map[string]string{
"message": "Friendship created successfully",
"edgeID": edgeID,
}, nil
}

// GetEdgesHandler demonstrates fetching edges connected to a vertex
func GetEdgesHandler(ctx *gofr.Context) (interface{}, error) {
collection := ctx.PathParam("collection")
vertexID := ctx.PathParam("vertexID")

fullVertexID := fmt.Sprintf("%s/%s", collection, vertexID)

// Prepare a slice to hold edge details
edges := make(arangodb.EdgeDetails, 0)

// Fetch all edges connected to the given vertex
err := ctx.ArangoDB.GetEdges(ctx, "social_network", "social_graph", "friendships",
fullVertexID, &edges)
if err != nil {
return nil, fmt.Errorf("failed to get edges: %w", err)
}

return map[string]interface{}{
"vertexID": vertexID,
"edges": edges,
}, nil
}
```


6 changes: 3 additions & 3 deletions docs/advanced-guide/publishing-custom-metrics/page.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func main() {

## Adding Labels to Custom Metrics

GoFr leverages metrics support by enabling labels. Labels are a key feature in metrics that allow you to categorize and filter metrics based on relevant information.
GoFr leverages metrics support by enabling labels. Labels are a key feature in metrics that allows us to categorize and filter metrics based on relevant information.

### Understanding Labels

Expand All @@ -152,7 +152,7 @@ Common examples of labels include:
- service: (e.g., "api-gateway", "database")
- status: (e.g., "success", "failure")

By adding labels, you can create different time series for the same metric based on the label values.
By adding labels, we can create different time series for the same metric based on the label values.
This allows for more granular analysis and visualization in Grafana (or any other) dashboards.

### Additional Considerations
Expand All @@ -161,7 +161,7 @@ This allows for more granular analysis and visualization in Grafana (or any othe
- Choose meaningful label names that clearly describe the data point.
- Ensure consistency in label naming conventions across your application.

By effectively using labels in GoFr, you can enrich your custom metrics and gain deeper insights into your application's performance and behavior.
By effectively using labels in GoFr, we can enrich your custom metrics and gain deeper insights into your application's performance and behavior.

### Usage:

Expand Down
2 changes: 1 addition & 1 deletion docs/advanced-guide/using-publisher-subscriber/page.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ MQTT_USER=username // authentication username
MQTT_PASSWORD=password // authentication password
```
> **Note** : If `MQTT_HOST` config is not provided, the application will connect to a public broker
> {% new-tab-link title="HiveMQ" href="https://www.hivemq.com/mqtt/public-mqtt-broker/" /%}
> {% new-tab-link title="EMQX Broker" href="https://www.emqx.com/en/mqtt/public-mqtt5-broker" /%}
#### Docker setup
```shell
Expand Down
Loading

0 comments on commit d6cd85a

Please sign in to comment.