Skip to content

Commit c72bc69

Browse files
committed
Merge branch 'main' of github.com:gofr-dev/gofr
2 parents ab76d66 + 8ea784b commit c72bc69

37 files changed

+1273
-188
lines changed

Diff for: .github/workflows/go.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,6 @@ jobs:
374374

375375
# Check file naming conventions using ls-lint
376376
- name: Check for file names errors
377-
uses: ls-lint/action@v2.2.3
377+
uses: ls-lint/action@v2.3.0
378378
with:
379379
config: .ls-lint.yml

Diff for: README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -137,4 +137,4 @@ If your PR is merged, or if you contribute by writing articles or promoting GoFr
137137

138138
### Partners
139139

140-
<img src="https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.png" alt="JetBrains logo" width="200">
140+
<img src="https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.png" alt="JetBrains logo" width="200">

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

+180-25
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ syntax = "proto3";
5656
option go_package = "path/to/your/proto/file";
5757
5858
service {serviceName}Service {
59-
rpc {serviceMethod} ({serviceRequest}) returns ({serviceResponse}) {}
59+
rpc {serviceMethod} ({serviceRequest}) returns ({serviceResponse}) {}
6060
}
6161
```
6262

@@ -67,16 +67,16 @@ procedure call. Below is a generic representation for services' gRPC messages ty
6767

6868
```protobuf
6969
message {serviceRequest} {
70-
int64 id = 1;
71-
string name = 2;
72-
// other fields that can be passed
70+
int64 id = 1;
71+
string name = 2;
72+
// other fields that can be passed
7373
}
7474
7575
message {serviceResponse} {
76-
int64 id = 1;
77-
string name = 2;
78-
string address = 3;
79-
// other customer related fields
76+
int64 id = 1;
77+
string name = 2;
78+
string address = 3;
79+
// other customer related fields
8080
}
8181
```
8282

@@ -146,6 +146,56 @@ func main() {
146146

147147
>Note: By default, gRPC server will run on port 9000, to customize the port users can set `GRPC_PORT` config in the .env
148148
149+
## Adding gRPC Server Options
150+
151+
To customize your gRPC server, use `AddGRPCServerOptions()`.
152+
153+
### Example: Enabling TLS & other ServerOptions
154+
```go
155+
func main() {
156+
app := gofr.New()
157+
158+
// Add TLS credentials and connection timeout in one call
159+
creds, _ := credentials.NewServerTLSFromFile("server-cert.pem", "server-key.pem")
160+
161+
app.AddGRPCServerOptions(
162+
grpc.Creds(creds),
163+
grpc.ConnectionTimeout(10 * time.Second),
164+
)
165+
166+
packageName.Register{serviceName}ServerWithGofr(app, &{packageName}.New{serviceName}GoFrServer())
167+
168+
app.Run()
169+
}
170+
```
171+
172+
## Adding Custom Unary Interceptors
173+
174+
Interceptors help in implementing authentication, validation, request transformation, and error handling.
175+
176+
### Example: Authentication Interceptor
177+
```go
178+
func main() {
179+
app := gofr.New()
180+
181+
app.AddGRPCUnaryInterceptors(authInterceptor)
182+
183+
packageName.Register{serviceName}ServerWithGofr(app, &{packageName}.New{serviceName}GoFrServer())
184+
185+
app.Run()
186+
}
187+
188+
func authInterceptor(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
189+
if !isAuthenticated(ctx) {
190+
return nil, status.Errorf(codes.Unauthenticated, "authentication failed")
191+
}
192+
193+
return handler(ctx, req)
194+
}
195+
```
196+
197+
For more details on adding additional interceptors and server options, refer to the [official gRPC Go package](https://pkg.go.dev/google.golang.org/grpc#ServerOption).
198+
149199
## Generating gRPC Client using `gofr wrap grpc client`
150200

151201
**1. Use the `gofr wrap grpc client` Command:**
@@ -159,27 +209,132 @@ This command leverages the `gofr-cli` to generate a `{serviceName}_client.go` fi
159209
```go
160210
// gRPC Handler with context support
161211
func {serviceMethod}(ctx *gofr.Context) (*{serviceResponse}, error) {
162-
// Create the gRPC client
163-
srv, err := New{serviceName}GoFrClient("your-grpc-server-host", ctx.Metrics())
164-
if err != nil {
165-
return nil, err
212+
// Create the gRPC client
213+
srv, err := New{serviceName}GoFrClient("your-grpc-server-host", ctx.Metrics())
214+
if err != nil {
215+
return nil, err
216+
}
217+
218+
// Prepare the request
219+
req := &{serviceRequest}{
220+
// populate fields as necessary
221+
}
222+
223+
// Call the gRPC method with tracing/metrics enabled
224+
res, err := srv.{serviceMethod}(ctx, req)
225+
if err != nil {
226+
return nil, err
227+
}
228+
229+
return res, nil
166230
}
231+
```
167232

168-
// Prepare the request
169-
req := &{serviceRequest}{
170-
// populate fields as necessary
233+
234+
## Customizing gRPC Client with DialOptions
235+
236+
GoFr provides flexibility to customize your gRPC client connections using gRPC `DialOptions`. This allows users to configure aspects such as transport security, interceptors, and load balancing policies.
237+
You can pass optional parameters while creating your gRPC client to tailor the connection to your needs. Here’s an example of a Unary Interceptor that sets metadata on outgoing requests:
238+
239+
```go
240+
func main() {
241+
app := gofr.New()
242+
243+
// Create a gRPC client for the service
244+
gRPCClient, err := client.New{serviceName}GoFrClient(
245+
app.Config.Get("GRPC_SERVER_HOST"),
246+
app.Metrics(),
247+
grpc.WithChainUnaryInterceptor(MetadataUnaryInterceptor),
248+
)
249+
250+
if err != nil {
251+
app.Logger().Errorf("Failed to create gRPC client: %v", err)
252+
return
253+
}
254+
255+
greet := NewGreetHandler(gRPCClient)
256+
257+
app.GET("/hello", greet.Hello)
258+
259+
app.Run()
171260
}
172261

173-
// Call the gRPC method with tracing/metrics enabled
174-
res, err := srv.{serviceMethod}(ctx, req)
175-
if err != nil {
176-
return nil, err
262+
// MetadataUnaryInterceptor sets a custom metadata value on outgoing requests
263+
func MetadataUnaryInterceptor(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
264+
md := metadata.Pairs("client-id", "GoFr-Client-123")
265+
ctx = metadata.NewOutgoingContext(ctx, md)
266+
267+
err := invoker(ctx, method, req, reply, cc, opts...)
268+
if err != nil {
269+
return fmt.Errorf("Error in %s: %v", method, err)
270+
}
271+
272+
return err
177273
}
274+
```
275+
276+
This interceptor sets a metadata key `client-id` with a value of `GoFr-Client-123` for each request. Metadata can be used for authentication, tracing, or custom behaviors.
277+
278+
### Using TLS Credentials and Advanced Service Config
279+
By default, gRPC connections in GoFr are made over insecure connections, which is not recommended for production. You can override this behavior using TLS credentials. Additionally, a more comprehensive service configuration can define retry policies and other settings:
280+
281+
```go
282+
import (
283+
"google.golang.org/grpc"
284+
"google.golang.org/grpc/credentials"
285+
)
286+
287+
// The default serviceConfig in GoFr only sets the loadBalancingPolicy to "round_robin".
288+
const serviceConfig = `{
289+
"loadBalancingPolicy": "round_robin",
290+
"methodConfig": [{
291+
"name": [{"service": "HelloService"}],
292+
"retryPolicy": {
293+
"maxAttempts": 4,
294+
"initialBackoff": "0.1s",
295+
"maxBackoff": "1s",
296+
"backoffMultiplier": 2.0,
297+
"retryableStatusCodes": ["UNAVAILABLE", "RESOURCE_EXHAUSTED"]
298+
}
299+
}]
300+
}`
301+
302+
func main() {
303+
app := gofr.New()
178304

179-
return res, nil
305+
creds, err := credentials.NewClientTLSFromFile("path/to/cert.pem", "")
306+
if err != nil {
307+
app.Logger().Errorf("Failed to load TLS certificate: %v", err)
308+
return
309+
}
310+
311+
gRPCClient, err := client.New{serviceName}GoFrClient(
312+
app.Config.Get("GRPC_SERVER_HOST"),
313+
app.Metrics(),
314+
grpc.WithTransportCredentials(creds),
315+
grpc.WithDefaultServiceConfig(serviceConfig),
316+
)
317+
318+
if err != nil {
319+
app.Logger().Errorf("Failed to create gRPC client: %v", err)
320+
return
321+
}
322+
323+
greet := NewGreetHandler(gRPCClient)
324+
325+
app.GET("/hello", greet.Hello)
326+
327+
app.Run()
180328
}
181329
```
182330

331+
In this example:
332+
- `WithTransportCredentials` sets up TLS security.
333+
- `WithDefaultServiceConfig` defines retry policies with exponential backoff and specific retryable status codes.
334+
335+
### Further Reading
336+
For more details on configurable DialOptions, refer to the [official gRPC package for Go](https://pkg.go.dev/google.golang.org/grpc#DialOption).
337+
183338
## HealthChecks in GoFr's gRPC Service/Clients
184339
Health Checks in GoFr's gRPC Services
185340

@@ -189,20 +344,20 @@ GoFr provides built-in health checks for gRPC services, enabling observability,
189344

190345
```go
191346
type {serviceName}GoFrClient interface {
192-
SayHello(*gofr.Context, *HelloRequest, ...grpc.CallOption) (*HelloResponse, error)
193-
health
347+
SayHello(*gofr.Context, *HelloRequest, ...grpc.CallOption) (*HelloResponse, error)
348+
health
194349
}
195350

196351
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)
352+
Check(ctx *gofr.Context, in *grpc_health_v1.HealthCheckRequest, opts ...grpc.CallOption) (*grpc_health_v1.HealthCheckResponse, error)
353+
Watch(ctx *gofr.Context, in *grpc_health_v1.HealthCheckRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[grpc_health_v1.HealthCheckResponse], error)
199354
}
200355
```
201356

202357
### Server Integration
203358
```go
204359
type {serviceName}GoFrServer struct {
205-
health *healthServer
360+
health *healthServer
206361
}
207362
```
208363
Supported Methods for HealthCheck :

Diff for: docs/datasources/getting-started/page.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ as unnecessary database drivers are not being compiled and added to the build.
9393
-
9494
-
9595
-
96-
-
96+
-
9797

9898
---
9999

Diff for: docs/public/metrics-dashboard.png

514 KB
Loading

Diff for: docs/public/reviewers/aditya_joshi.webp

37.5 KB
Binary file not shown.

Diff for: docs/public/reviewers/ayush_mishra.webp

39 KB
Binary file not shown.

Diff for: docs/public/reviewers/christophe_colombier.webp

92.2 KB
Binary file not shown.

Diff for: docs/public/reviewers/manosh_malai.webp

45 KB
Binary file not shown.

Diff for: docs/public/reviewers/praveen_kumar.webp

59.4 KB
Binary file not shown.

Diff for: docs/public/reviewers/shridhar_vijay.webp

60.5 KB
Binary file not shown.

Diff for: docs/public/reviewers/vignesh.webp

28.1 KB
Binary file not shown.

Diff for: docs/public/reviewers/vineet_dwivedi.webp

23.1 KB
Binary file not shown.

Diff for: docs/quick-start/connecting-mysql/page.md

+3-14
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,12 @@ Just like Redis GoFr also supports connection to SQL (MySQL, MariaDB, and Postgr
44

55
## Setup
66

7-
Users can run MySQL and create a database locally using the following Docker command:
7+
Users can run MySQL/MariaDB and create a database locally using the following Docker command:
88

99
```bash
10-
docker run --name gofr-mysql -e MYSQL_ROOT_PASSWORD=root123 -e MYSQL_DATABASE=test_db -p 3306:3306 -d mysql:8.0.30
10+
docker run --name gofr-db -e MYSQL_ROOT_PASSWORD=root123 -e MYSQL_DATABASE=test_db -p 3306:3306 -d mysql:8.0.30
1111
```
1212

13-
For MariaDB, you would run:
14-
15-
```bash
16-
docker run --name gofr-mariadb -e MYSQL_ROOT_PASSWORD=root123 -e MYSQL_DATABASE=test_db -p 3306:3306 -d mariadb:latest
17-
```
18-
19-
2013
Access `test_db` database and create table customer with columns `id` and `name`. Change mysql to mariadb as needed:
2114

2215
```bash
@@ -43,11 +36,7 @@ DB_PASSWORD=root123
4336
DB_NAME=test_db
4437
DB_PORT=3306
4538
DB_DIALECT=mysql
46-
DB_CHARSET=
47-
48-
# DB_CHARSET: The character set for database connection (default: utf8).
49-
# The `DB_CHARSET` defaults to utf8, but setting it to utf8mb4 is recommended if you need full Unicode support,
50-
# including emojis and special characters.
39+
DB_CHARSET=utf8 #(optional)
5140
```
5241

5342
Now in the following example, we'll store customer data using **POST** `/customer` and then use **GET** `/customer` to retrieve the same.

Diff for: docs/quick-start/connecting-redis/page.md

+1-7
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,7 @@ GoFr simplifies the process of connecting to Redis.
66

77
Ensure we have Redis installed on our system.
88

9-
Optionally, We can use Docker to set up a development environment as described below.
10-
11-
```bash
12-
docker run --name gofr-redis -p 6379:6379 -d redis
13-
```
14-
15-
We can also set up a development environment with password authentication as described below.
9+
Optionally, We can use Docker to set up a development environment with password authentication as described below.
1610

1711
```bash
1812
docker run --name gofr-redis -p 2002:6379 -d \

