From 6970a1b09a452eb74a07756999072f04a12988a9 Mon Sep 17 00:00:00 2001 From: Depado Date: Fri, 7 Oct 2016 15:28:27 +0200 Subject: [PATCH] Correctly handle Facebook errors (#14) * Sending back the error message of Facebook as an error for some function calls * Adding error handling for other function calls * Private function to parse Facebook's response * Handling errors for ProfileByID function --- message.go | 2 +- messenger.go | 32 +++++++++++++++++++++++++++++--- response.go | 42 +++++++++++++++++++++++++++++++++++++++--- 3 files changed, 69 insertions(+), 7 deletions(-) diff --git a/message.go b/message.go index c857455..f967c39 100644 --- a/message.go +++ b/message.go @@ -36,7 +36,7 @@ type Delivery struct { Seq int `json:"seq"` } -// Delivery represents a the event fired when a message is read by the +// Read represents a the event fired when a message is read by the // recipient. type Read struct { // RawWatermark is the timestamp before which all messages have been read diff --git a/messenger.go b/messenger.go index dc79383..d80a446 100644 --- a/messenger.go +++ b/messenger.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "io/ioutil" "net/http" "time" ) @@ -120,9 +121,28 @@ func (m *Messenger) ProfileByID(id int64) (Profile, error) { client := &http.Client{} resp, err := client.Do(req) + if err != nil { + return p, err + } defer resp.Body.Close() - err = json.NewDecoder(resp.Body).Decode(&p) + content, err := ioutil.ReadAll(resp.Body) + if err != nil { + return p, err + } + + err = json.Unmarshal(content, &p) + if err != nil { + return p, err + } + + if p == *new(Profile) { + qr := QueryResponse{} + err = json.Unmarshal(content, &qr) + if qr.Error != nil { + err = fmt.Errorf("Facebook error : %s", qr.Error.Message) + } + } return p, err } @@ -152,9 +172,12 @@ func (m *Messenger) GreetingSetting(text string) error { client := &http.Client{} resp, err := client.Do(req) + if err != nil { + return err + } defer resp.Body.Close() - return err + return checkFacebookError(resp.Body) } // CallToActionsSetting sends settings for Get Started or Persist Menu @@ -181,9 +204,12 @@ func (m *Messenger) CallToActionsSetting(state string, actions []CallToActionsIt client := &http.Client{} resp, err := client.Do(req) + if err != nil { + return err + } defer resp.Body.Close() - return err + return checkFacebookError(resp.Body) } // handle is the internal HTTP handler for the webhooks. diff --git a/response.go b/response.go index 3d9fdcf..c183385 100644 --- a/response.go +++ b/response.go @@ -16,6 +16,33 @@ const ( SendMessageURL = "https://graph.facebook.com/v2.6/me/messages" ) +// QueryResponse is the response sent back by Facebook when setting up things +// like greetings or call-to-actions +type QueryResponse struct { + Error *QueryError `json:"error,omitempty"` + Result string `json:"result,omitempty"` +} + +// QueryError is representing an error sent back by Facebook +type QueryError struct { + Message string `json:"message"` + Type string `json:"type"` + Code int `json:"code"` + FBTraceID string `json:"fbtrace_id"` +} + +func checkFacebookError(r io.Reader) error { + var err error + + qr := QueryResponse{} + err = json.NewDecoder(r).Decode(&qr) + if qr.Error != nil { + err = fmt.Errorf("Facebook error : %s", qr.Error.Message) + } + + return err +} + // Response is used for responding to events with messages. type Response struct { token string @@ -136,9 +163,12 @@ func (r *Response) ButtonTemplate(text string, buttons *[]StructuredMessageButto client := &http.Client{} resp, err := client.Do(req) + if err != nil { + return err + } defer resp.Body.Close() - return err + return checkFacebookError(resp.Body) } // GenericTemplate is a message which allows for structural elements to be sent @@ -173,9 +203,12 @@ func (r *Response) GenericTemplate(elements *[]StructuredMessageElement) error { client := &http.Client{} resp, err := client.Do(req) + if err != nil { + return err + } defer resp.Body.Close() - return err + return checkFacebookError(resp.Body) } // SenderAction sends a info about sender action @@ -201,9 +234,12 @@ func (r *Response) SenderAction(action string) error { client := &http.Client{} resp, err := client.Do(req) + if err != nil { + return err + } defer resp.Body.Close() - return err + return checkFacebookError(resp.Body) } // SendMessage is the information sent in an API request to Facebook.