Skip to content

Commit d6cd85a

Browse files
authored
Merge pull request #1466 from gofr-dev/release/v1.33.0
Release/v1.33.0
2 parents aae7488 + 7aee6ab commit d6cd85a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+5690
-432
lines changed

Diff for: .github/workflows/go.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ jobs:
241241
uses: actions/checkout@v4
242242

243243
- name: Set up Go environment
244-
uses: actions/setup-go@v4
244+
uses: actions/setup-go@v5
245245
with:
246246
go-version: '1.22'
247247
cache: false
@@ -251,7 +251,7 @@ jobs:
251251
go mod tidy
252252
253253
- name: Lint Root Module
254-
uses: golangci/golangci-lint-action@v3
254+
uses: golangci/golangci-lint-action@v6
255255
with:
256256
version: v1.62
257257
working-directory: .

Diff for: CONTRIBUTING.md

+5
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ docker pull scylladb/scylla
8383
docker run --name scylla -d -p 2025:9042 scylladb/scylla
8484
docker pull surrealdb/surrealdb:latest
8585
docker run --name surrealdb -d -p 8000:8000 surrealdb/surrealdb:latest start --bind 0.0.0.0:8000
86+
docker run -d --name arangodb \
87+
-p 8529:8529 \
88+
-e ARANGO_ROOT_PASSWORD=rootpassword \
89+
--pull always \
90+
arangodb:latest
8691

8792

8893

Diff for: docs/advanced-guide/custom-spans-in-tracing/page.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
# Custom Spans In Tracing
22

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

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

9-
- **Gain granular insights:** Custom spans allow you to track specific operations or functions within your application,
9+
- **Gain granular insights:** Custom spans allows us to track specific operations or functions within your application,
1010
providing detailed performance data.
1111
- **Identify bottlenecks:** Analyzing custom spans helps to pinpoint areas of your code that may be causing
1212
performance bottlenecks or inefficiencies.

Diff for: docs/advanced-guide/gofr-errors/page.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ dbErr2 := datasource.ErrorDB{Message : "database connection timed out!"}
4444
GoFr's error structs implements an interface with `Error() string` and `StatusCode() int` methods, users can override the
4545
status code by implementing it for their custom error.
4646

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

4949
#### Usage:
5050
```go

Diff for: docs/advanced-guide/grpc/page.md

+40-5
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
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.
44

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

1011
## Prerequisites
1112

@@ -137,15 +138,15 @@ import (
137138
func main() {
138139
app := gofr.New()
139140

140-
packageName.Register{serviceName}ServerWithGofr(app, &{packageName}.{serviceName}GoFrServer{})
141+
packageName.Register{serviceName}ServerWithGofr(app, &{packageName}.New{serviceName}GoFrServer())
141142

142143
app.Run()
143144
}
144145
```
145146

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

150151
**1. Use the `gofr wrap grpc client` Command:**
151152
```bash
@@ -178,4 +179,38 @@ return nil, err
178179
return res, nil
179180
}
180181
```
182+
183+
## HealthChecks in GoFr's gRPC Service/Clients
184+
Health Checks in GoFr's gRPC Services
185+
186+
GoFr provides built-in health checks for gRPC services, enabling observability, monitoring, and inter-service health verification.
187+
188+
### Client Interface
189+
190+
```go
191+
type {serviceName}GoFrClient interface {
192+
SayHello(*gofr.Context, *HelloRequest, ...grpc.CallOption) (*HelloResponse, error)
193+
health
194+
}
195+
196+
type health interface {
197+
Check(ctx *gofr.Context, in *grpc_health_v1.HealthCheckRequest, opts ...grpc.CallOption) (*grpc_health_v1.HealthCheckResponse, error)
198+
Watch(ctx *gofr.Context, in *grpc_health_v1.HealthCheckRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[grpc_health_v1.HealthCheckResponse], error)
199+
}
200+
```
201+
202+
### Server Integration
203+
```go
204+
type {serviceName}GoFrServer struct {
205+
health *healthServer
206+
}
207+
```
208+
Supported Methods for HealthCheck :
209+
```go
210+
func (h *healthServer) Check(ctx *gofr.Context, req *grpc_health_v1.HealthCheckRequest) (*grpc_health_v1.HealthCheckResponse, error)
211+
func (h *healthServer) Watch(ctx *gofr.Context, in *grpc_health_v1.HealthCheckRequest, stream grpc_health_v1.Health_WatchServer) error
212+
func (h *healthServer) SetServingStatus(ctx *gofr.Context, service string, status grpc_health_v1.HealthCheckResponse_ServingStatus)
213+
func (h *healthServer) Shutdown(ctx *gofr.Context)
214+
func (h *healthServer) Resume(ctx *gofr.Context)
215+
```
181216
> ##### 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)

