Documentation
¶
Overview ¶
Package client provides a unified HTTP client for AINative platform API interactions.
The client package implements:
- JWT bearer token authentication
- Automatic token refresh on 401 Unauthorized responses
- Request/response logging for observability
- Configurable retry logic with exponential backoff
- Timeout configuration per request
- Base URL configuration for different AINative services
Basic Usage:
authClient := auth.NewClient(authConfig)
tokens, err := authClient.GetStoredTokens(ctx)
client := client.New(
client.WithAuthClient(authClient),
client.WithBaseURL("https://api.ainative.studio"),
client.WithTimeout(30 * time.Second),
)
resp, err := client.Get(ctx, "/api/v1/resource")
The client automatically:
- Injects JWT bearer tokens into requests
- Refreshes expired tokens when receiving 401 responses
- Logs all requests and responses
- Retries failed requests with exponential backoff
- Respects context cancellation and timeouts
Example (CustomOptions) ¶
Example_customOptions demonstrates advanced client configuration
// Create auth client
authClient := &mockAuthClient{
tokens: &auth.TokenPair{
AccessToken: &auth.AccessToken{
Raw: "your-access-token",
ExpiresAt: time.Now().Add(1 * time.Hour),
UserID: "user-123",
Email: "user@example.com",
Issuer: "ainative-auth",
Audience: "ainative-code",
},
},
}
// Create client with custom HTTP client and options
apiClient := client.New(
client.WithBaseURL("https://api.ainative.studio"),
client.WithAuthClient(authClient),
client.WithTimeout(60*time.Second),
client.WithMaxRetries(5), // More retries for flaky networks
)
ctx := context.Background()
// Example: Make request with custom headers
resp, err := apiClient.Get(ctx, "/api/v1/users/me",
client.WithHeader("X-Request-ID", "unique-request-id"),
client.WithHeader("X-Client-Version", "1.0.0"),
)
if err != nil {
fmt.Printf("Failed to get user: %v\n", err)
return
}
var user map[string]interface{}
json.Unmarshal(resp, &user)
fmt.Printf("User: %v\n", user)
// Example: Make unauthenticated request (public endpoint)
resp, err = apiClient.Get(ctx, "/api/v1/public/status",
client.WithSkipAuth(), // Don't inject JWT token
)
if err != nil {
fmt.Printf("Failed to get status: %v\n", err)
return
}
var status map[string]interface{}
json.Unmarshal(resp, &status)
fmt.Printf("Status: %v\n", status)
// Example: Make request with multiple query parameters
resp, err = apiClient.Get(ctx, "/api/v1/search",
client.WithQueryParam("q", "golang"),
client.WithQueryParam("type", "repository"),
client.WithQueryParam("sort", "stars"),
client.WithQueryParam("order", "desc"),
)
if err != nil {
fmt.Printf("Failed to search: %v\n", err)
return
}
var searchResults map[string]interface{}
json.Unmarshal(resp, &searchResults)
fmt.Printf("Search results: %v\n", searchResults)
Example (DesignServiceClient) ¶
Example_designServiceClient demonstrates using the API client for Design Service
// Create auth client
authClient := &mockAuthClient{
tokens: &auth.TokenPair{
AccessToken: &auth.AccessToken{
Raw: "your-access-token",
ExpiresAt: time.Now().Add(1 * time.Hour),
UserID: "user-123",
Email: "user@example.com",
Issuer: "ainative-auth",
Audience: "ainative-code",
},
},
}
// Create API client configured for Design Service
apiClient := client.New(
client.WithBaseURL("https://design.ainative.studio"),
client.WithAuthClient(authClient),
client.WithTimeout(60*time.Second), // Longer timeout for design operations
client.WithMaxRetries(3),
)
ctx := context.Background()
// Example: Generate a design from prompt
designPayload := map[string]interface{}{
"prompt": "Create a modern login page with dark mode",
"style": "minimalist",
"colorScheme": "blue",
"framework": "tailwind",
}
resp, err := apiClient.Post(ctx, "/api/v1/generate", designPayload)
if err != nil {
fmt.Printf("Failed to generate design: %v\n", err)
return
}
var designResult map[string]interface{}
json.Unmarshal(resp, &designResult)
fmt.Printf("Design generated: %v\n", designResult)
// Example: Get design by ID
designID := "design-123"
resp, err = apiClient.Get(ctx, fmt.Sprintf("/api/v1/designs/%s", designID))
if err != nil {
fmt.Printf("Failed to get design: %v\n", err)
return
}
var design map[string]interface{}
json.Unmarshal(resp, &design)
fmt.Printf("Design details: %v\n", design)
Example (ErrorHandling) ¶
Example_errorHandling demonstrates error handling patterns
authClient := &mockAuthClient{
tokens: &auth.TokenPair{
AccessToken: &auth.AccessToken{
Raw: "your-access-token",
ExpiresAt: time.Now().Add(1 * time.Hour),
UserID: "user-123",
Email: "user@example.com",
Issuer: "ainative-auth",
Audience: "ainative-code",
},
},
}
apiClient := client.New(
client.WithBaseURL("https://api.ainative.studio"),
client.WithAuthClient(authClient),
client.WithTimeout(30*time.Second),
client.WithMaxRetries(3),
)
ctx := context.Background()
// Example: Handle different error types
resp, err := apiClient.Get(ctx, "/api/v1/resource")
if err != nil {
// Check for specific error types
if client.IsAuthError(err) {
fmt.Println("Authentication error - please re-authenticate")
// Re-authenticate user
return
}
if client.IsRetryable(err) {
fmt.Println("Retryable error - the client already retried automatically")
// You could implement additional retry logic here
return
}
// Check for HTTP errors
var httpErr *client.HTTPError
if httpError, ok := err.(*client.HTTPError); ok {
httpErr = httpError
switch {
case httpErr.StatusCode == 404:
fmt.Println("Resource not found")
case httpErr.StatusCode == 403:
fmt.Println("Access forbidden - check permissions")
case httpErr.StatusCode >= 500:
fmt.Println("Server error - try again later")
default:
fmt.Printf("HTTP error %d: %s\n", httpErr.StatusCode, httpErr.Message)
}
return
}
// Generic error handling
fmt.Printf("Request failed: %v\n", err)
return
}
// Success - process response
var result map[string]interface{}
json.Unmarshal(resp, &result)
fmt.Printf("Success: %v\n", result)
Example (RlhfClient) ¶
Example_rlhfClient demonstrates using the API client for RLHF (Reinforcement Learning from Human Feedback)
// Create auth client
authClient := &mockAuthClient{
tokens: &auth.TokenPair{
AccessToken: &auth.AccessToken{
Raw: "your-access-token",
ExpiresAt: time.Now().Add(1 * time.Hour),
UserID: "user-123",
Email: "user@example.com",
Issuer: "ainative-auth",
Audience: "ainative-code",
},
},
}
// Create API client configured for RLHF service
apiClient := client.New(
client.WithBaseURL("https://rlhf.ainative.studio"),
client.WithAuthClient(authClient),
client.WithTimeout(30*time.Second),
)
ctx := context.Background()
// Example: Submit feedback for a model response
feedbackPayload := map[string]interface{}{
"sessionID": "session-123",
"responseID": "resp-456",
"feedback": map[string]interface{}{
"rating": 5,
"helpful": true,
"comment": "This response was very helpful and accurate",
"categories": []string{"accuracy", "clarity", "helpfulness"},
},
"context": map[string]interface{}{
"userQuery": "How do I implement OAuth 2.0?",
"modelResponse": "OAuth 2.0 is an authorization framework...",
},
}
resp, err := apiClient.Post(ctx, "/api/v1/feedback", feedbackPayload)
if err != nil {
fmt.Printf("Failed to submit feedback: %v\n", err)
return
}
var feedbackResult map[string]interface{}
json.Unmarshal(resp, &feedbackResult)
fmt.Printf("Feedback submitted: %v\n", feedbackResult)
// Example: Get feedback analytics
resp, err = apiClient.Get(ctx, "/api/v1/analytics/feedback",
client.WithQueryParam("startDate", "2026-01-01"),
client.WithQueryParam("endDate", "2026-01-31"),
client.WithQueryParam("aggregateBy", "day"),
)
if err != nil {
fmt.Printf("Failed to get analytics: %v\n", err)
return
}
var analytics map[string]interface{}
json.Unmarshal(resp, &analytics)
fmt.Printf("Analytics: %v\n", analytics)
// Example: Submit a preference comparison (A/B testing)
comparisonPayload := map[string]interface{}{
"sessionID": "session-789",
"prompt": "Explain dependency injection",
"responseA": map[string]interface{}{
"id": "resp-a-1",
"content": "Dependency injection is a design pattern...",
},
"responseB": map[string]interface{}{
"id": "resp-b-1",
"content": "DI is when you pass dependencies to a class...",
},
"preferred": "A",
"reason": "More detailed and professional explanation",
}
resp, err = apiClient.Post(ctx, "/api/v1/comparisons", comparisonPayload)
if err != nil {
fmt.Printf("Failed to submit comparison: %v\n", err)
return
}
var comparison map[string]interface{}
json.Unmarshal(resp, &comparison)
fmt.Printf("Comparison submitted: %v\n", comparison)
Example (StrapiCMSClient) ¶
Example_strapiCMSClient demonstrates using the API client for Strapi CMS
// Create auth client
authClient := &mockAuthClient{
tokens: &auth.TokenPair{
AccessToken: &auth.AccessToken{
Raw: "your-access-token",
ExpiresAt: time.Now().Add(1 * time.Hour),
UserID: "user-123",
Email: "user@example.com",
Issuer: "ainative-auth",
Audience: "ainative-code",
},
},
}
// Create API client configured for Strapi
apiClient := client.New(
client.WithBaseURL("https://cms.ainative.studio"),
client.WithAuthClient(authClient),
client.WithTimeout(30*time.Second),
)
ctx := context.Background()
// Example: Create a blog post
blogPostPayload := map[string]interface{}{
"data": map[string]interface{}{
"title": "Getting Started with AINative Code",
"content": "AINative Code is a powerful CLI tool...",
"author": "John Doe",
"tags": []string{"tutorial", "getting-started"},
"status": "draft",
},
}
resp, err := apiClient.Post(ctx, "/api/blog-posts", blogPostPayload)
if err != nil {
fmt.Printf("Failed to create blog post: %v\n", err)
return
}
var post map[string]interface{}
json.Unmarshal(resp, &post)
fmt.Printf("Blog post created: %v\n", post)
// Example: Query blog posts with filters and pagination
resp, err = apiClient.Get(ctx, "/api/blog-posts",
client.WithQueryParam("filters[status][$eq]", "published"),
client.WithQueryParam("sort", "publishedAt:desc"),
client.WithQueryParam("pagination[page]", "1"),
client.WithQueryParam("pagination[pageSize]", "10"),
)
if err != nil {
fmt.Printf("Failed to query blog posts: %v\n", err)
return
}
var posts map[string]interface{}
json.Unmarshal(resp, &posts)
fmt.Printf("Blog posts: %v\n", posts)
// Example: Update a blog post
postID := "1"
updatePayload := map[string]interface{}{
"data": map[string]interface{}{
"status": "published",
},
}
resp, err = apiClient.Put(ctx, fmt.Sprintf("/api/blog-posts/%s", postID), updatePayload)
if err != nil {
fmt.Printf("Failed to update blog post: %v\n", err)
return
}
var updatedPost map[string]interface{}
json.Unmarshal(resp, &updatedPost)
fmt.Printf("Blog post updated: %v\n", updatedPost)
Example (ZeroDBClient) ¶
Example_zeroDBClient demonstrates using the API client for ZeroDB NoSQL operations
// Create auth client (simplified for example)
authClient := &mockAuthClient{
tokens: &auth.TokenPair{
AccessToken: &auth.AccessToken{
Raw: "your-access-token",
ExpiresAt: time.Now().Add(1 * time.Hour),
UserID: "user-123",
Email: "user@example.com",
Issuer: "ainative-auth",
Audience: "ainative-code",
},
},
}
// Create API client configured for ZeroDB
apiClient := client.New(
client.WithBaseURL("https://api.ainative.studio"),
client.WithAuthClient(authClient),
client.WithTimeout(30*time.Second),
client.WithMaxRetries(3),
)
ctx := context.Background()
// Example: Create a NoSQL table
createTablePayload := map[string]interface{}{
"name": "users",
"schema": map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"name": map[string]string{"type": "string"},
"email": map[string]string{"type": "string"},
"age": map[string]string{"type": "number"},
},
},
}
resp, err := apiClient.Post(ctx, "/api/v1/projects/my-project/nosql/tables", createTablePayload)
if err != nil {
fmt.Printf("Failed to create table: %v\n", err)
return
}
var createResult map[string]interface{}
json.Unmarshal(resp, &createResult)
fmt.Printf("Table created: %v\n", createResult)
// Example: Insert a document
insertPayload := map[string]interface{}{
"table": "users",
"data": map[string]interface{}{
"name": "John Doe",
"email": "john@example.com",
"age": 30,
},
}
resp, err = apiClient.Post(ctx, "/api/v1/projects/my-project/nosql/documents", insertPayload)
if err != nil {
fmt.Printf("Failed to insert document: %v\n", err)
return
}
var insertResult map[string]interface{}
json.Unmarshal(resp, &insertResult)
fmt.Printf("Document inserted: %v\n", insertResult)
// Example: Query documents with MongoDB-style filter
queryPayload := map[string]interface{}{
"table": "users",
"filter": map[string]interface{}{
"age": map[string]interface{}{
"$gte": 18,
"$lt": 65,
},
},
"limit": 10,
"offset": 0,
}
resp, err = apiClient.Post(ctx, "/api/v1/projects/my-project/nosql/query", queryPayload)
if err != nil {
fmt.Printf("Failed to query documents: %v\n", err)
return
}
var queryResult map[string]interface{}
json.Unmarshal(resp, &queryResult)
fmt.Printf("Query results: %v\n", queryResult)
Index ¶
- Variables
- func FormatThinkingBlock(block *ThinkingBlock, showDepth bool) string
- func GetMaxDepth(blocks []ThinkingBlock) int
- func GetThinkingDuration(state *ThinkingState) time.Duration
- func IsAuthError(err error) bool
- func IsRetryable(err error) bool
- func MergeThinkingBlocks(blocks []ThinkingBlock) string
- func ThinkingEventFromJSON(jsonData string) (*providers.Event, error)
- func ValidateThinkingEvent(event *providers.Event) error
- type Client
- func (c *Client) Delete(ctx context.Context, path string, opts ...RequestOption) ([]byte, error)
- func (c *Client) Get(ctx context.Context, path string, opts ...RequestOption) ([]byte, error)
- func (c *Client) Patch(ctx context.Context, path string, body interface{}, opts ...RequestOption) ([]byte, error)
- func (c *Client) Post(ctx context.Context, path string, body interface{}, opts ...RequestOption) ([]byte, error)
- func (c *Client) Put(ctx context.Context, path string, body interface{}, opts ...RequestOption) ([]byte, error)
- type HTTPError
- type Option
- type Options
- type RequestOption
- type RequestOptions
- type Response
- type ThinkingBlock
- type ThinkingEventParser
- type ThinkingState
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrHTTPRequest indicates an HTTP request failed. ErrHTTPRequest = errors.New("HTTP request failed") // ErrHTTPResponse indicates an HTTP response error. ErrHTTPResponse = errors.New("HTTP response error") ErrUnauthorized = errors.New("unauthorized") // ErrForbidden indicates a 403 Forbidden response. ErrForbidden = errors.New("forbidden") // ErrNotFound indicates a 404 Not Found response. ErrNotFound = errors.New("not found") // ErrRateLimited indicates a 429 Too Many Requests response. ErrRateLimited = errors.New("rate limited") // ErrServerError indicates a 5xx server error response. ErrServerError = errors.New("server error") // ErrNoAuthClient indicates no auth client is configured. ErrNoAuthClient = errors.New("no auth client configured") // ErrTokenRefreshFailed indicates token refresh failed. ErrTokenRefreshFailed = errors.New("token refresh failed") // ErrMaxRetriesExceeded indicates maximum retry attempts exceeded. ErrMaxRetriesExceeded = errors.New("maximum retry attempts exceeded") // ErrInvalidURL indicates an invalid URL. ErrInvalidURL = errors.New("invalid URL") // ErrInvalidRequest indicates an invalid request. ErrInvalidRequest = errors.New("invalid request") )
Functions ¶
func FormatThinkingBlock ¶
func FormatThinkingBlock(block *ThinkingBlock, showDepth bool) string
FormatThinkingBlock formats a thinking block for display
func GetMaxDepth ¶
func GetMaxDepth(blocks []ThinkingBlock) int
GetMaxDepth returns the maximum depth found in thinking blocks
func GetThinkingDuration ¶
func GetThinkingDuration(state *ThinkingState) time.Duration
GetThinkingDuration calculates the duration of a thinking session
func IsAuthError ¶
IsAuthError returns true if the error is an authentication error.
func IsRetryable ¶
IsRetryable returns true if the error is retryable.
func MergeThinkingBlocks ¶
func MergeThinkingBlocks(blocks []ThinkingBlock) string
MergeThinkingBlocks combines multiple thinking blocks into a single text
func ThinkingEventFromJSON ¶
ThinkingEventFromJSON parses a thinking event from JSON string
func ValidateThinkingEvent ¶
ValidateThinkingEvent validates that a thinking event has required fields
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client represents an HTTP client for AINative platform API interactions.
func (*Client) Patch ¶
func (c *Client) Patch(ctx context.Context, path string, body interface{}, opts ...RequestOption) ([]byte, error)
Patch performs a PATCH request to the specified path with the given body.
type HTTPError ¶
HTTPError represents an HTTP error with status code and message.
func NewHTTPError ¶
NewHTTPError creates a new HTTP error.
type Option ¶
type Option func(*Client)
Option is a functional option for configuring the Client.
func WithAuthClient ¶
WithAuthClient sets the authentication client for JWT token management.
func WithBaseURL ¶
WithBaseURL sets the base URL for API requests.
func WithHTTPClient ¶
WithHTTPClient sets a custom HTTP client.
func WithMaxRetries ¶
WithMaxRetries sets the maximum number of retry attempts for failed requests.
func WithTimeout ¶
WithTimeout sets the HTTP request timeout.
type Options ¶
type Options struct {
// BaseURL is the base URL for all API requests
BaseURL string
// Timeout is the default timeout for HTTP requests
Timeout time.Duration
// MaxRetries is the maximum number of retry attempts
MaxRetries int
// RetryBackoff is the initial backoff duration for retries
RetryBackoff time.Duration
// EnableLogging enables request/response logging
EnableLogging bool
// HTTPClient is the underlying HTTP client (optional)
HTTPClient *http.Client
// UserAgent is the User-Agent header value
UserAgent string
}
Options contains configuration options for the HTTP client.
func DefaultOptions ¶
func DefaultOptions() *Options
DefaultOptions returns the default client options.
type RequestOption ¶
type RequestOption func(*requestOptions)
RequestOption is a functional option for per-request configuration.
func WithDisableRetry ¶
func WithDisableRetry() RequestOption
WithDisableRetry disables retry logic for this request.
func WithHeader ¶
func WithHeader(key, value string) RequestOption
WithHeader adds a custom header to the request.
func WithHeaders ¶
func WithHeaders(headers map[string]string) RequestOption
WithHeaders adds multiple custom headers to the request.
func WithQueryParam ¶
func WithQueryParam(key, value string) RequestOption
WithQueryParam adds a query parameter to the request.
func WithQueryParams ¶
func WithQueryParams(params map[string]string) RequestOption
WithQueryParams adds multiple query parameters to the request.
func WithSkipAuth ¶
func WithSkipAuth() RequestOption
WithSkipAuth skips JWT token injection for this request.
type RequestOptions ¶
type RequestOptions struct {
// Headers are additional headers to include in the request
Headers map[string]string
// QueryParams are query parameters to include in the request
QueryParams map[string]string
// Timeout overrides the default client timeout for this request
Timeout time.Duration
// SkipAuth skips JWT token injection for this request
SkipAuth bool
// DisableRetry disables retry logic for this request
DisableRetry bool
}
RequestOptions contains per-request options.
type Response ¶
type Response struct {
// StatusCode is the HTTP status code
StatusCode int
// Headers are the response headers
Headers http.Header
// Body is the raw response body
Body []byte
// Duration is the time taken for the request
Duration time.Duration
}
Response represents an HTTP response with parsed data.
type ThinkingBlock ¶
type ThinkingBlock struct {
Content string `json:"content"`
Depth int `json:"depth"`
Timestamp time.Time `json:"timestamp"`
Index int `json:"index"`
Type string `json:"type"` // "start", "delta", "end"
Metadata map[string]interface{} `json:"metadata,omitempty"`
}
ThinkingBlock represents a single thinking event block
func FilterThinkingBlocks ¶
func FilterThinkingBlocks(blocks []ThinkingBlock, blockType string) []ThinkingBlock
FilterThinkingBlocks filters thinking blocks by type
type ThinkingEventParser ¶
type ThinkingEventParser struct {
// contains filtered or unexported fields
}
ThinkingEventParser handles parsing and processing of thinking events
func NewThinkingEventParser ¶
func NewThinkingEventParser() *ThinkingEventParser
NewThinkingEventParser creates a new thinking event parser
func (*ThinkingEventParser) GetState ¶
func (p *ThinkingEventParser) GetState() *ThinkingState
GetState returns the current thinking state
func (*ThinkingEventParser) ParseEvent ¶
func (p *ThinkingEventParser) ParseEvent(event *providers.Event) (*ThinkingBlock, error)
ParseEvent parses a provider event and extracts thinking information
func (*ThinkingEventParser) Reset ¶
func (p *ThinkingEventParser) Reset()
Reset resets the parser state
type ThinkingState ¶
type ThinkingState struct {
Blocks []ThinkingBlock
CurrentDepth int
TotalEvents int
IsThinking bool
StartTime time.Time
LastEventTime time.Time
}
ThinkingState tracks the current state of thinking events
Directories
¶
| Path | Synopsis |
|---|---|
|
Package design provides a client for interacting with the AINative Design API.
|
Package design provides a client for interacting with the AINative Design API. |
|
Package rlhf provides a client for AINative RLHF (Reinforcement Learning from Human Feedback) operations.
|
Package rlhf provides a client for AINative RLHF (Reinforcement Learning from Human Feedback) operations. |
|
Package strapi provides a client for interacting with Strapi CMS API.
|
Package strapi provides a client for interacting with Strapi CMS API. |
|
Package zerodb provides a client for ZeroDB NoSQL table operations.
|
Package zerodb provides a client for ZeroDB NoSQL table operations. |