Diff for: docs/quick-start/observability/page.md

+11
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,17 @@ For example: When running application locally, we can access /metrics endpoint o
137137

138138
GoFr also supports creating {% new-tab-link newtab=false title="custom metrics" href="/docs/advanced-guide/publishing-custom-metrics" /%}.
139139

140+
### Example Dashboard
141+
142+
These metrics can be easily consumed by monitoring systems like {% new-tab-link title="Prometheus" href="https://prometheus.io/" /%}
143+
and visualized in dashboards using tools like {% new-tab-link title="Grafana" href="https://grafana.com/" /%}.
144+
145+
Here's a sample Grafana dashboard utilizing GoFr's metrics:
146+
147+
{% figure src="/metrics-dashboard.png" alt="Grafana Dashboard showing GoFr metrics including HTTP request rates,
148+
response times etc." caption="Example monitoring dashboard using GoFr's built-in metrics" /%}
149+
150+
140151
## Tracing
141152

142153
{% new-tab-link title="Tracing" href="https://opentelemetry.io/docs/concepts/signals/#traces" /%} is a powerful tool for gaining insights into your application's behavior, identifying bottlenecks, and improving

Diff for: docs/references/configs/page.md

+6
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,12 @@ This document lists all the configuration options supported by the GoFr framewor
193193
- Currently supported only for PostgreSQL, with Default certificate file.
194194
- disable
195195

196+
---
197+
198+
- DB_CHARSET
199+
- The character set for database connection
200+
- utf8
201+
196202
{% /table %}
197203

198204
### Redis

0 commit comments

Comments
 (0)