Diff for: docs/advanced-guide/injecting-databases-drivers/page.md

+189-4
Original file line numberDiff line numberDiff line change
@@ -908,11 +908,11 @@ func main() {
908908
app.AddSurrealDB(client)
909909

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

914914
query := "SELECT * FROM type::thing('person', $id)"
915-
vars := map[string]interface{}{
915+
vars := map[string]any{
916916
"id": id,
917917
}
918918

@@ -925,14 +925,14 @@ func main() {
925925
})
926926

927927
// POST request to create a new person
928-
app.POST("/person", func(ctx *gofr.Context) (interface{}, error) {
928+
app.POST("/person", func(ctx *gofr.Context) (any, error) {
929929
var person Person
930930

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

935-
result, err := ctx.SurrealDB.Create(ctx, "person", map[string]interface{}{
935+
result, err := ctx.SurrealDB.Create(ctx, "person", map[string]any{
936936
"name": person.Name,
937937
"age": person.Age,
938938
"email": person.Email,
@@ -949,3 +949,188 @@ func main() {
949949
}
950950

951951
```
952+
953+
954+
## ArangoDB
955+
956+
GoFr supports injecting `ArangoDB` that implements the following interface. Any driver that implements the interface can be
957+
added using the `app.AddArangoDB()` method, and users can use ArangoDB across the application with `gofr.Context`.
958+
959+
```go
960+
type ArangoDB interface {
961+
// CreateDocument creates a new document in the specified collection.
962+
CreateDocument(ctx context.Context, dbName, collectionName string, document any) (string, error)
963+
// GetDocument retrieves a document by its ID from the specified collection.
964+
GetDocument(ctx context.Context, dbName, collectionName, documentID string, result any) error
965+
// UpdateDocument updates an existing document in the specified collection.
966+
UpdateDocument(ctx context.Context, dbName, collectionName, documentID string, document any) error
967+
// DeleteDocument deletes a document by its ID from the specified collection.
968+
DeleteDocument(ctx context.Context, dbName, collectionName, documentID string) error
969+
970+
// GetEdges retrieves all the edge documents connected to a specific vertex in an ArangoDB graph.
971+
GetEdges(ctx context.Context, dbName, graphName, edgeCollection, vertexID string, resp any) error
972+
973+
// Query executes an AQL query and binds the results
974+
Query(ctx context.Context, dbName string, query string, bindVars map[string]any, result any) error
975+
976+
HealthCheck(context.Context) (any, error)
977+
}
978+
```
979+
980+
Users can easily inject a driver that supports this interface, providing usability without compromising the extensibility to use multiple databases.
981+
982+
Import the GoFr's external driver for ArangoDB:
983+
984+
```shell
985+
go get gofr.dev/pkg/gofr/datasource/arangodb@latest
986+
```
987+
988+
### Example
989+
990+
```go
991+
package main
992+
993+
import (
994+
"fmt"
995+
996+
"gofr.dev/pkg/gofr"
997+
"gofr.dev/pkg/gofr/datasource/arangodb"
998+
)
999+
1000+
type Person struct {
1001+
Name string `json:"name"`
1002+
Age int `json:"age"`
1003+
}
1004+
1005+
func main() {
1006+
app := gofr.New()
1007+
1008+
// Configure the ArangoDB client
1009+
arangoClient := arangodb.New(arangodb.Config{
1010+
Host: "localhost",
1011+
User: "root",
1012+
Password: "root",
1013+
Port: 8529,
1014+
})
1015+
app.AddArangoDB(arangoClient)
1016+
1017+
// Example routes demonstrating different types of operations
1018+
app.POST("/setup", Setup)
1019+
app.POST("/users/{name}", CreateUserHandler)
1020+
app.POST("/friends", CreateFriendship)
1021+
app.GET("/friends/{collection}/{vertexID}", GetEdgesHandler)
1022+
1023+
app.Run()
1024+
}
1025+
1026+
// Setup demonstrates database and collection creation
1027+
func Setup(ctx *gofr.Context) (interface{}, error) {
1028+
_, err := ctx.ArangoDB.CreateDocument(ctx, "social_network", "", nil)
1029+
if err != nil {
1030+
return nil, fmt.Errorf("failed to create database: %w", err)
1031+
}
1032+
1033+
if err := createCollection(ctx, "social_network", "persons"); err != nil {
1034+
return nil, err
1035+
}
1036+
if err := createCollection(ctx, "social_network", "friendships"); err != nil {
1037+
return nil, err
1038+
}
1039+
1040+
// Define and create the graph
1041+
edgeDefs := arangodb.EdgeDefinition{
1042+
{Collection: "friendships", From: []string{"persons"}, To: []string{"persons"}},
1043+
}
1044+
1045+
_, err = ctx.ArangoDB.CreateDocument(ctx, "social_network", "social_graph", edgeDefs)
1046+
if err != nil {
1047+
return nil, fmt.Errorf("failed to create graph: %w", err)
1048+
}
1049+
1050+
return "Setup completed successfully", nil
1051+
}
1052+
1053+
// Helper function to create collections
1054+
func createCollection(ctx *gofr.Context, dbName, collectionName string) error {
1055+
_, err := ctx.ArangoDB.CreateDocument(ctx, dbName, collectionName, nil)
1056+
if err != nil {
1057+
return fmt.Errorf("failed to create collection %s: %w", collectionName, err)
1058+
}
1059+
return nil
1060+
}
1061+
1062+
// CreateUserHandler demonstrates user management and document creation
1063+
func CreateUserHandler(ctx *gofr.Context) (interface{}, error) {
1064+
name := ctx.PathParam("name")
1065+
1066+
// Create a person document
1067+
person := Person{
1068+
Name: name,
1069+
Age: 25,
1070+
}
1071+
docID, err := ctx.ArangoDB.CreateDocument(ctx, "social_network", "persons", person)
1072+
if err != nil {
1073+
return nil, fmt.Errorf("failed to create person document: %w", err)
1074+
}
1075+
1076+
return map[string]string{
1077+
"message": "User created successfully",
1078+
"docID": docID,
1079+
}, nil
1080+
}
1081+
1082+
// CreateFriendship demonstrates edge document creation
1083+
func CreateFriendship(ctx *gofr.Context) (interface{}, error) {
1084+
var req struct {
1085+
From string `json:"from"`
1086+
To string `json:"to"`
1087+
StartDate string `json:"startDate"`
1088+
}
1089+
1090+
if err := ctx.Bind(&req); err != nil {
1091+
return nil, err
1092+
}
1093+
1094+
edgeDocument := map[string]any{
1095+
"_from": fmt.Sprintf("persons/%s", req.From),
1096+
"_to": fmt.Sprintf("persons/%s", req.To),
1097+
"startDate": req.StartDate,
1098+
}
1099+
1100+
// Create an edge document for the friendship
1101+
edgeID, err := ctx.ArangoDB.CreateDocument(ctx, "social_network", "friendships", edgeDocument)
1102+
if err != nil {
1103+
return nil, fmt.Errorf("failed to create friendship: %w", err)
1104+
}
1105+
1106+
return map[string]string{
1107+
"message": "Friendship created successfully",
1108+
"edgeID": edgeID,
1109+
}, nil
1110+
}
1111+
1112+
// GetEdgesHandler demonstrates fetching edges connected to a vertex
1113+
func GetEdgesHandler(ctx *gofr.Context) (interface{}, error) {
1114+
collection := ctx.PathParam("collection")
1115+
vertexID := ctx.PathParam("vertexID")
1116+
1117+
fullVertexID := fmt.Sprintf("%s/%s", collection, vertexID)
1118+
1119+
// Prepare a slice to hold edge details
1120+
edges := make(arangodb.EdgeDetails, 0)
1121+
1122+
// Fetch all edges connected to the given vertex
1123+
err := ctx.ArangoDB.GetEdges(ctx, "social_network", "social_graph", "friendships",
1124+
fullVertexID, &edges)
1125+
if err != nil {
1126+
return nil, fmt.Errorf("failed to get edges: %w", err)
1127+
}
1128+
1129+
return map[string]interface{}{
1130+
"vertexID": vertexID,
1131+
"edges": edges,
1132+
}, nil
1133+
}
1134+
```
1135+
1136+

Diff for: docs/advanced-guide/publishing-custom-metrics/page.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ func main() {
141141

142142
## Adding Labels to Custom Metrics
143143

144-
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.
144+
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.
145145

146146
### Understanding Labels
147147

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

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

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

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

166166
### Usage:
167167

Diff for: docs/advanced-guide/using-publisher-subscriber/page.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ MQTT_USER=username // authentication username
164164
MQTT_PASSWORD=password // authentication password
165165
```
166166
> **Note** : If `MQTT_HOST` config is not provided, the application will connect to a public broker
167-
> {% new-tab-link title="HiveMQ" href="https://www.hivemq.com/mqtt/public-mqtt-broker/" /%}
167+
> {% new-tab-link title="EMQX Broker" href="https://www.emqx.com/en/mqtt/public-mqtt5-broker" /%}
168168
169169
#### Docker setup
170170
```shell

0 commit comments

Comments
 (0)