Go-клиент для PayPal API

от автора

Всем привет! Мы разрабатываем сервис для сбора, доставки и анализа логов, серверная часть которого написана на Go. В этой статье мы расскажем о проблеме, с которой мы столкнулись при подключении нашего проекта к платежной системе PayPal и о решении, которое мы разработали и успешно внедрили.

Итак, у многих есть опыт работы с API PayPal, использовать OAuth 2.0 довольно просто: подключаем библиотеку-клиент в свой проект и начинаем реализацию.

Для PHP, Java и Python существуют официальные SDK библиотеки, но наш сервис написан на GO, и в этом случае поиск SDK не дал нам приемлемых результатов(https://github.com/search?q=paypal+golang). В итоге найдено пять проектов на github, два из которых выглядят достойно, но имеют ограниченный функционал:

Нам был необходим клиент с возможностью расширения и улучшения функционала, поэтому было принято решение написать свой велосипед.

OAuth 2.0

На этапе разработки мы использовали PayPal sandbox, где проводили тестирование всех видов запросов API.

Первый этап — это работа с протоколом PayPal и авторизация. PayPal использует OAuth версии 2.0. Для начала нам необходимо получить приватные ключи (client_id и secret_key).

Авторизация осуществляется следующим образом: после получения client_id и secret_key необходимо сделать запрос в PayPal на получение access_token, который действителен в течении заданного времени. Далее все запросы в PayPal API должны сопровождаться этим токеном в заголовке запроса (-u ":").

Реализация с использованием нашего клиента:

import "github.com/logpacker/PayPal-Go-SDK" // ... // Create a client instance c, err := paypalsdk.NewClient("clientID", "secretID", paypalsdk.APIBaseSandBox) accessToken, err := c.GetAccessToken() 

Далее объект клиента будет иметь все доступные методы для работы с API. Например, чтобы создать платеж нам необходимо выполнить следующее:

paymentResponse, err := client.CreatePayment(p) 

Мы работаем над тем, чтобы предоставить и описать все доступные операции API, при этом есть возможность вызвать любой конечный метод посредством базовых функций:

req, err := c.NewRequest(method, url, payload) c.SendWithAuth(req, &resp) 

Все запросы в PayPal можно логировать в файл, полный дамп запроса сохраняется вместе с заголовками:

c.SetLogFile("/tpm/paypal-debug.log") 

Доступные функции API

Полный список функций PayPal API представлен в спецификации, все они делятся на группы, Payments, Orders, Vault. В клиенте мы реализовали встроенные функции для основных операций API:

POST /v1/oauth2/token — получение временного access_token

accessToken, err := c.GetAccessToken() 

За сохранение ключа отвечает приложение, поэтому вместо получения нового ключа можно установить сохраненный.

token := "abcdef" c.SetAccessToken(token) 

POST /v1/payments/payment — создание платежа в PayPal. Мы предоставили две функции для создания платежа.

Внутренний PayPal платеж:

amount := paypalsdk.Amount{     Total:    "7.00",     Currency: "USD", } redirectURI := "http://example.com/redirect-uri" cancelURI := "http://example.com/cancel-uri" description := "Description for this payment" paymentResult, err := c.CreateDirectPaypalPayment(amount, redirectURI, cancelURI, description) 

2. Платеж любого типа:

p := paypalsdk.Payment{     Intent: "sale",     Payer: &paypalsdk.Payer{         PaymentMethod: "credit_card",         FundingInstruments: []paypalsdk.FundingInstrument{paypalsdk.FundingInstrument{             CreditCard: &paypalsdk.CreditCard{                 Number:      "4111111111111111",                 Type:        "visa",                 ExpireMonth: "11",                 ExpireYear:  "2020",                 CVV2:        "777",                 FirstName:   "John",                 LastName:    "Doe",             },         }},     },     Transactions: []paypalsdk.Transaction{paypalsdk.Transaction{         Amount: &paypalsdk.Amount{             Currency: "USD",             Total:    "7.00",         },         Description: "My Payment",     }},     RedirectURLs: &paypalsdk.RedirectURLs{         ReturnURL: "http://...",         CancelURL: "http://...",     }, } paymentResponse, err := client.CreatePayment(p) 

GET /v1/payments/payment/ID — получение информации о платеже

payment, err := c.GetPayment(paymentID) 

GET /v1/payments/payment — список всех платежей

payments, err := c.GetPayments() 

GET /v1/payments/authorization/ID — получение информации об авторизации

authID := "2DC87612EK520411B" auth, err := c.GetAuthorization(authID) 

POST /v1/payments/authorization/ID/capture — блокировка авторизации

capture, err := c.CaptureAuthorization(authID, &paypalsdk.Amount{Total: "7.00", Currency: "USD"}, true) 

POST /v1/payments/authorization/ID/void — отмена авторизации

auth, err := c.VoidAuthorization(authID) 

POST /v1/payments/authorization/ID/reauthorize — реавторизация

auth, err := c.ReauthorizeAuthorization(authID, &paypalsdk.Amount{Total: "7.00", Currency: "USD"}) 

GET /v1/payments/sale/ID — получение объекта продажи

saleID := "36C38912MN9658832" sale, err := c.GetSale(saleID) 

POST /v1/payments/sale/ID/refund — возврат средств для объекта продажи. Можно сделать как полный возврат платежа, так и частичный.

// Full refund, err := c.RefundSale(saleID, nil) // Partial refund, err := c.RefundSale(saleID, &paypalsdk.Amount{Total: "7.00", Currency: "USD"}) 

GET /v1/payments/refund/ID — получение информации о возврате

orderID := "O-4J082351X3132253H" refund, err := c.GetRefund(orderID) 

GET /v1/payments/orders/ID — получение информации о заказе

order, err := c.GetOrder(orderID) 

POST /v1/payments/orders/ID/authorize — авторизация заказа

auth, err := c.AuthorizeOrder(orderID, &paypalsdk.Amount{Total: "7.00", Currency: "USD"}) 

POST /v1/payments/orders/ID/capture — блокировка заказа (может быть частичной или полной, в зависимости от переданных Amount и IsFinalTransaction)

capture, err := c.CaptureOrder(orderID, &paypalsdk.Amount{Total: "7.00", Currency: "USD"}, true, nil) 

POST /v1/payments/orders/ID/do-void — отмена заказа

order, err := c.VoidOrder(orderID) 

Также можно воспользоваться godoc документацией для ознакомления со всеми функциями клиента: https://godoc.org/github.com/logpacker/PayPal-Go-SDK

Тестирование и CI

В проекте реализованы два типа тестов: Unit и Integration. Unit тесты позволяют проверить работоспособность внутренних условий и валидацию.
Пример проверки входных параметров в функции NewClient:

_, err := NewClient("", "", "") if err == nil { 	t.Errorf("All arguments are required in NewClient()") } else { 	fmt.Println(err.Error()) } 

Интеграционные тесты работают непосредственно с тестовыми данными на PayPal Sandbox, проверяют ответы сервера и их преобразования в go-структуры.

Данный процесс представлен на схеме ниже:

Пример проверки ответа функции CreateDirectPaypalPayment:

c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) c.GetAccessToken()  amount := Amount{ 	Total:    "15.11", 	Currency: "USD", }  p, err := c.CreateDirectPaypalPayment(amount, "http://example.com", "http://example.com", "test payment")  if err != nil || p.ID == "" { 	t.Errorf("Test paypal payment is not created") } 

