Skip to content

Commit

Permalink
Improve code comments and update README
Browse files Browse the repository at this point in the history
Signed-off-by: Han Verstraete (OpenFaaS Ltd) <[email protected]>
  • Loading branch information
welteki committed May 28, 2024
1 parent 010fae1 commit 5bf5635
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 12 deletions.
50 changes: 50 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,56 @@ if err != nil {

Please refer [examples](https://github.com/openfaas/go-sdk/tree/master/examples) folder for code examples of each operation

## Invoke functions

```go
header := http.Header{}
header.Set("Content-Type", "text/plain")

body := strings.NewReader("OpenFaaS")

async := false
authenticate := false

// Make a POST request to a figlet function in the openfaas-fn namespace
res, err := client.InvokeFunction(context.Background(), "figlet", "openfaas-fn", http.MethodPost, header, nil, body, async, authenticate)
if err != nil {
log.Printf("Failed to invoke function: %s", err)
return
}

if res.Body != nil {
defer res.Body.Close()
}

// Read the response body
body, err := io.ReadAll(res.Body)
if err != nil {
log.Printf("Error reading response body: %s", err)
return
}

// Print the response
fmt.Printf("Response status code: %s\n", res.Status)
fmt.Printf("Response body: %s\n", string(body))
```

### Authenticate function invocations

The SDK supports invoking functions if you are using OpenFaaS IAM with [built-in authentication for functions](https://www.openfaas.com/blog/built-in-function-authentication/).

Set the `auth` argument to `true` when calling `InvokeFunction` to authenticate the request with an OpenFaaS function access token.

The `Client` needs a `TokenSource` to get an ID token that can be exchanged for a function access token to make authenticated function invocations. By default the `TokenAuth` provider that was set when constructing a new `Client` is used.

It is also possible to provide a custom `TokenSource` for the function token exchange:

```go
ts := sdk.NewClientCredentialsTokenSource(clientID, clientSecret, tokenURL, scope, grantType, audience)

client := sdk.NewClientWithOpts(gatewayURL, http.DefaultClient, sdk.WithFunctionTokenSource(ts))
```

## License

License: MIT
28 changes: 17 additions & 11 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,22 @@ import (
"github.com/openfaas/faas-provider/types"
)

// Client is used to manage OpenFaaS functions
// Client is used to manage OpenFaaS and invoke functions
type Client struct {
GatewayURL *url.URL
ClientAuth ClientAuth
// URL of the OpenFaaS gateway
GatewayURL *url.URL

// Authentication provider for authenticating request to the OpenFaaS API.
ClientAuth ClientAuth

// TokenSource for getting an ID token that can be exchanged for an
// OpenFaaS function access token to invoke functions.
FunctionTokenSource TokenSource

// Http client used for calls to the OpenFaaS gateway.
client *http.Client
// Cache for OpenFaaS function access tokens for invoking functions.

// OpenFaaS function access token cache for invoking functions.
fnTokenCache *TokenCache
}

Expand Down Expand Up @@ -79,23 +87,27 @@ type ClientAuth interface {

type ClientOption func(*Client)

// WithFunctionTokenSource configures the function token source for the client.
func WithFunctionTokenSource(tokenSource TokenSource) ClientOption {
return func(c *Client) {
c.FunctionTokenSource = tokenSource
}
}

// WithAuthentication configures the authentication provider fot the client.
func WithAuthentication(auth ClientAuth) ClientOption {
return func(c *Client) {
c.ClientAuth = auth
}
}

// NewClient creates an Client for managing OpenFaaS
// NewClient creates a Client for managing OpenFaaS and invoking functions
func NewClient(gatewayURL *url.URL, auth ClientAuth, client *http.Client) *Client {
return NewClientWithOpts(gatewayURL, client, WithAuthentication(auth))
}

// NewClientWithOpts creates a Client for managing OpenFaaS and invoking functions
// It takes a list of ClientOptions to configure the client.
func NewClientWithOpts(gatewayURL *url.URL, client *http.Client, options ...ClientOption) *Client {
c := &Client{
GatewayURL: gatewayURL,
Expand All @@ -120,12 +132,6 @@ func NewClientWithOpts(gatewayURL *url.URL, client *http.Client, options ...Clie
return c
}

func (s *Client) WithFunctionTokenSource(tokenSource TokenSource) *Client {
s.FunctionTokenSource = tokenSource

return s
}

// GetNamespaces get openfaas namespaces
func (s *Client) GetNamespaces(ctx context.Context) ([]string, error) {
namespaces := []string{}
Expand Down
7 changes: 6 additions & 1 deletion functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func (c *Client) InvokeFunction(ctx context.Context, name, namespace string, met
return nil, fmt.Errorf("failed to get function access token: %w", err)
}

// Consider caching the token in memory as long as the token is valid
// Function access tokens are cached in memory as long as the token is valid
// to prevent having to do a token exchange each time the function is invoked.
cacheKey := getFunctionTokenCacheKey(idToken, fmt.Sprintf("%s.%s", name, namespace))
functionToken, ok := c.fnTokenCache.Get(cacheKey)
Expand All @@ -70,6 +70,11 @@ func (c *Client) InvokeFunction(ctx context.Context, name, namespace string, met
return c.do(req)
}

// getFunctionTokenCacheKey computes a cache key for caching a function access token based
// on the original id token that is exchanged for the function access token and the function
// name e.g. figlet.openfaas-fn.
// The original token is included in the hash to avoid cache hits for a function when the
// source token changes.
func getFunctionTokenCacheKey(idToken string, serviceName string) string {
hash := sha256.New()
hash.Write([]byte(idToken))
Expand Down

0 comments on commit 5bf5635

Please sign in to comment.