The way API errors are wrapped does not work. Having type aliases to an interface means that at runtime all of the errors are indistinguishable from one another.
Here is the current code:
type BadRequest error
type InvalidToken error
type NotFound error
type InternalError error
// extractError checks if the response signifies an error.
// If so, it returns the error.
// Otherwise, it returns nil.
func extractError(code int, errorBuf []byte) error {
if code >= 200 && code < 300 {
return nil
}
wrappedError := fmt.Errorf("HTTP %v: %s", code, errorBuf)
switch code {
case 400:
return BadRequest(wrappedError)
case 401:
return InvalidToken(wrappedError)
case 404:
return NotFound(wrappedError)
case 500:
return InternalError(wrappedError)
default:
return wrappedError
}
}
Solution
Create a real error and use that for the specific types. They should also include the error code, for example:
// You can edit this code!
// Click here and start typing.
package main
import "fmt"
type HTTPError struct {
Msg string
Code uint
}
func (e HTTPError) Error() string {
return fmt.Sprintf("Client error (%d): %s", e.Code, e.Msg)
}
type NotFound HTTPError
func (e NotFound) Error() string {
return fmt.Sprintf("NotFound error (%d): %s", e.Code, e.Msg)
}
func main() {
genericError := HTTPError{
Msg: "Method Not Found",
Code: 404,
}
fmt.Printf("Error type: %T, Error message: %v\n", genericError, genericError)
var notFound NotFound = NotFound{
Msg: "Method Not Found",
Code: 404,
}
fmt.Printf("Error type: %T, Error message: %v\n", notFound, notFound)
}
Create types so that the extractError can be updated as follows:
// extractError checks if the response signifies an error.
// If so, it returns the error.
// Otherwise, it returns nil.
func extractError(code int, errorBuf []byte) error {
if code >= 200 && code < 300 {
return nil
}
switch code {
case 401:
return InvalidToken{Msg: errorBuf}
case 404:
return NotFound{Msg: errorBuf}
case 500:
return InternalError(wrappedError)
default:
if code < 400 {
return ClientError{Code: code, Msg: errorBuf}
} else if code < 500 {
return ServerError{Code: code, Msg: errorBuf}
}
return UnknownError{Code: code, Msg: errorBuf}
}
}
Subject of the issue
The way API errors are wrapped does not work. Having type aliases to an interface means that at runtime all of the errors are indistinguishable from one another.
Here is the current code:
Solution
Create a real error and use that for the specific types. They should also include the error code, for example:
Create types so that the
extractError
can be updated as follows: