Go SDK
Introduction
To understand how to use this SDK, it is best to read the following documentation:
API Reference
This SDK wraps the Server API and (amongst other things) exposes the responses of the webservice calls as Go objects. Understanding the Acquiring API will help you understand these SDK objects as well.
The explanation of all the various
features
we offer.
This current document will help you understand the global flow when interacting with the Worldline platform using the Go SDK.
Introduction
To understand how to use this SDK, it is best to read the following documentation:
API Reference
This SDK wraps the Server API and (amongst other things) exposes the responses of the webservice calls as Go objects. Understanding the Acquiring API will help you understand these SDK objects as well.The explanation of all the various features we offer.
This current document will help you understand the global flow when interacting with the Worldline platform using the Go SDK.
The Go SDK helps you to communicate with the Acquiring API . More specifically, it offers a fluent Go API that provides access to all the functionality of the RESTful API. Below, we discuss the following topics in detail.
Initialization of the SDK
Errors
Logging
Advanced use: Connection pooling
Advanced use: Customization of the communication
Notes
The source code of the SDK is available on Github . There you can find installation instructions.
The API documentation of the latest version of the SDK is available here .
Initialization of the Go SDK
All Go code snippets presented in the API Reference assume you have initialized the Go SDK before using them in your Development Environment. This section details the initialization of the Go SDK.
Initializing is simple, and requires only one key task: use our acquiringsdk.CreateClient function to create an acquiringsdk.Client instance, which contains the actual methods to communicate with the Acquiring API.
The acquiringsdk.CreateClient function needs the following input information to provide you with an initialized acquiringsdk.Client .
The oAuth2TokenURI , oauth2ClientID and oauth2ClientSecret .
The name of the integrator, e.g. your company name
You can create an instance of acquiringsdk.Client using the acquiringsdk.CreateClient function with this code snippet:
conf, _ := acquiringsdk.CreateOAuth2Configuration("oauth2ClientId", "oauth2ClientSecret', "oath2TokenURI", "integrator")
client, _ := acquiringsdk.CreateClientFromConfiguration(conf)
This acquiring.Client instance offers connection pooling and can be reused for multiple concurrent API calls. Once it is no longer used it should be closed.
The client can be closed after usage by calling the following code right after the client is created:
defer client.Close()
Using CommunicatorConfiguration
You can specify more options by using a configuration.CommunicatorConfiguration object. You can configure extra properties on this object as needed. For example, using an in-memory TOML file:
// The oauth2TokenURI can remain empty here, it will be overwritten from the TOML data
conf, _ := acquiring.CreateOAuth2Configuration("oauth2ClientID", "oauth2ClientSecret", "", "integrator")
tomlData := `
ConnectTimeout = 5000000000
SocketTimeout = 300000000000
MaxConnections = 10
AuthorizationType = "OAuth2"
OAuth2TokenURI = "https://auth-test-eu-west-1.aws.bambora.com/connect/token"
[APIEndpoint]
host = "api.preprod.acquiring.worldline-solutions.com"
`
toml.Decode(tomlData, conf)
client, _ := acquirngsdk.CreateClientFromConfiguration(conf)
These values are the default values. We recommend keeping the timeout values at these values. See API endpoints for the possible hosts and token URIs.
If a proxy should be used, the configuration.CommunicatorConfiguration object should have one extra property set, Proxy * url.URL . If the proxy requires authentication, then this should be set as the Userinfo of the URL.
The timeouts are defined as time.Duration properties. When using TOML, these only support the default time unit, which is nanoseconds. To convert a number of seconds to nanoseconds, add 9 zeroes. For instance, the ConnectTimeout value above is 5 seconds, and the SocketTimeout value is 300 seconds (5 minutes).
Errors
All calls can return one of the following errors:
An errors.ValidationError if the request was not correct and couldn't be processed (HTTP status code 400)
An errors.AuthorizationError if the request was not allowed (HTTP status code 403)
An errors.IdempotenceError if an idempotent request caused a conflict (HTTP status code 409)
An errors.ReferenceError if an object was attempted to be referenced that doesn't exist or has been removed, or there was a conflict (HTTP status code 404, 409 or 410)
An errors.PlatformError if something went wrong on the Worldline platform. The Worldline platform was unable to process a message from a downstream system or the service that you're trying to reach is temporary unavailable (HTTP status code 500, 502 or 503)
An errors.APIError if the RESTful API returned any other error
A payment attempt can now be handled as follows:
response, err := client.V1().Acquirer(acquirerID).Merchant(merchantID).Payments().ProcessPayment(request, nil)
switch e := err.(type)
case *errors.ValidationError:
fmt.Println("Input validation error:", e.Detail())
case *errors.AuthorizationError:
fmt.Println("Authorization error:", e.Detail())
case *errors.ReferenceError:
fmt.Println("Incorrect object reference:", e.Detail())
case *errors.PlatformError:
fmt.Println("Error occurred at Worldline or a downstream partner/acquirer:", e.Detail())
case errors.APIError:
fmt.Println("Worldline error:", e.StatusCode(), ",", e.Detail())
default:
// An internal error
Error overview
The following table is a summary that shows when each of these errors will be returned:
HTTP status code |
Meaning |
Description |
Error Type |
---|---|---|---|
200 |
Successful |
Your request was processed correctly |
N/A |
201 |
Created |
Your request was processed correctly and a new resource was created.
|
N/A |
204 |
No Content |
Your request was processed correctly |
N/A |
400 |
Bad Request |
Your request is not correct and can't be processed. Please correct the mistake and try again. |
errors.ValidationError |
403 |
Not Authorized |
You're trying to do something that is not allowed or that you're not authorized to do. |
errors.AuthorizationError |
404 |
Not Found |
The object you were trying to access could not be found on the server. |
errors.ReferenceError |
409 |
Conflict |
Your idempotent request resulted in a conflict. The first request has not finished yet. |
errors.IdempotenceError |
409 |
Conflict |
Your request resulted in a conflict. Either you submitted a duplicate request or you're trying to create something with a duplicate key. |
errors.ReferenceError |
500 |
Internal Server Error |
Something went wrong on the Worldline platform. |
errors.PlatformError |
502 |
Bad Gateway |
The Worldline platform was unable to process a message from a downstream partner/acquirer. |
errors.PlatformError |
503 |
Service Unavailable |
The service that you're trying to reach is temporary unavailable.
|
errors.PlatformError |
other |
Unexpected error |
An unexpected error has occurred |
errors.APIError |
HTTP status code 401 responses are automatically handled by the SDK and will not result in an exception if your OAuth2 credentials are valid. The SDK will automatically try to renew the access token if it gets such a response.
Logging
The Go SDK supports logging of requests, responses, and errors of the API communication.
In order to start using the logging feature, an implementation of the logging.CommunicatorLogger interface should be provided. The SDK provides two example implementations for logging to os.Stdout ( logging.StdOutCommunicatorLogger ) and logging to a standard Go logger ( logging.DefaultLogCommunicatorLogger ).
Logging can be enabled by calling the EnableLogging method on an acquiringsdk.Client object, and providing the logger as an argument. The logger can subsequently be disabled by calling the DisableLogging method.
When logged messages contain sensitive data, this data is obfuscated.
The following code exemplifies the use of adding a logger:
conf, _ := acquiringsdk.CreateOAuth2Configuration("oauth2ClientId", "oauth2ClientSecret', "oath2TokenURI", "integrator")
client, _ := acquiringsdk.CreateClientFromConfiguration(conf)
logger, _ := logging.NewDefaultLogCommunicatorLogger(log.Logger{})
client.EnableLogging(logger)
//... Do some calls
client.DisableLogging()
Advanced use: Connection pooling
An acquiringsdk.Client created using the acquiringsdk.CreateClient or acquiringsdk.CreateClientFromConfiguration function will use its own connection pool. If multiple clients should share a single connection pool, the acquiringsdk.CreateCommunicatorFromConfiguration function should be used to first create a shared communicator.Communicator , then the acquiringsdk.CreateClientFromCommunicator function should be used to create acquiringsdk.Client instances that use that communicator.Communicator :
conf, _ := acquiringsdk.CreateOAuth2Configuration("oauth2ClientId", "oauth2ClientSecret', "oath2TokenURI", "integrator")
communicator, _ := acquiringsdk.CreateCommunicatorFromConfiguration(conf)
// create one or more clients using the shared communicator
client, _ := acquiringsdk.CreateClientFromCommunicator(communicator)
Instead of closing these acquiringsdk.Client instances, you should instead close the communicator.Communicator when it is no longer needed. This will close all acquiringsdk.Client instances that use the communicator.Communicator .
If instead one of the acquiringsdk.Client instances is closed, the communicator.Communicator will be closed as well. As a result, all other acquiringsdk.Client instances that use the communicator.Communicator will also be closed. Attempting to use a closed acquiringsdk.Client or communicator.Communicator will result in an error.
Just like acquiringsdk.Client , communicator.Communicator instances can be closed after usage by calling the following code right after the communicator is created:
defer communicator.Close()
Connection management
Just like acquiringsdk.Client , communicator.Communicator also has method CloseExpiredConnections that can be used to evict expired HTTP connections. You can call this method on the communicator.Communicator instead of on any of the acquiringsdk.Client instances. The effect will be the same.
Advanced use: Customization of the communication
An acquiringsdk.Client uses a communicator.Communicator to communicate with the RESTful API. A communicator.Communicator contains all the logic to transform a request object to an HTTP request and an HTTP response to a response object. The functionality of the communicator.Communicator is built on the following:
The RESTful Server API endpoint URI.
A communicator.Connection , which represents one or more HTTP connections to the Worldline server.
An authentication.Authenticator , which is used to sign your requests.
A communicator.MetadataProvider , which constructs the header with metadata of your server that is sent in requests for BI and fraud prevention purposes.
A json.Marshaller , which is used to marshal and unmarshal request and response objects to and from JSON.
For your convenience, an acquiringsdk.CommunicatorBuilder is provided to easily replace one or more of these components. For example, to instantiate an acquiringsdk.Client that uses your own implementation of communicator.Connection , you can use the following code snippet:
connection := YourConnection{}
conf, _ := acquiringsdk.CreateOAuth2Configuration("oauth2ClientId", "oauth2ClientSecret', "oath2TokenURI", "integrator")
communicatorBuilder, _ := acquiringsdk.CreateCommunicatorBuilderFromConfiguration(conf)
communicator, _ := communicatorBuilder.WithConnection(connection).Build()
client, _ := acquiringsdk.CreateClientFromCommunicator(communicator)
Logging
To facilitate implementing logging in a custom communicator.Connection , the SDK provides utility structs logging.RequestLogMessageBuilder and logging.ResponseLogMessageBuilder . These can be used to easily construct request and response messages. For instance:
// In the below code, logger is the logging.CommunicatorLogger set using EnableLogging.
// Note that it may be null if EnableLogging is not called.
requestID := createRequestID() // Create a unique id; function to be provided by you
requestLogMessageBuilder, _ := NewRequestLogMessageBuilder(requestID, method, uri,
obfuscation.DefaultBodyObfuscator(), obfuscation.DefaultHeaderObfuscator()
)
// add request headers to requestLogMessageBuilder
// if present, set the request body on requestLogMessageBuilder
logger.LogRequestLogMessage(requestLogMessageBuilder.BuildMessage().String())
start := time.Now()
// send the request
end := time.Now()
duration := end.Sub(start)
statusCode := ...
responseLogMessageBuilder, _ := NewResponseLogMessageBuilder(requestID, statusCode, duration,
obfuscation.DefaultBodyObfuscator(), obfuscation.DefaultHeaderObfuscator())
// add response headers to responseLogMessageBuilder
// if present, set the response body on responseLogMessageBuilder
logger.LogResponseLogMessage(responseLogMessageBuilder.BuildMessage().String())
Notes
Error handling
Many of the code snippets presented on this page ignore errors returned by function or method calls for simplicity. When using the SDK in production, make sure that all errors are properly handled.
Renaming of properties
The Go SDK uses Go naming conventions as much as possible. The first letter of each property is turned into upper case, and several acronyms in properties have been turned into upper case. For example, paymentId is called PaymentID .