Skip to content

Commit

Permalink
docs: add client documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
ispiroglu committed Sep 24, 2024
1 parent cad7daf commit ed24cb4
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 3 deletions.
149 changes: 149 additions & 0 deletions docs/modules/client.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# Client

The client module enables your application to interact with other web services over HTTP using the [Resty](https://github.com/go-resty/resty) library.

This module simplifies the process of creating an HTTP client. It reads the base URL and timeout configurations from a config file. To create a client, you need to add the module to your application as follows:

```go

app := chaki.New()

app.Use(
// ...
client.Module(),
// ...
)

//...
```

To create a client, you can use the following code:

```go
type exampleClient struct {
*client.Base
}

func newClient(f *client.Factory) *exampleClient {
return &exampleClient{
Base: f.Get("example-client"),
}
}
```

the `example-client` name should match the name in the config file to configure the client from the config file:
```yaml
client:
example-client:
baseUrl: "http://super-duper-client-url.com"
timeout: 500ms
```
To create a request, you should use the following code. This ensures that tracing and other metadata are used on the request as all metadata is under context.
```go
func (cl *exampleClient) SendHello(ctx context.Context) (string, error) {
resp := &response.Response[string]{}

request := cl.Request(ctx) // this gives you an *resty.Request, to work with.

if _, err := request.
SetResult(resp).
Get("/hello"); err != nil {
return "", err
}

return resp.Data, nil
}
```

If you want to log every outgoing request and incoming response, you can simply set `logging` key to `true` on config.
```yaml
client:
example-client:
baseUrl: "http://super-duper-client-url.com"
timeout: 500ms
logging: true
```
---
## Error Handler
By default, Chaki provides a built-in error handler to encapsulate incoming errors. The source code can be found in `modules/client/errors.go`. To avoid log chaos, error cases are not logged by default.

To access the details of the errors, you can cast the error type into `GenericClientError` type as follows:
```go
_, err := cl.SendSomeRequest()
genericError := client.GenericClientError{}
errors.As(err, genericError)
logger.From(ctx).Error(genericError.ClientName)
```

### Providing error handler
You can provide a custom error handler to handle errors in a more specific way. The error handler function should accept a `context.Context` and a `*resty.Response` as parameters.
```go
func newClient(f *client.Factory) *exampleClient {
return &exampleClient{
Base: f.Get("example-client", client.WithErrDecoder(customErrorDecoder)),
}
}
func customErrorDecoder(_ context.Context, res *resty.Response) error {
if res.StatusCode() == 404 {
return fmt.Errorf("not found")
}
return nil
}
```

---

## Wrappers

You can add wrappers to clients to extend their functionality. Chaki provides a default wrapper that adds the following headers to requests if the corresponding values are present in the context:
```go
CorrelationIDKey = "x-correlationId"
ExecutorUserKey = "x-executor-user"
AgentNameKey = "x-agentname"
OwnerKey = "x-owner"
```

### Providing an wrapper

You can wrap the existing client as follows.
```go
type user struct {
publicUsername string
publicTag string
}
func HeaderWrapper() client.DriverWrapper {
return func(restyClient *resty.Client) *resty.Client {
return restyClient.OnBeforeRequest(func(c *resty.Client, r *resty.Request) error {
ctx := r.Context()
h := map[string]string{}
if v := ctx.Value("user"); v != nil {
user := v.(user)
h["publicUsername"] = user.publicUsername
h["publicTag"] = user.publicTag
}
r.SetHeaders(h)
return nil
})
}
}
func newClient(f *client.Factory) *exampleClient {
return &exampleClient{
Base: f.Get("example-client",
client.WithDriverWrappers(HeaderWrapper())),
}
}
```
4 changes: 3 additions & 1 deletion example/client-server/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ type exampleClient struct {

func newClient(f *client.Factory) *exampleClient {
return &exampleClient{
Base: f.Get("example-client"),
Base: f.Get("example-client",
client.WithErrDecoder(customErrorDecoder),
client.WithDriverWrappers(HeaderWrapper())),
}
}

Expand Down
30 changes: 30 additions & 0 deletions example/client-server/client/client_wrapper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package main

import (
"github.com/Trendyol/chaki/modules/client"
"github.com/go-resty/resty/v2"
)

type user struct {
publicUsername string
publicTag string
}

func HeaderWrapper() client.DriverWrapper {
return func(restyClient *resty.Client) *resty.Client {
return restyClient.OnBeforeRequest(func(c *resty.Client, r *resty.Request) error {
ctx := r.Context()

h := map[string]string{}

if v := ctx.Value("user"); v != nil {
user := v.(user)
h["publicUsername"] = user.publicUsername
h["publicTag"] = user.publicTag
}

r.SetHeaders(h)
return nil
})
}
}
15 changes: 15 additions & 0 deletions example/client-server/client/error_decoder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package main

import (
"context"
"fmt"

"github.com/go-resty/resty/v2"
)

func customErrorDecoder(_ context.Context, res *resty.Response) error {
if res.StatusCode() == 404 {
return fmt.Errorf("not found")
}
return nil
}
1 change: 1 addition & 0 deletions modules/client/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func newDriverBuilder(cfg *config.Config) *driverBuilder {
d := resty.New().
SetBaseURL(cfg.GetString("baseurl")).
SetTimeout(cfg.GetDuration("timeout")).

// Debug mode provides a logging, but it's not in the same format with our logger.
SetDebug(cfg.GetBool("debug"))
return &driverBuilder{
Expand Down
5 changes: 3 additions & 2 deletions modules/common/ctxvaluer/valuer.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import (
const (
CorrelationIDKey = "x-correlationId"
ExecutorUserKey = "x-executor-user"
TraceIDKey = "trace-id"
SpanIDKey = "span-id"
AgentNameKey = "x-agentname"
OwnerKey = "x-owner"

TraceIDKey = "trace-id"
SpanIDKey = "span-id"
)

var (
Expand Down

0 comments on commit ed24cb4

Please sign in to comment.