diff --git a/README.md b/README.md index 3081454..5306592 100644 --- a/README.md +++ b/README.md @@ -345,14 +345,42 @@ See [documentation(https://core.telegram.org/bots/api#getfile) ## Errors -The library provides error `ErrorForbidden` for error code 403. That code returns when the bot has no access to the action. -For example, when the user blocked the bot. +This library includes error handling. It provides the following error types: +- **ErrorForbidden (403):** This error occurs when the bot has no access to the action, such as when the user has blocked the bot. +- **ErrorBadRequest (400):** This error indicates a bad request made to the bot's API. +- **ErrorUnauthorized (401):** This error occurs when the bot's access is unauthorized for the requested action. +- **TooManyRequestsError: (429)** This error indicates that the bot has received too many requests within a short period. It includes a RetryAfter value indicating when to retry the request. +- **ErrorNotFound (404):** This error indicates that the requested resource was not found. +- **ErrorConflict (409):** This error indicates a conflict occurred during the request. + +Usage: ```go _, err := b.SendMessage(...) -if errors.Is(err, bot.ErrorForbidden) { - // your code +if errors.Is(err, mybot.ErrorForbidden) { + // Handle the ErrorForbidden (403) case here +} + +if errors.Is(err, mybot.ErrorBadRequest) { + // Handle the ErrorBadRequest (400) case here +} + +if errors.Is(err, mybot.ErrorUnauthorized) { + // Handle the ErrorUnauthorized (401) case here +} + +if mybot.IsTooManyRequestsError(err) { + // Handle the TooManyRequestsError (429) case here + fmt.Println("Received TooManyRequestsError with retry_after:", err.(*mybot.TooManyRequestsError).RetryAfter) +} + +if errors.Is(err, mybot.ErrorNotFound) { + // Handle the ErrorNotFound (404) case here +} + +if errors.Is(err, mybot.ErrorConflict) { + // Handle the ErrorConflict (409) case here } ``` diff --git a/bot_test.go b/bot_test.go index bcd6b9f..9b19e68 100644 --- a/bot_test.go +++ b/bot_test.go @@ -138,7 +138,7 @@ func TestNew_error_getMe(t *testing.T) { if err == nil { t.Fatal("unexpected nil error") } - if err.Error() != "error call getMe, error response from telegram for method getMe, 400 err1" { + if err.Error() != "error call getMe, bad request, err1" { t.Fatalf("wrong error message %q", err.Error()) } } diff --git a/errors.go b/errors.go new file mode 100644 index 0000000..9cd3002 --- /dev/null +++ b/errors.go @@ -0,0 +1,43 @@ +package bot + +import ( + "errors" + "fmt" +) + +var ( + ErrorForbidden = errors.New("forbidden") + ErrorBadRequest = errors.New("bad request") + ErrorUnauthorized = errors.New("unauthorized") + ErrorTooManyRequests = errors.New("too many requests") + ErrorNotFound = errors.New("not found") + ErrorConflict = errors.New("conflict") +) + +type TooManyRequestsError struct { + Message string + RetryAfter int +} + +func (e *TooManyRequestsError) Error() string { + return fmt.Sprintf("%s: retry_after %d", e.Message, e.RetryAfter) +} + +func IsTooManyRequestsError(err error) bool { + _, ok := err.(*TooManyRequestsError) + return ok +} + +type MigrateError struct { + Message string + MigrateToChatID int +} + +func (e *MigrateError) Error() string { + return fmt.Sprintf("%s: migrate_to_chat_id %d", e.Message, e.MigrateToChatID) +} + +func IsMigrateError(err error) bool { + _, ok := err.(*MigrateError) + return ok +} diff --git a/raw_request.go b/raw_request.go index eaec307..6f30d60 100644 --- a/raw_request.go +++ b/raw_request.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "encoding/json" - "errors" "fmt" "io" "mime/multipart" @@ -18,10 +17,12 @@ type apiResponse struct { Result json.RawMessage `json:"result,omitempty"` Description string `json:"description,omitempty"` ErrorCode int `json:"error_code,omitempty"` + Parameters struct { + RetryAfter int `json:"retry_after,omitempty"` + MigrateToChatID int `json:"migrate_to_chat_id,omitempty"` + } `json:"parameters,omitempty"` } -var ErrorForbidden = errors.New("forbidden") - func (b *Bot) rawRequest(ctx context.Context, method string, params any, dest any) error { var httpBody io.Reader = http.NoBody var contentType string @@ -81,10 +82,34 @@ func (b *Bot) rawRequest(ctx context.Context, method string, params any, dest an } if !r.OK { - if r.ErrorCode == 403 { + switch r.ErrorCode { + case 403: return fmt.Errorf("%w, %s", ErrorForbidden, r.Description) + case 400: + if r.Parameters.MigrateToChatID != 0 { + err := &MigrateError{ + Message: fmt.Sprintf("%s: %s", ErrorBadRequest, r.Description), + MigrateToChatID: r.Parameters.MigrateToChatID, + } + + return err + } + return fmt.Errorf("%w, %s", ErrorBadRequest, r.Description) + case 401: + return fmt.Errorf("%w, %s", ErrorUnauthorized, r.Description) + case 404: + return fmt.Errorf("%w, %s", ErrorNotFound, r.Description) + case 409: + return fmt.Errorf("%w, %s", ErrorConflict, r.Description) + case 429: + err := &TooManyRequestsError{ + Message: fmt.Sprintf("%s, %s", ErrorTooManyRequests, r.Description), + RetryAfter: r.Parameters.RetryAfter, + } + return err + default: + return fmt.Errorf("error response from telegram for method %s, %d %s", method, r.ErrorCode, r.Description) } - return fmt.Errorf("error response from telegram for method %s, %d %s", method, r.ErrorCode, r.Description) } if !bytes.Equal(r.Result, []byte("[]")) {