Skip to content

Commit

Permalink
Attach the Request ID to relevant SDK exceptions (#23)
Browse files Browse the repository at this point in the history
* Attach the Request ID to relevant SDK exceptions

* fix build

* typo
  • Loading branch information
maxence-charriere authored Jan 2, 2020
1 parent 085b486 commit 81ed1a1
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 19 deletions.
1 change: 1 addition & 0 deletions .semaphore/semaphore.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ blocks:
- sem-version go 1.12
- go get github.com/stretchr/testify/...
- go get github.com/google/uuid
- go get github.com/tidwall/gjson
- go test -v ./...
14 changes: 3 additions & 11 deletions pkg/auditlog/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"sync"
"time"

"github.com/workos-inc/workos-go/pkg/workos"
)

// Client represents a client that performs auditlog request to WorkOS API.
Expand Down Expand Up @@ -76,13 +76,5 @@ func (c *Client) Publish(ctx context.Context, e Event) error {
}
defer res.Body.Close()

if res.StatusCode < 200 || res.StatusCode >= 300 {
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return fmt.Errorf("%s: %s", res.Status, err)
}
return fmt.Errorf("%s: %s", res.Status, body)
}

return nil
return workos.TryGetHTTPError(res)
}
12 changes: 4 additions & 8 deletions pkg/sso/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ package sso
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
"sync"
"time"

"github.com/workos-inc/workos-go/pkg/workos"
)

// ConnectionType represents a connection type.
Expand Down Expand Up @@ -158,12 +158,8 @@ func (c *Client) GetProfile(ctx context.Context, opts GetProfileOptions) (Profil
}
defer res.Body.Close()

if res.StatusCode < 200 || res.StatusCode >= 300 {
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return Profile{}, fmt.Errorf("%s: %s", res.Status, err)
}
return Profile{}, fmt.Errorf("%s: %s", res.Status, body)
if err = workos.TryGetHTTPError(res); err != nil {
return Profile{}, err
}

var body struct {
Expand Down
47 changes: 47 additions & 0 deletions pkg/workos/http.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package workos

import (
"fmt"
"io/ioutil"
"net/http"

"github.com/tidwall/gjson"
)

// TryGetHTTPError returns an error when the http response contains invalid
// status code.
func TryGetHTTPError(r *http.Response) error {
if r.StatusCode >= 200 && r.StatusCode < 300 {
return nil
}

var msg string

body, err := ioutil.ReadAll(r.Body)
if err != nil {
msg = err.Error()
} else if m := gjson.GetBytes(body, "message").Str; m != "" {
msg = m
} else {
msg = string(body)
}

return HTTPError{
Code: r.StatusCode,
Status: r.Status,
RequestID: r.Header.Get("X-Request-ID"),
Message: msg,
}
}

// HTTPError represents an http error.
type HTTPError struct {
Code int
Status string
RequestID string
Message string
}

func (e HTTPError) Error() string {
return fmt.Sprintf("%s: request id %q: %s", e.Status, e.RequestID, e.Message)
}
71 changes: 71 additions & 0 deletions pkg/workos/http_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package workos

import (
"net/http"
"net/http/httptest"
"testing"

"github.com/stretchr/testify/require"
)

func TestGetHTTPErrorWithJSONPayload(t *testing.T) {
rec := httptest.NewRecorder()
rec.Header().Set("X-Request-ID", "GOrOXx")
rec.WriteHeader(http.StatusUnauthorized)
rec.WriteString(`{"message":"unauthorized"}`)

err := TryGetHTTPError(rec.Result())
require.Error(t, err)

httperr := err.(HTTPError)
require.Equal(t, http.StatusUnauthorized, httperr.Code)
require.Equal(t, "401 Unauthorized", httperr.Status)
require.Equal(t, "GOrOXx", httperr.RequestID)
require.Equal(t, "unauthorized", httperr.Message)

t.Log(httperr)
}

func TestGetHTTPErrorWithTextPayload(t *testing.T) {
rec := httptest.NewRecorder()
rec.Header().Set("X-Request-ID", "GOrOXx")
rec.WriteHeader(http.StatusUnauthorized)
rec.WriteString("unauthorized msg")

err := TryGetHTTPError(rec.Result())
require.Error(t, err)

httperr := err.(HTTPError)
require.Equal(t, http.StatusUnauthorized, httperr.Code)
require.Equal(t, "401 Unauthorized", httperr.Status)
require.Equal(t, "GOrOXx", httperr.RequestID)
require.Equal(t, "unauthorized msg", httperr.Message)

t.Log(httperr)
}

func TestGetHTTPErrorWithoutRequestID(t *testing.T) {
rec := httptest.NewRecorder()
rec.WriteHeader(http.StatusUnauthorized)
rec.WriteString(`{"message":"unauthorized"}`)

err := TryGetHTTPError(rec.Result())
require.Error(t, err)

httperr := err.(HTTPError)
require.Equal(t, http.StatusUnauthorized, httperr.Code)
require.Equal(t, "401 Unauthorized", httperr.Status)
require.Empty(t, httperr.RequestID)
require.Equal(t, "unauthorized", httperr.Message)

t.Log(httperr)
}

func TestGetHTTPErrorNoError(t *testing.T) {
rec := httptest.NewRecorder()
rec.Header().Set("X-Request-ID", "GOrOXx")
rec.WriteHeader(http.StatusOK)

err := TryGetHTTPError(rec.Result())
require.NoError(t, err)
}

0 comments on commit 81ed1a1

Please sign in to comment.