Мы создали тестовый аккаунт в песочнице PayPal и используем тестовые ID для каждого вида запроса. Например, на платеже с ID PAY-5YK922393D847794YKER7MUI можно тестировать получение информации о нем. Для того, чтобы сообщить клиенту, что вы работаете с Sandbox, вам необходимо установить базовый URL API (и после тестирования поменять его на Live URL):

c, err := paypalsdk.NewClient("clientID", "secretID", paypalsdk.APIBaseSandBox) 

Тесты могут быть запущены локально командой go test, но нельзя быть всегда уверенным, что код в репозитории будет всегда стабильным. Поэтому мы используем Continuous Integration (CI) для автоматического запуска теста при каждом пуше в репозиторий. Мы используем TravisCI, он легко интегрируется с GitHub репозиторием, в корне нашего проекта лежит конфигурация .travis.yml:

language: go go:  - 1.5 install:  - export PATH=$PATH:$HOME/gopath/bin script:  - go test -v 

Open Source и ближайшие планы

Все наши наработки вы можете найти на GitHub, они опубликованы под MIT лицнзией. В планах создать некую стандартную библиотеку для Go, обеспечить полное покрытие API (+webapps и т.д.)

Актуальную документацию можно найти на странице проекта в GitHub.

Ждем ваших коммитов и pull-реквестов на logpacker/PayPal-Go-SDK.

ссылка на оригинал статьи http://habrahabr.ru/post/274555/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *