From 3a2323e1ef1ca1046ffbfaa6b7311af661f6f2c9 Mon Sep 17 00:00:00 2001 From: Aliaksandr Pliutau Date: Fri, 30 Oct 2015 14:02:32 +0700 Subject: [PATCH] little fixes after understanding --- README.md | 17 ++++++++ auth.go | 71 ++++++++++++++++-------------- auth_test.go | 50 ++++++++++----------- client.go | 111 ++++++++++++++++++++--------------------------- client_test.go | 10 ++--- examples/main.go | 28 +++++------- payment.go | 4 +- types.go | 17 ++------ 8 files changed, 147 insertions(+), 161 deletions(-) diff --git a/README.md b/README.md index 4b848ed..da7c98e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,20 @@ [![Build Status](https://travis-ci.org/logpacker/paypalsdk.svg?branch=master)](https://travis-ci.org/logpacker/paypalsdk) PayPal REST API + +#### Usage + +``` +// Create a client instance +c, err := paypalsdk.NewClient("clietnid", "secret", paypalsdk.APIBaseSandBox) +``` + +``` +// Redirect client to this URL with provided redirect URI and necessary scopes. It's necessary to retreive authorization_code +authCodeURL, err := c.GetAuthorizationCodeURL("https://example.com/redirect-uri", []string{"address"}) +``` + +``` +// When you will have authorization_code you can get an access_token +accessToken, err := c.GetAccessToken(authCode, "https://example.com/redirect-uri") +``` diff --git a/auth.go b/auth.go index 1153be0..526c16e 100644 --- a/auth.go +++ b/auth.go @@ -1,52 +1,57 @@ package paypalsdk import ( - "net/http" - "strings" - "net/url" - "errors" - "bytes" - "fmt" + "bytes" + "errors" + "fmt" + "net/http" + "net/url" + "strings" ) // GetAuthorizationCodeURL returns URL where we need to redirect user // After signin in PayPal get authorization_code on redirectURI func (c *Client) GetAuthorizationCodeURL(redirectURI string, scopes []string) (string, error) { - if redirectURI == "" { - return "", errors.New("redirectURI cannot be empty") - } + if redirectURI == "" { + return "", errors.New("redirectURI cannot be empty") + } - if len(scopes) == 0 { - scopes = []string{"profile", "email"} - } + if len(scopes) == 0 { + scopes = []string{"profile", "email"} + } - return c.APIBase + "/webapps/auth/protocol/openidconnect/v1/authorize?client_id=" + - url.QueryEscape(c.ClientID) + "&response_type=code&scope=" + strings.Join(scopes, "+") + - "&redirect_uri=" + url.QueryEscape(redirectURI), nil + return c.APIBase + "/webapps/auth/protocol/openidconnect/v1/authorize?client_id=" + + url.QueryEscape(c.ClientID) + "&response_type=code&scope=" + strings.Join(scopes, "+") + + "&redirect_uri=" + url.QueryEscape(redirectURI), nil } -// GetRefreshToken returns struct of RefreshTokenResponse +// GetAccessToken returns struct of TokenResponse // Client must to get an authorization code before // redirectURI must match with redirectURI sent to GetAuthorizationCodeURL -func (c *Client) GetRefreshToken(authorizationCode string, redirectURI string) (*RefreshTokenResponse, error) { - if authorizationCode == "" { - return &RefreshTokenResponse{}, errors.New("authorizationCode cannot be empty") - } - if redirectURI == "" { - return &RefreshTokenResponse{}, errors.New("redirectURI cannot be empty") - } +func (c *Client) GetAccessToken(authorizationCode string, redirectURI string) (*TokenResponse, error) { + if authorizationCode == "" { + return &TokenResponse{}, errors.New("authorizationCode cannot be empty") + } + if redirectURI == "" { + return &TokenResponse{}, errors.New("redirectURI cannot be empty") + } - buf := bytes.NewBuffer([]byte("grant_type=authorization_code&code=" + url.QueryEscape(authorizationCode) + "&redirect_uri=" + url.QueryEscape(redirectURI))) - req, err := http.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/identity/openidconnect/tokenservice"), buf) - if err != nil { - return &RefreshTokenResponse{}, err - } + buf := bytes.NewBuffer([]byte("grant_type=authorization_code&code=" + url.QueryEscape(authorizationCode) + "&redirect_uri=" + url.QueryEscape(redirectURI))) + req, err := http.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/identity/openidconnect/tokenservice"), buf) + if err != nil { + return &TokenResponse{}, err + } - req.SetBasicAuth(c.ClientID, c.Secret) - req.Header.Set("Content-type", "application/x-www-form-urlencoded") + req.SetBasicAuth(c.ClientID, c.Secret) + req.Header.Set("Content-type", "application/x-www-form-urlencoded") - r := RefreshTokenResponse{} - err = c.Send(req, &r) + t := TokenResponse{} + err = c.Send(req, &t) - return &r, err + // Set Token fur current Client + if t.Token != "" { + c.Token = &t + } + + return &t, err } diff --git a/auth_test.go b/auth_test.go index 52895e0..031c40f 100644 --- a/auth_test.go +++ b/auth_test.go @@ -1,40 +1,40 @@ package paypalsdk import ( - "testing" + "testing" ) func TestGetAuthorizationCodeURL(t *testing.T) { - c, _ := NewClient("clid", "secret", APIBaseSandBox) + c, _ := NewClient("clid", "secret", APIBaseSandBox) - _, err := c.GetAuthorizationCodeURL("", []string{}) - if err == nil { - t.Errorf("redirectURI is required in GetAuthorizationCodeURL") - } + _, err := c.GetAuthorizationCodeURL("", []string{}) + if err == nil { + t.Errorf("redirectURI is required in GetAuthorizationCodeURL") + } - uri, err := c.GetAuthorizationCodeURL("test", []string{}) - if uri != "https://api.sandbox.paypal.com/webapps/auth/protocol/openidconnect/v1/authorize?client_id=clid&response_type=code&scope=profile+email&redirect_uri=test" { - t.Errorf("GetAuthorizationCodeURL returns incorrect value for redirectURI=test") - } + uri, err := c.GetAuthorizationCodeURL("test", []string{}) + if uri != "https://api.sandbox.paypal.com/webapps/auth/protocol/openidconnect/v1/authorize?client_id=clid&response_type=code&scope=profile+email&redirect_uri=test" { + t.Errorf("GetAuthorizationCodeURL returns incorrect value for redirectURI=test") + } - uri, err = c.GetAuthorizationCodeURL("test", []string{"address"}) - if uri != "https://api.sandbox.paypal.com/webapps/auth/protocol/openidconnect/v1/authorize?client_id=clid&response_type=code&scope=address&redirect_uri=test" { - t.Errorf("GetAuthorizationCodeURL returns incorrect value for redirectURI=test and scope=address") - } + uri, err = c.GetAuthorizationCodeURL("test", []string{"address"}) + if uri != "https://api.sandbox.paypal.com/webapps/auth/protocol/openidconnect/v1/authorize?client_id=clid&response_type=code&scope=address&redirect_uri=test" { + t.Errorf("GetAuthorizationCodeURL returns incorrect value for redirectURI=test and scope=address") + } } -func TestGetRefreshToken(t *testing.T) { - c, _ := NewClient("clid", "secret", APIBaseSandBox) +func TestGetAccessToken(t *testing.T) { + c, _ := NewClient("clid", "secret", APIBaseSandBox) - _, err := c.GetRefreshToken("123", "") - if err == nil { - t.Errorf("redirectURI is required in GetRefreshToken") - } + _, err := c.GetAccessToken("123", "") + if err == nil { + t.Errorf("redirectURI is required in GetRefreshToken") + } - _, err = c.GetRefreshToken("", "123") - if err == nil { - t.Errorf("authorizationCode is required in GetRefreshToken") - } + _, err = c.GetAccessToken("", "123") + if err == nil { + t.Errorf("authorizationCode is required in GetRefreshToken") + } - _, err = c.GetRefreshToken("123", "123") + _, err = c.GetAccessToken("123", "123") } diff --git a/client.go b/client.go index 09123ab..480e020 100644 --- a/client.go +++ b/client.go @@ -1,87 +1,68 @@ package paypalsdk import ( - "encoding/json" - "io/ioutil" - "net/http" - "errors" - "bytes" - "fmt" - "io" + "encoding/json" + "errors" + "io" + "io/ioutil" + "net/http" ) // NewClient returns new Client struct func NewClient(clientID string, secret string, APIBase string) (*Client, error) { - if clientID == "" || secret == "" || APIBase == "" { - return &Client{}, errors.New("ClientID, Secret and APIBase are required to create a Client") - } + if clientID == "" || secret == "" || APIBase == "" { + return &Client{}, errors.New("ClientID, Secret and APIBase are required to create a Client") + } - return &Client{ - &http.Client{}, - clientID, - secret, - APIBase, - nil, - }, nil -} - -// GetAcessToken request a new access token from Paypal -func (c *Client) GetAccessToken() (*TokenResponse, error) { - buf := bytes.NewBuffer([]byte("grant_type=client_credentials")) - req, err := http.NewRequest("POST", fmt.Sprintf("%s%s", c.APIBase, "/oauth2/token"), buf) - if err != nil { - return &TokenResponse{}, err - } - - req.SetBasicAuth(c.ClientID, c.Secret) - req.Header.Set("Content-type", "application/x-www-form-urlencoded") - - t := TokenResponse{} - err = c.Send(req, &t) - - return &t, err + return &Client{ + &http.Client{}, + clientID, + secret, + APIBase, + nil, + }, nil } // Send makes a request to the API, the response body will be // unmarshaled into v, or if v is an io.Writer, the response will // be written to it without decoding func (c *Client) Send(req *http.Request, v interface{}) error { - // Set default headers - req.Header.Set("Accept", "application/json") - req.Header.Set("Accept-Language", "en_US") + // Set default headers + req.Header.Set("Accept", "application/json") + req.Header.Set("Accept-Language", "en_US") - // Default values for headers - if req.Header.Get("Content-type") == "" { - req.Header.Set("Content-type", "application/json") - } + // Default values for headers + if req.Header.Get("Content-type") == "" { + req.Header.Set("Content-type", "application/json") + } - resp, err := c.client.Do(req) - if err != nil { - return err - } - defer resp.Body.Close() + resp, err := c.client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() - if resp.StatusCode < 200 || resp.StatusCode > 299 { - errResp := &ErrorResponse{Response: resp} - data, err := ioutil.ReadAll(resp.Body) + if resp.StatusCode < 200 || resp.StatusCode > 299 { + errResp := &ErrorResponse{Response: resp} + data, err := ioutil.ReadAll(resp.Body) - if err == nil && len(data) > 0 { - json.Unmarshal(data, errResp) - } + if err == nil && len(data) > 0 { + json.Unmarshal(data, errResp) + } - return errResp - } + return errResp + } - if v != nil { - if w, ok := v.(io.Writer); ok { - io.Copy(w, resp.Body) - } else { - err = json.NewDecoder(resp.Body).Decode(v) - if err != nil { - return err - } - } - } + if v != nil { + if w, ok := v.(io.Writer); ok { + io.Copy(w, resp.Body) + } else { + err = json.NewDecoder(resp.Body).Decode(v) + if err != nil { + return err + } + } + } - return nil + return nil } diff --git a/client_test.go b/client_test.go index 6f42818..8082f06 100644 --- a/client_test.go +++ b/client_test.go @@ -1,12 +1,12 @@ package paypalsdk import ( - "testing" + "testing" ) func TestNewClient(t *testing.T) { - _, err := NewClient("", "", "") - if err == nil { - t.Errorf("All arguments are required in NewClient()") - } + _, err := NewClient("", "", "") + if err == nil { + t.Errorf("All arguments are required in NewClient()") + } } diff --git a/examples/main.go b/examples/main.go index 932e754..c17dff9 100644 --- a/examples/main.go +++ b/examples/main.go @@ -1,26 +1,18 @@ package main import ( - "paypalsdk" + "paypalsdk" - "fmt" - "os" + "fmt" + "os" ) func main() { - client, err := paypalsdk.NewClient("AZgwu4yt5Ba0gyTu1dGBH3txHCJbMuFNvrmQxBaQbfDncDiCs6W_rwJD8Ir-0pZrN-_eq7n9zVd8Y-5f", "EBzA1wRl5t73OMugOieDj_tI3vihfJmGl47ukQT-cpctooIzDu0K7IPESNC0cKodlLSOXzwI8qXSM0rd", paypalsdk.APIBaseSandBox) - if err == nil { - fmt.Println("DEBUG: ClientID=" + client.ClientID + " APIBase=" + client.APIBase) - } else { - fmt.Println("ERROR: " + err.Error()) - os.Exit(1) - } - - token, err := client.GetAccessToken() - if err == nil { - fmt.Println("DEBUG: Access token=" + token.Token) - } else { - fmt.Println("ERROR: " + err.Error()) - os.Exit(1) - } + client, err := paypalsdk.NewClient("AZgwu4yt5Ba0gyTu1dGBH3txHCJbMuFNvrmQxBaQbfDncDiCs6W_rwJD8Ir-0pZrN-_eq7n9zVd8Y-5f", "EBzA1wRl5t73OMugOieDj_tI3vihfJmGl47ukQT-cpctooIzDu0K7IPESNC0cKodlLSOXzwI8qXSM0rd", paypalsdk.APIBaseSandBox) + if err == nil { + fmt.Println("DEBUG: ClientID=" + client.ClientID + " APIBase=" + client.APIBase) + } else { + fmt.Println("ERROR: " + err.Error()) + os.Exit(1) + } } diff --git a/payment.go b/payment.go index 0625261..00af5e3 100644 --- a/payment.go +++ b/payment.go @@ -2,7 +2,7 @@ package paypalsdk import () -// CreateDirectCreditCardPatment sends request with payment -func CreateDirectCreditCardPatment(cc CreditCrad, amount Amount) error { +// CreateDirectCreditCardPayment sends request with payment +func CreateDirectCreditCardPayment(cc CreditCard, amount Amount) error { return nil } diff --git a/types.go b/types.go index d7d5f00..0b97f96 100644 --- a/types.go +++ b/types.go @@ -25,18 +25,9 @@ type ( // TokenResponse maps to the API response for the /oauth2/token endpoint TokenResponse struct { - Scope string `json:"scope"` - Token string `json:"access_token"` - Type string `json:"token_type"` - AppID string `json:"app_id"` - ExpiresIn int `json:"expires_in"` - } - - // RefreshTokenResponse maps to the API response for the /v1/identity/openidconnect/tokenservice - RefreshTokenResponse struct { - Type string `json:"token_type"` RefreshToken string `json:"refresh_token"` - AccessToken string `json:"access_token"` + Token string `json:"access_token"` + Type string `json:"token_type"` ExpiresIn int `json:"expires_in"` } @@ -56,8 +47,8 @@ type ( Issue string `json:"issue"` } - // CreditCrad - All info about customer's CC - CreditCrad struct { + // CreditCard - All info about customer's CC + CreditCard struct { Type string Number string ExpireYear int