📜 ⬆️ ⬇️

PayPal API Go Client



Hello! We are developing a service for collecting, delivering and analyzing logs, the server part of which is written in Go . In this article, we will talk about the problem we encountered when connecting our project to the PayPal payment system and the solution we developed and successfully implemented.

So, many have experience with the PayPal API, using OAuth 2.0 is quite simple: we plug the client library into our project and start the implementation.

For PHP, Java and Python, there are official SDK libraries, but our service is written in GO, and in this case, the search for SDK did not give us acceptable results ( https://github.com/search?q=paypal+golang ). As a result, five projects were found on github, two of which look decent, but have limited functionality:
')

We needed a client with the ability to expand and improve the functionality, so it was decided to write his bike .

OAuth 2.0


At the development stage, we used the PayPal sandbox , where we tested all kinds of API requests.

The first step is to work with the PayPal protocol and authorization. PayPal uses OAuth version 2.0. First we need to get private keys (client_id and secret_key).

Authorization is carried out as follows: after receiving client_id and secret_key, it is necessary to make a request to PayPal to receive an access_token, which is valid for a specified time. Further, all requests to the PayPal API must be accompanied by this token in the request header (-u ":").



Implementation using our client:

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


Further, the client object will have all available methods for working with the API. For example, to create a payment, we need to do the following:

 paymentResponse, err := client.CreatePayment(p) 


We are working to provide and describe all the available API operations , while it is possible to call any final method using basic functions:

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


All requests to PayPal can be logged to a file, the full request dump is saved along with the headers:

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


API Functions Available


A complete list of PayPal API functions is provided in the specification , they are all divided into groups, Payments, Orders, Vault. In the client, we implemented built-in functions for basic API operations:

POST / v1 / oauth2 / token - receive temporary access_token

 accessToken, err := c.GetAccessToken() 


The application is responsible for saving the key, so instead of receiving a new key, you can set the saved one.

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


POST / v1 / payments / payment - create a payment in PayPal. We provided two functions for making a payment.

Internal PayPal Payment:

 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. Payment of any type:

 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 - getting information about payment

 payment, err := c.GetPayment(paymentID) 


GET / v1 / payments / payment - a list of all payments

 payments, err := c.GetPayments() 


GET / v1 / payments / authorization / ID - getting authorization information

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


POST / v1 / payments / authorization / ID / capture - block authorization

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


POST / v1 / payments / authorization / ID / void - cancel authorization

 auth, err := c.VoidAuthorization(authID) 


POST / v1 / payments / authorization / ID / reauthorize - reauthorization

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


GET / v1 / payments / sale / ID - getting the object of sale

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


POST / v1 / payments / sale / ID / refund - return of funds for the object of sale. You can make a full refund or partial 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 - getting information about the return

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


GET / v1 / payments / orders / ID - getting information about the order

 order, err := c.GetOrder(orderID) 


POST / v1 / payments / orders / ID / authorize - order authorization

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


POST / v1 / payments / orders / ID / capture - order blocking (can be partial or complete, depending on the transferred Amount and IsFinalTransaction)

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


POST / v1 / payments / orders / ID / do-void - order cancellation

 order, err := c.VoidOrder(orderID) 


You can also use godoc documentation to familiarize yourself with all client functions: https://godoc.org/github.com/logpacker/PayPal-Go-SDK

Testing and CI


Two types of tests are implemented in the project: Unit and Integration. Unit tests allow you to check the performance of internal conditions and validation.
An example of checking input parameters in the NewClient function:

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


Integration tests work directly with the test data on PayPal Sandbox, check the server responses and convert them to go-structures.

This process is presented in the diagram below:



An example of checking the response of the CreateDirectPaypalPayment function:

 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") } 


We created a test account in the PayPal sandbox and use test IDs for each type of request. For example, on a payment with ID PAY-5YK922393D847794YKER7MUI, you can test getting information about it. In order to inform the client that you are working with Sandbox, you need to set the base URL of the API (and after testing change it to Live URL):

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


Tests can be run locally with the go test command, but one cannot always be sure that the code in the repository will always be stable. Therefore, we use Continuous Integration (CI) to automatically run the test every time we push into the repository. We use TravisCI , it easily integrates with the GitHub repository, at the root of our project is the configuration .travis.yml:

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


Open Source and immediate plans


All our insights can be found on GitHub, they are published under MIT license. Plans to create some standard Go library, to provide full API coverage (+ webapps, etc.)

Current documentation can be found on the project page in GitHub.

We are waiting for your commits and pull requests to logpacker / PayPal-Go-SDK .

Source: https://habr.com/ru/post/274555/


All Articles