Improve error reporting (#68)
* Provide APIError and use Go's error wrapping * Add generic request error * Fix code formatting
This commit is contained in:
9
api.go
9
api.go
@@ -66,9 +66,14 @@ func (c *Client) sendRequest(req *http.Request, v interface{}) error {
|
|||||||
var errRes ErrorResponse
|
var errRes ErrorResponse
|
||||||
err = json.NewDecoder(res.Body).Decode(&errRes)
|
err = json.NewDecoder(res.Body).Decode(&errRes)
|
||||||
if err != nil || errRes.Error == nil {
|
if err != nil || errRes.Error == nil {
|
||||||
return fmt.Errorf("error, status code: %d", res.StatusCode)
|
reqErr := RequestError{
|
||||||
|
StatusCode: res.StatusCode,
|
||||||
|
Err: err,
|
||||||
}
|
}
|
||||||
return fmt.Errorf("error, status code: %d, message: %s", res.StatusCode, errRes.Error.Message)
|
return fmt.Errorf("error, %w", &reqErr)
|
||||||
|
}
|
||||||
|
errRes.Error.StatusCode = res.StatusCode
|
||||||
|
return fmt.Errorf("error, status code: %d, message: %w", res.StatusCode, errRes.Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
if v != nil {
|
if v != nil {
|
||||||
|
|||||||
47
api_test.go
47
api_test.go
@@ -81,6 +81,53 @@ func TestAPI(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAPIError(t *testing.T) {
|
||||||
|
apiToken := os.Getenv("OPENAI_TOKEN")
|
||||||
|
if apiToken == "" {
|
||||||
|
t.Skip("Skipping testing against production OpenAI API. Set OPENAI_TOKEN environment variable to enable it.")
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
c := NewClient(apiToken + "_invalid")
|
||||||
|
ctx := context.Background()
|
||||||
|
_, err = c.ListEngines(ctx)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("ListEngines did not fail")
|
||||||
|
}
|
||||||
|
|
||||||
|
var apiErr *APIError
|
||||||
|
if !errors.As(err, &apiErr) {
|
||||||
|
t.Fatalf("Error is not an APIError: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if apiErr.StatusCode != 401 {
|
||||||
|
t.Fatalf("Unexpected API error status code: %d", apiErr.StatusCode)
|
||||||
|
}
|
||||||
|
if *apiErr.Code != "invalid_api_key" {
|
||||||
|
t.Fatalf("Unexpected API error code: %s", *apiErr.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRequestError(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
c := NewClient("dummy")
|
||||||
|
c.BaseURL = "https://httpbin.org/status/418?"
|
||||||
|
ctx := context.Background()
|
||||||
|
_, err = c.ListEngines(ctx)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("ListEngines request did not fail")
|
||||||
|
}
|
||||||
|
|
||||||
|
var reqErr *RequestError
|
||||||
|
if !errors.As(err, &reqErr) {
|
||||||
|
t.Fatalf("Error is not a RequestError: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if reqErr.StatusCode != 418 {
|
||||||
|
t.Fatalf("Unexpected request error status code: %d", reqErr.StatusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// numTokens Returns the number of GPT-3 encoded tokens in the given text.
|
// numTokens Returns the number of GPT-3 encoded tokens in the given text.
|
||||||
// This function approximates based on the rule of thumb stated by OpenAI:
|
// This function approximates based on the rule of thumb stated by OpenAI:
|
||||||
// https://beta.openai.com/tokenizer
|
// https://beta.openai.com/tokenizer
|
||||||
|
|||||||
35
error.go
35
error.go
@@ -1,10 +1,37 @@
|
|||||||
package gogpt
|
package gogpt
|
||||||
|
|
||||||
type ErrorResponse struct {
|
import "fmt"
|
||||||
Error *struct {
|
|
||||||
Code *int `json:"code,omitempty"`
|
// APIError provides error information returned by the OpenAI API.
|
||||||
|
type APIError struct {
|
||||||
|
Code *string `json:"code,omitempty"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
Param *string `json:"param,omitempty"`
|
Param *string `json:"param,omitempty"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
} `json:"error,omitempty"`
|
StatusCode int `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestError provides informations about generic request errors.
|
||||||
|
type RequestError struct {
|
||||||
|
StatusCode int
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
type ErrorResponse struct {
|
||||||
|
Error *APIError `json:"error,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *APIError) Error() string {
|
||||||
|
return e.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *RequestError) Error() string {
|
||||||
|
if e.Err != nil {
|
||||||
|
return e.Err.Error()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("status code %d", e.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *RequestError) Unwrap() error {
|
||||||
|
return e.Err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user