From 5a2cb4a61e33a80c7bf448ffc03139d00fca8150 Mon Sep 17 00:00:00 2001 From: Ehson Date: Mon, 11 Mar 2024 17:32:26 +0500 Subject: [PATCH 01/10] Added error handling for specific error codes --- README.md | 20 ++++++++++++++++++++ errors.go | 12 ++++++++++++ raw_request.go | 23 ++++++++++++++++++++--- 3 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 errors.go diff --git a/README.md b/README.md index 50d67d0..06b45fa 100644 --- a/README.md +++ b/README.md @@ -353,6 +353,26 @@ _, err := b.SendMessage(...) if errors.Is(err, bot.ErrorForbidden) { // your code } + +if errors.Is(err, bot.ErrorBadRequest) { + // your code +} + +if errors.Is(err, bot.ErrorUnauthorized) { + // your code +} + +if errors.Is(err, bot.ErrorTooManyRequests) { + // your code +} + +if errors.Is(err, bot.ErrorNotFound) { + // your code +} + +if errors.Is(err, bot.ErrorConflict) { + // your code +} ``` ## UI Components diff --git a/errors.go b/errors.go new file mode 100644 index 0000000..bdff1fa --- /dev/null +++ b/errors.go @@ -0,0 +1,12 @@ +package bot + +import "errors" + +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") +) diff --git a/raw_request.go b/raw_request.go index eaec307..eaff38d 100644 --- a/raw_request.go +++ b/raw_request.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "encoding/json" - "errors" "fmt" "io" "mime/multipart" @@ -20,8 +19,6 @@ type apiResponse struct { ErrorCode int `json:"error_code,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 @@ -84,6 +81,26 @@ func (b *Bot) rawRequest(ctx context.Context, method string, params any, dest an if r.ErrorCode == 403 { return fmt.Errorf("%w, %s", ErrorForbidden, r.Description) } + + if r.ErrorCode == 400 { + return fmt.Errorf("%w, %s", ErrorBadRequest, r.Description) + } + + if r.ErrorCode == 401 { + return fmt.Errorf("%w, %s", ErrorUnauthorized, r.Description) + } + + if r.ErrorCode == 404 { + return fmt.Errorf("%w, %s", ErrorNotFound, r.Description) + } + + if r.ErrorCode == 409 { + return fmt.Errorf("%w, %s", ErrorConflict, r.Description) + } + + if r.ErrorCode == 429 { + return fmt.Errorf("%w, %s", ErrorTooManyRequests, r.Description) + } return fmt.Errorf("error response from telegram for method %s, %d %s", method, r.ErrorCode, r.Description) } From 9d15aa7c4bd0eddfcfd60ccb804d12c7e0d2d05e Mon Sep 17 00:00:00 2001 From: Ehson Date: Thu, 14 Mar 2024 15:04:21 +0500 Subject: [PATCH 02/10] added TooManyRequestsError witch have retry_after --- errors.go | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/errors.go b/errors.go index bdff1fa..9a31b92 100644 --- a/errors.go +++ b/errors.go @@ -1,6 +1,9 @@ package bot -import "errors" +import ( + "errors" + "fmt" +) var ( ErrorForbidden = errors.New("forbidden") @@ -10,3 +13,17 @@ var ( 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 +} From 397eb6f20cbe4081368b9086190c1b631688a08d Mon Sep 17 00:00:00 2001 From: Ehson Date: Thu, 14 Mar 2024 15:14:54 +0500 Subject: [PATCH 03/10] Added a parameters field with retry_after and handled error code 429 --- raw_request.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/raw_request.go b/raw_request.go index eaff38d..28c590b 100644 --- a/raw_request.go +++ b/raw_request.go @@ -17,6 +17,9 @@ 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"` + } `json:"parameters,omitempty"` } func (b *Bot) rawRequest(ctx context.Context, method string, params any, dest any) error { @@ -99,7 +102,11 @@ func (b *Bot) rawRequest(ctx context.Context, method string, params any, dest an } if r.ErrorCode == 429 { - return fmt.Errorf("%w, %s", ErrorTooManyRequests, r.Description) + err := &TooManyRequestsError{ + Message: fmt.Sprintf("%w, %s", ErrorTooManyRequests, r.Description), + RetryAfter: r.Parameters.RetryAfter, + } + return err } return fmt.Errorf("error response from telegram for method %s, %d %s", method, r.ErrorCode, r.Description) } From 805363d931d53afb91126aa5899bd45ab55b559f Mon Sep 17 00:00:00 2001 From: Ehson Date: Thu, 14 Mar 2024 15:15:31 +0500 Subject: [PATCH 04/10] added example of handling TooManyRequestsError with RetryAfter --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 06b45fa..09eaff1 100644 --- a/README.md +++ b/README.md @@ -362,8 +362,9 @@ if errors.Is(err, bot.ErrorUnauthorized) { // your code } -if errors.Is(err, bot.ErrorTooManyRequests) { - // your code +if bot.IsTooManyRequestsError(err) { + // your code + fmt.Println("Received TooManyRequestsError with retry_after: ", err.(*TooManyRequestsError).RetryAfter) } if errors.Is(err, bot.ErrorNotFound) { From 71415f1ec95e4207945086b556bf972b60a22d85 Mon Sep 17 00:00:00 2001 From: Ehson Date: Thu, 28 Mar 2024 11:02:41 +0500 Subject: [PATCH 05/10] fix: changed description --- README.md | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 09eaff1..602447a 100644 --- a/README.md +++ b/README.md @@ -344,35 +344,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, bot.ErrorBadRequest) { - // your code +if errors.Is(err, mybot.ErrorBadRequest) { + // Handle the ErrorBadRequest (400) case here } -if errors.Is(err, bot.ErrorUnauthorized) { - // your code +if errors.Is(err, mybot.ErrorUnauthorized) { + // Handle the ErrorUnauthorized (401) case here } -if bot.IsTooManyRequestsError(err) { - // your code - fmt.Println("Received TooManyRequestsError with retry_after: ", err.(*TooManyRequestsError).RetryAfter) +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, bot.ErrorNotFound) { - // your code +if errors.Is(err, mybot.ErrorNotFound) { + // Handle the ErrorNotFound (404) case here } -if errors.Is(err, bot.ErrorConflict) { - // your code +if errors.Is(err, mybot.ErrorConflict) { + // Handle the ErrorConflict (409) case here } ``` From 1c6009bf5ecfb4fba849c7d19f7cc609da98e6ac Mon Sep 17 00:00:00 2001 From: Ehson Date: Thu, 28 Mar 2024 11:03:15 +0500 Subject: [PATCH 06/10] fix: used switch statement instead of if statement --- raw_request.go | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/raw_request.go b/raw_request.go index 28c590b..6f39d83 100644 --- a/raw_request.go +++ b/raw_request.go @@ -81,34 +81,26 @@ 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) - } - - if r.ErrorCode == 400 { + case 400: return fmt.Errorf("%w, %s", ErrorBadRequest, r.Description) - } - - if r.ErrorCode == 401 { + case 401: return fmt.Errorf("%w, %s", ErrorUnauthorized, r.Description) - } - - if r.ErrorCode == 404 { + case 404: return fmt.Errorf("%w, %s", ErrorNotFound, r.Description) - } - - if r.ErrorCode == 409 { + case 409: return fmt.Errorf("%w, %s", ErrorConflict, r.Description) - } - - if r.ErrorCode == 429 { + case 429: err := &TooManyRequestsError{ Message: fmt.Sprintf("%w, %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("[]")) { From bcbc87b82cdd33705a58b935b37ee3a9d8050c98 Mon Sep 17 00:00:00 2001 From: Ehson Date: Sun, 31 Mar 2024 17:25:14 +0500 Subject: [PATCH 07/10] add MigrateError type and IsMigrateError function --- errors.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/errors.go b/errors.go index 9a31b92..9cd3002 100644 --- a/errors.go +++ b/errors.go @@ -27,3 +27,17 @@ 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 +} From 6130d1a0edae282393259ccdf520018cc30118b3 Mon Sep 17 00:00:00 2001 From: Ehson Date: Sun, 31 Mar 2024 17:28:49 +0500 Subject: [PATCH 08/10] updated apiResponse struct and error handling logic --- raw_request.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/raw_request.go b/raw_request.go index 6f39d83..4f847c8 100644 --- a/raw_request.go +++ b/raw_request.go @@ -18,7 +18,8 @@ type apiResponse struct { Description string `json:"description,omitempty"` ErrorCode int `json:"error_code,omitempty"` Parameters struct { - RetryAfter int `json:"retry_after"` + RetryAfter int `json:"retry_after,omitempty"` + MigrateToChatID int `json:"migrate_to_chat_id,omitempty"` } `json:"parameters,omitempty"` } @@ -85,6 +86,14 @@ func (b *Bot) rawRequest(ctx context.Context, method string, params any, dest an case 403: return fmt.Errorf("%w, %s", ErrorForbidden, r.Description) case 400: + if r.Parameters.MigrateToChatID != 0 { + err := &MigrateError{ + Message: fmt.Sprintf("%w: %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) From 0055018bbd9f703b989c1205c009cccf38fe796e Mon Sep 17 00:00:00 2001 From: usmonzodasomon Date: Tue, 2 Apr 2024 21:21:23 +0500 Subject: [PATCH 09/10] fix: changed from %w to %s to ensure proper functionality of Sprintf --- raw_request.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/raw_request.go b/raw_request.go index 4f847c8..6f30d60 100644 --- a/raw_request.go +++ b/raw_request.go @@ -88,7 +88,7 @@ func (b *Bot) rawRequest(ctx context.Context, method string, params any, dest an case 400: if r.Parameters.MigrateToChatID != 0 { err := &MigrateError{ - Message: fmt.Sprintf("%w: %s", ErrorBadRequest, r.Description), + Message: fmt.Sprintf("%s: %s", ErrorBadRequest, r.Description), MigrateToChatID: r.Parameters.MigrateToChatID, } @@ -103,7 +103,7 @@ func (b *Bot) rawRequest(ctx context.Context, method string, params any, dest an return fmt.Errorf("%w, %s", ErrorConflict, r.Description) case 429: err := &TooManyRequestsError{ - Message: fmt.Sprintf("%w, %s", ErrorTooManyRequests, r.Description), + Message: fmt.Sprintf("%s, %s", ErrorTooManyRequests, r.Description), RetryAfter: r.Parameters.RetryAfter, } return err From 932d3b022ed421c9ec9ce12ed52371065824a2e9 Mon Sep 17 00:00:00 2001 From: Ehson Date: Wed, 3 Apr 2024 12:33:32 +0500 Subject: [PATCH 10/10] fix: correct error message in getMe test --- bot_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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()) } }