package friendli
import (
"encoding/json"
"fmt"
"io"
"net/http"
)
// APIError represents an error returned by the Friendli API
type APIError struct {
StatusCode int
Message string
Type string
Details map[string]interface{}
}
// Error implements the error interface
func (e *APIError) Error() string {
if e.Type != "" {
return fmt.Sprintf("friendli: %s (status %d): %s", e.Type, e.StatusCode, e.Message)
}
return fmt.Sprintf("friendli: status %d: %s", e.StatusCode, e.Message)
}
// IsRateLimitError returns true if the error is a rate limit error
func (e *APIError) IsRateLimitError() bool {
return e.StatusCode == http.StatusTooManyRequests
}
// IsAuthenticationError returns true if the error is an authentication error
func (e *APIError) IsAuthenticationError() bool {
return e.StatusCode == http.StatusUnauthorized
}
// IsValidationError returns true if the error is a validation error
func (e *APIError) IsValidationError() bool {
return e.StatusCode == http.StatusUnprocessableEntity
}
// errorResponse represents the structure of error responses from the API
type errorResponse struct {
Error struct {
Message string `json:"message"`
Type string `json:"type"`
Code string `json:"code"`
Param string `json:"param"`
Details map[string]interface{} `json:"details"`
} `json:"error"`
}
// parseErrorResponse attempts to parse an error response from the API
func parseErrorResponse(resp *http.Response) error {
body, err := io.ReadAll(resp.Body)
if err != nil {
return &APIError{
StatusCode: resp.StatusCode,
Message: fmt.Sprintf("failed to read error response: %v", err),
}
}
var errResp errorResponse
if err := json.Unmarshal(body, &errResp); err != nil {
// If we can't parse the error response, return a generic error with the body
return &APIError{
StatusCode: resp.StatusCode,
Message: string(body),
}
}
return &APIError{
StatusCode: resp.StatusCode,
Message: errResp.Error.Message,
Type: errResp.Error.Type,
Details: errResp.Error.Details,
}
}
// ValidationError represents a validation error for request parameters
type ValidationError struct {
Field string
Message string
}
// Error implements the error interface
func (e *ValidationError) Error() string {
return fmt.Sprintf("validation error: %s: %s", e.Field, e.Message)
}
// Common validation errors
// ErrMissingAPIKey is returned when the API key is not provided
var ErrMissingAPIKey = &ValidationError{
Field: "apiKey",
Message: "API key is required",
}
// ErrMissingModel is returned when the model is not specified
var ErrMissingModel = &ValidationError{
Field: "model",
Message: "model is required",
}
// ErrEmptyMessages is returned when the messages array is empty
var ErrEmptyMessages = &ValidationError{
Field: "messages",
Message: "at least one message is required",
}