Skip to content

Commit

Permalink
Added error handling for specific error codes (#69)
Browse files Browse the repository at this point in the history
* Added error handling for specific error codes

* added TooManyRequestsError witch have retry_after

* Added a parameters field with retry_after and handled error code 429

* added example of handling TooManyRequestsError with RetryAfter

* fix: changed description

* fix: used switch statement instead of if statement

* add MigrateError type and IsMigrateError function

* updated apiResponse struct and error handling logic

* fix: changed from %w to %s to ensure proper functionality of Sprintf

* fix: correct error message in getMe test

---------

Co-authored-by: Ehson <[email protected]>
Co-authored-by: usmonzodasomon <[email protected]>
  • Loading branch information
3 people authored Apr 3, 2024
1 parent 8f8421f commit e65d48b
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 10 deletions.
36 changes: 32 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
```

Expand Down
2 changes: 1 addition & 1 deletion bot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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())
}
}
Expand Down
43 changes: 43 additions & 0 deletions errors.go
Original file line number Diff line number Diff line change
@@ -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
}
35 changes: 30 additions & 5 deletions raw_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"mime/multipart"
Expand All @@ -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
Expand Down Expand Up @@ -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("[]")) {
Expand Down

0 comments on commit e65d48b

Please sign in to comment.