alice-lg/pkg/http/api_errors.go
2024-01-26 14:19:18 +01:00

115 lines
2.7 KiB
Go

package http
// Improve error handling
// Create api.ErrorResponses based on errors returned from server.
// Strip out potentially sensitive information, eg. connection errors
// to internal IP addresses.
import (
"net/http"
"net/url"
"strings"
"github.com/alice-lg/alice-lg/pkg/api"
)
// ErrResourceNotFoundError is a 404 error
type ErrResourceNotFoundError struct{}
// Error implements the error interface and returns
// the error message
func (err *ErrResourceNotFoundError) Error() string {
return "resource not found"
}
// ErrTimeout will be sent if the request took too long
type ErrTimeout string
// Implement Error interface
func (err ErrTimeout) Error() string {
return string(err)
}
// Variables
var (
ErrSourceNotFound = &ErrResourceNotFoundError{}
)
// Error tags
const (
TagGenericError = "GENERIC_ERROR"
TagConnectionRefused = "CONNECTION_REFUSED"
TagConnectionTimeout = "CONNECTION_TIMEOUT"
TagResourceNotFound = "NOT_FOUND"
TagValidationError = "VALIDATION_ERROR"
)
// Error codes
const (
CodeGeneric = 42
CodeConnectionRefused = 100
CodeConnectionTimeout = 101
CodeValidationError = 400
CodeResourceNotFound = 404
)
// Error status codes
const (
StatusError = http.StatusInternalServerError
StatusResourceNotFound = http.StatusNotFound
StatusValidationError = http.StatusBadRequest
TimeoutError = http.StatusGatewayTimeout
)
// Handle an error and create a error API response
func apiErrorResponse(
routeserverID string,
err error,
) (api.ErrorResponse, int) {
code := CodeGeneric
message := err.Error()
tag := TagGenericError
status := StatusError
// TODO: This needs refactoring.
if err == api.ErrTooManyRoutes {
tag = TagValidationError
code = CodeValidationError
status = StatusValidationError
} else {
switch e := err.(type) {
case ErrTimeout:
tag = TagConnectionTimeout
code = CodeConnectionTimeout
status = TimeoutError
case *ErrResourceNotFoundError:
tag = TagResourceNotFound
code = CodeResourceNotFound
status = StatusResourceNotFound
case *url.Error:
if strings.Contains(message, "connection refused") {
tag = TagConnectionRefused
code = CodeConnectionRefused
message = "Connection refused while dialing the API"
} else if e.Timeout() {
tag = TagConnectionTimeout
code = CodeConnectionTimeout
message = "Connection timed out when connecting to the backend API"
}
case *ErrValidationFailed:
tag = TagValidationError
code = CodeValidationError
status = StatusValidationError
message = e.Reason
}
}
return api.ErrorResponse{
Code: code,
Tag: tag,
Message: message,
RouteserverID: routeserverID,
}, status
}