faas-clinet
This commit is contained in:
297
faas-client/README.md
Normal file
297
faas-client/README.md
Normal file
@ -0,0 +1,297 @@
|
||||
# Skybridge FaaS Client
|
||||
|
||||
A lightweight Go client library for interacting with the Skybridge Function-as-a-Service (FaaS) platform.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
go get github.com/RyanCopley/skybridge/faas-client
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Client Setup
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
faasclient "github.com/RyanCopley/skybridge/faas-client"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Create a new client
|
||||
client := faasclient.NewClient(
|
||||
"http://localhost:8080", // FaaS API base URL
|
||||
faasclient.WithUserEmail("admin@example.com"), // Authentication
|
||||
)
|
||||
|
||||
// Use the client...
|
||||
}
|
||||
```
|
||||
|
||||
### Authentication Options
|
||||
|
||||
```go
|
||||
// Using user email header (for development)
|
||||
client := faasclient.NewClient(baseURL,
|
||||
faasclient.WithUserEmail("user@example.com"))
|
||||
|
||||
// Using custom auth headers
|
||||
client := faasclient.NewClient(baseURL,
|
||||
faasclient.WithAuth(map[string]string{
|
||||
"Authorization": "Bearer " + token,
|
||||
"X-User-Email": "user@example.com",
|
||||
}))
|
||||
|
||||
// Using custom HTTP client
|
||||
httpClient := &http.Client{Timeout: 30 * time.Second}
|
||||
client := faasclient.NewClient(baseURL,
|
||||
faasclient.WithHTTPClient(httpClient))
|
||||
```
|
||||
|
||||
### Function Management
|
||||
|
||||
#### Creating a Function
|
||||
|
||||
```go
|
||||
req := &faasclient.CreateFunctionRequest{
|
||||
Name: "my-function",
|
||||
AppID: "my-app",
|
||||
Runtime: faasclient.RuntimeNodeJS18,
|
||||
Image: "node:18-alpine", // Optional, auto-selected if not provided
|
||||
Handler: "index.handler",
|
||||
Code: "exports.handler = async (event) => { return 'Hello World'; }",
|
||||
Environment: map[string]string{
|
||||
"NODE_ENV": "production",
|
||||
},
|
||||
Timeout: faasclient.Duration(30 * time.Second),
|
||||
Memory: 512,
|
||||
Owner: faasclient.Owner{
|
||||
Type: faasclient.OwnerTypeIndividual,
|
||||
Name: "John Doe",
|
||||
Owner: "john@example.com",
|
||||
},
|
||||
}
|
||||
|
||||
function, err := client.CreateFunction(context.Background(), req)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Printf("Created function: %s (ID: %s)", function.Name, function.ID)
|
||||
```
|
||||
|
||||
#### Getting a Function
|
||||
|
||||
```go
|
||||
function, err := client.GetFunction(context.Background(), functionID)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Printf("Function: %s, Runtime: %s", function.Name, function.Runtime)
|
||||
```
|
||||
|
||||
#### Updating a Function
|
||||
|
||||
```go
|
||||
newTimeout := faasclient.Duration(60 * time.Second)
|
||||
req := &faasclient.UpdateFunctionRequest{
|
||||
Timeout: &newTimeout,
|
||||
Environment: map[string]string{
|
||||
"NODE_ENV": "development",
|
||||
},
|
||||
}
|
||||
|
||||
function, err := client.UpdateFunction(context.Background(), functionID, req)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
```
|
||||
|
||||
#### Listing Functions
|
||||
|
||||
```go
|
||||
response, err := client.ListFunctions(context.Background(), "my-app", 50, 0)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, fn := range response.Functions {
|
||||
log.Printf("Function: %s (ID: %s)", fn.Name, fn.ID)
|
||||
}
|
||||
```
|
||||
|
||||
#### Deleting a Function
|
||||
|
||||
```go
|
||||
err := client.DeleteFunction(context.Background(), functionID)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
```
|
||||
|
||||
### Function Deployment
|
||||
|
||||
```go
|
||||
// Deploy with default options
|
||||
resp, err := client.DeployFunction(context.Background(), functionID, nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Force deployment
|
||||
req := &faasclient.DeployFunctionRequest{
|
||||
Force: true,
|
||||
}
|
||||
resp, err = client.DeployFunction(context.Background(), functionID, req)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Printf("Deployment status: %s", resp.Status)
|
||||
```
|
||||
|
||||
### Function Execution
|
||||
|
||||
#### Synchronous Execution
|
||||
|
||||
```go
|
||||
input := json.RawMessage(`{"name": "World"}`)
|
||||
req := &faasclient.ExecuteFunctionRequest{
|
||||
FunctionID: functionID,
|
||||
Input: input,
|
||||
Async: false,
|
||||
}
|
||||
|
||||
response, err := client.ExecuteFunction(context.Background(), req)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Printf("Result: %s", string(response.Output))
|
||||
log.Printf("Duration: %v", response.Duration)
|
||||
```
|
||||
|
||||
#### Asynchronous Execution
|
||||
|
||||
```go
|
||||
input := json.RawMessage(`{"name": "World"}`)
|
||||
response, err := client.InvokeFunction(context.Background(), functionID, input)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Printf("Execution ID: %s", response.ExecutionID)
|
||||
log.Printf("Status: %s", response.Status)
|
||||
```
|
||||
|
||||
### Execution Management
|
||||
|
||||
#### Getting Execution Details
|
||||
|
||||
```go
|
||||
execution, err := client.GetExecution(context.Background(), executionID)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Printf("Status: %s", execution.Status)
|
||||
log.Printf("Duration: %v", execution.Duration)
|
||||
if execution.Error != "" {
|
||||
log.Printf("Error: %s", execution.Error)
|
||||
}
|
||||
```
|
||||
|
||||
#### Listing Executions
|
||||
|
||||
```go
|
||||
// List all executions
|
||||
response, err := client.ListExecutions(context.Background(), nil, 50, 0)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// List executions for a specific function
|
||||
response, err = client.ListExecutions(context.Background(), &functionID, 50, 0)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, exec := range response.Executions {
|
||||
log.Printf("Execution: %s, Status: %s", exec.ID, exec.Status)
|
||||
}
|
||||
```
|
||||
|
||||
#### Canceling an Execution
|
||||
|
||||
```go
|
||||
err := client.CancelExecution(context.Background(), executionID)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
```
|
||||
|
||||
#### Getting Execution Logs
|
||||
|
||||
```go
|
||||
logs, err := client.GetExecutionLogs(context.Background(), executionID)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, logLine := range logs.Logs {
|
||||
log.Printf("Log: %s", logLine)
|
||||
}
|
||||
```
|
||||
|
||||
#### Getting Running Executions
|
||||
|
||||
```go
|
||||
response, err := client.GetRunningExecutions(context.Background())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Printf("Running executions: %d", response.Count)
|
||||
for _, exec := range response.Executions {
|
||||
log.Printf("Running: %s (Function: %s)", exec.ID, exec.FunctionID)
|
||||
}
|
||||
```
|
||||
|
||||
## Types
|
||||
|
||||
The client provides comprehensive type definitions that match the FaaS API:
|
||||
|
||||
- `FunctionDefinition` - Complete function metadata
|
||||
- `FunctionExecution` - Execution details and results
|
||||
- `RuntimeType` - Supported runtimes (NodeJS18, Python39, Go120, Custom)
|
||||
- `ExecutionStatus` - Execution states (Pending, Running, Completed, Failed, etc.)
|
||||
- `Owner` - Ownership information
|
||||
- Request/Response types for all operations
|
||||
|
||||
## Error Handling
|
||||
|
||||
The client provides detailed error messages that include HTTP status codes and response bodies:
|
||||
|
||||
```go
|
||||
function, err := client.GetFunction(ctx, nonExistentID)
|
||||
if err != nil {
|
||||
// Error will include status code and details
|
||||
log.Printf("Error: %v", err) // "get function failed with status 404: Function not found"
|
||||
}
|
||||
```
|
||||
|
||||
## Architecture Benefits
|
||||
|
||||
This client package is designed as a lightweight, standalone library that:
|
||||
|
||||
- **No heavy dependencies**: Only requires `google/uuid`
|
||||
- **Zero coupling**: Doesn't import the entire FaaS service
|
||||
- **Modular**: Can be used by any service in your monolith
|
||||
- **Type-safe**: Comprehensive Go types for all API operations
|
||||
- **Flexible auth**: Supports multiple authentication methods
|
||||
Reference in New Issue
Block a user