Skip to content

Commit 68e4718

Browse files
committed
feat(analytics): improve error handling for API responses
1 parent 97e6b0c commit 68e4718

2 files changed

Lines changed: 55 additions & 15 deletions

File tree

internal/cli/api.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"regexp"
1111
"strings"
1212

13+
"github.com/auth0/go-auth0/v2/management/core"
1314
"github.com/spf13/cobra"
1415

1516
"github.com/auth0/auth0-cli/internal/ansi"
@@ -171,6 +172,10 @@ func apiCmdRun(cli *cli, inputs *apiCmdInputs) func(cmd *cobra.Command, args []s
171172
return err
172173
}
173174

175+
if response.StatusCode >= http.StatusBadRequest {
176+
return newAPIResponseError(response.StatusCode, response.Header, rawBodyJSON)
177+
}
178+
174179
if len(rawBodyJSON) == 0 {
175180
if cli.debug {
176181
cli.renderer.Infof("Response body is empty.")
@@ -279,6 +284,19 @@ func (i *apiCmdInputs) parseRaw(args []string) {
279284
i.RawURI = args[lenArgs-1]
280285
}
281286

287+
// newAPIResponseError builds a go-auth0 v2 management error from a non-2xx raw
288+
// `auth0 api` response. Using the real management error type (rather than a
289+
// bespoke one) means classifyCommandFailure maps the status to an error_class
290+
// through the same path as the typed SDK commands.
291+
func newAPIResponseError(statusCode int, header http.Header, body []byte) error {
292+
message := strings.TrimSpace(string(body))
293+
if message == "" {
294+
message = http.StatusText(statusCode)
295+
}
296+
297+
return core.NewAPIError(statusCode, header, fmt.Errorf("API request failed: %s", message))
298+
}
299+
282300
func isInsufficientScopeError(r *http.Response) error {
283301
if r.StatusCode != 403 {
284302
return nil

internal/cli/root.go

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"unicode"
1111

1212
"github.com/auth0/go-auth0/management"
13+
"github.com/auth0/go-auth0/v2/management/core"
1314
"github.com/spf13/cobra"
1415

1516
"github.com/auth0/auth0-cli/internal/analytics"
@@ -277,22 +278,43 @@ func classifyCommandFailure(err error) map[string]string {
277278
return properties
278279
}
279280

280-
var managementErr management.Error
281-
if errors.As(err, &managementErr) {
282-
status := managementErr.Status()
283-
switch {
284-
case status == 401 || status == 403:
285-
properties["error_class"] = "auth"
286-
case status == 400 || status == 422:
287-
properties["error_class"] = "validation"
288-
case status == 404:
289-
properties["error_class"] = "not_found"
290-
case status == 429:
291-
properties["error_class"] = "rate_limit"
292-
case status >= 500:
293-
properties["error_class"] = "api"
294-
}
281+
if status, ok := managementHTTPStatus(err); ok {
282+
properties["error_class"] = errorClassForHTTPStatus(status)
295283
}
296284

297285
return properties
298286
}
287+
288+
// managementHTTPStatus extracts the HTTP status from a go-auth0 management API
289+
// error anywhere in the error chain, supporting both the v1 (management.Error)
290+
// and v2 (*core.APIError) SDK error types.
291+
func managementHTTPStatus(err error) (int, bool) {
292+
var v1 management.Error
293+
if errors.As(err, &v1) {
294+
return v1.Status(), true
295+
}
296+
297+
var v2 *core.APIError
298+
if errors.As(err, &v2) {
299+
return v2.StatusCode, true
300+
}
301+
302+
return 0, false
303+
}
304+
305+
func errorClassForHTTPStatus(status int) string {
306+
switch {
307+
case status == 401 || status == 403:
308+
return "auth"
309+
case status == 400 || status == 422:
310+
return "validation"
311+
case status == 404:
312+
return "not_found"
313+
case status == 429:
314+
return "rate_limit"
315+
case status >= 500:
316+
return "api"
317+
default:
318+
return "unknown"
319+
}
320+
}

0 commit comments

Comments
 (0)