This project contains documentation and other resources related to IBM Cloud SDKs
Table of Contents
- Overview
- SDK Project Catalog
- Using the SDK
- SDK Structure
- Importing a service in your application
- Constructing service clients
- Authentication
- Passing parameters to operations
- Receiving operation responses
- Pagination
- Sending HTTP headers
- Transaction IDs
- Configuring the HTTP Client
- Configuring Request Timeouts
- Automatic retries
- Disabling SSL Verification - Discouraged
- Error Handling
- Logging
- Synchronous and asynchronous requests
- Questions
- Open source @ IBM
- License
IBM Cloud SDK client libraries allow developers to programmatically interact with various IBM Cloud services. SDKs are provided for the following languages:
- Go
- Java
- Node.js
- Python
The following table provides links to the various IBM Cloud SDK projects associated with IBM Cloud service categories:
This section provides general information on how to use the services contained in an IBM Cloud SDK client library. The programming examples below will illustrate how the various activities can be performed for each of the programming languages mentioned above using a mythical service named "Example Service" that is defined in example-service.yaml.
When you use an IBM Cloud SDK client library within your application to interact with a particular IBM Cloud service, your application code will appear to be invoking local functions rather than invoking REST operations over the network.
In fact, your application is invoking local functions that are provided by the SDK client library. Each SDK client library contains a collection of one or more related IBM Cloud services, where each service "client" - the client-side view of a particular IBM Cloud service - is implemented in its own class (Java, Node.js, Python) or struct (Go). Within this class or struct, there will be methods that represent the various operations that are defined in the API for that service. The function contained within each of these methods handles the various steps of invoking a REST operation over the network:
- constructing an HTTP request message
- sending the request message to the server via the network
- receiving the HTTP response message from the server
- consuming the response message and returning the results back to your application code
The mythical "Example Service" service client mentioned above is implemented as:
- Go: the
ExampleServiceV1
struct within theexampleservicev1
package - Java: the
ExampleService
class within thecom.ibm.cloud.mysdk.example_service.v1
package - Node.js: the
ExampleServiceV1
class within theexample-service/v1
module - Python: the
ExampleServiceV1
class within theexample_service_v1
module
Each IBM Cloud SDK project includes a README.md file which contains a table of the services included in that SDK project, along with language-specific information needed for you to use these services within your application code.
Before you can use a particular service within your application, you first need to import the correct language-specific programming constructs (package, class, struct, etc.) from the SDK client library that contains that service.
Go
For Go SDK client libraries, each IBM Cloud service will exist within its own package in the Go module that represents the SDK project as a whole. To use the mythical "Example Service" service client in your Go application, you would add an import to your application code like this:import {
"github.com/IBM/mysdk/exampleservicev1"
}
Note: this example assumes that the "Example Service" service client exists in
the exampleservicev1
package within the github.com/IBM/mysdk
module.
Be sure to consult the service table for the Go SDK client library you are using
to obtain the correct module import path and service package name for the service(s) that
you will use in your application.
After you add this import to your application, you can run the command go mod tidy
to automatically add the necessary module import to your application's go.mod
file.
Alternatively, you can manually add github.com/IBM/mysdk <version>
to your go.mod
file's
require
section, where <version>
represents the version of the SDK project that you
would like to use. For more details about the go.mod
file, please see this
reference.
Java
For Java SDK client libraries, each IBM Cloud service is packaged within its own jar containing the classes associated with that service. Each jar is identified by its artifact coordinates, which consist of the jar's group id, artifact id and version in the form:<group-id>:<artifact-id>:<version>
For example, the mythical "Example Service" service client might be contained within the
jar with artifact coordinates: com.ibm.cloud:example-service:1.0.0
.
The service table within each Java SDK project's README.md file will include the
artifact coordinates for each service contained in the project.
Before you can use a service in your application, you first need to define a dependency within your project's maven pom.xml file or gradle build script.
For maven, a dependency defined for the "Example Service" would look like this:
<dependency>
<groupId>com.ibm.cloud</groupId>
<artifactId>example-service</artifactId>
<version>1.0.0</version>
</dependency>
For gradle, the dependency would look like this:
compile 'com.ibm.cloud:example-service:1.0.0'
Be sure to consult the service table for the Java SDK client library you are using to obtain the correct artifact coordinates for the service(s) you will use in your application.
After defining an appropriate dependency within your build script, you would then import the classes needed by your application. For example, in order to construct an instance of the "Example Service" service client in your application, you would need to import the java class that implements that service, like this:
import com.ibm.cloud.mysdk.example_service.v1.ExampleService;
Your application will likely use a collection of various classes provided by the service's jar in addition to the primary class for that service. Be sure to include import statements in your application for each class that you need to use from the service's jar.
Note that some Java SDK client libraries provide a collection of javadocs for the various classes provided by that client library (look for a link on the Java SDK project's main github.com page). If present, these javadocs can be consulted to explore the set of available classes and determine which classes might be needed by your application.
Node.js
For Node.js SDK client libraries, each IBM Cloud service exists within its own folder inside the package that represents the SDK project as a whole. To use the mythical "Example Service" service client in your Node.js application, add an import to your application like this:const ExampleServiceV1 = require('mysdk/example-service/v1');
You would also need to add a dependency for the mysdk
package within your application project's
package.json
file as well.
Note: this example assumes that the "Example Service" service client exists in the
example-service
folder contained within the mysdk
package.
Be sure to consult the service table for the Node.js SDK client library you are using to obtain the correct import path for the service(s) you will use in your application.
Python
For Python SDK client libraries, each IBM Cloud service exists in its own module inside the package that represents the SDK project as a whole. To use the mythical "Example Service" service client in your Python application, add an import like this:from mysdk import ExampleServiceV1
This imports the ExampleServiceV1
class, which is the primary class associated with
the "Example Service" service client.
If your application needs to use additional service-related definitions (such as classes
which model the schemas in the service's API definition), use an import like this:
from mysdk.example_service_v1 import Resource, Resources
Note: in this example, Resource
and Resources
are classes that are defined
in the service's module (in addition to the ExampleServiceV1 service class).
If you would like to import all definitions related to a particular service, you can use an import like this:
from mysdk.example_service_v1 import *
Be sure to consult the service table for the Python SDK client library you are using to obtain the correct module name and service class name for the service(s) you will use in your application.
The SDK allows you to construct the service client in one of two ways:
- Setting client options programmatically
- Using external configuration properties
Here's an example of how to construct an instance of the "Example Service" client while specifying various client options (authenticator, service endpoint URL, etc.) programmatically:
Go
import {
"github.com/IBM/go-sdk-core/v5/core"
"github.com/IBM/mysdk/exampleservicev1"
}
// Create an IAM authenticator.
authenticator := &core.IamAuthenticator{
ApiKey: "<iam-api-key>",
}
// Construct an "options" struct for creating the service client.
options := &exampleservicev1.ExampleServiceV1Options{
Authenticator: authenticator, // required
URL: "https://example-service.cloud.ibm.com/v1", // optional
}
// Construct the service client.
myService, err := exampleservicev1.NewExampleServiceV1(options)
if err != nil {
panic(err)
}
// Service operations can now be invoked using the "myService" variable.
Java - for Java core versions prior to 9.7.0 (deprecated)
import com.ibm.cloud.mysdk.example_service.v1.ExampleService;
import com.ibm.cloud.sdk.core.security.Authenticator;
import com.ibm.cloud.sdk.core.security.IamAuthenticator;
// Create an IAM authenticator.
Authenticator authenticator = new IamAuthenticator("<iam-api-key>");
// Construct the service client.
ExampleService myService = new ExampleService(ExampleService.DEFAULT_SERVICE_NAME, authenticator);
// Set our custom service URL (optional).
myService.setServiceUrl("https://example-service.cloud.ibm.com/v1");
// Service operations can now be called using the "myService" variable.
Java - for Java core version 9.7.0 and above
import com.ibm.cloud.mysdk.example_service.v1.ExampleService;
import com.ibm.cloud.sdk.core.security.Authenticator;
import com.ibm.cloud.sdk.core.security.IamAuthenticator;
// Create an IAM authenticator.
Authenticator authenticator = new IamAuthenticator.Builder()
.apikey("<iam-api-key>")
.build();
// Construct the service client.
ExampleService myService = new ExampleService(ExampleService.DEFAULT_SERVICE_NAME, authenticator);
// Set our custom service URL (optional).
myService.setServiceUrl("https://example-service.cloud.ibm.com/v1");
// Service operations can now be called using the "myService" variable.
Node.js
const ExampleServiceV1 = require('mysdk/example-service/v1');
const { IamAuthenticator } = require('mysdk/auth');
// Create an IAM authenticator.
const authenticator = new IamAuthenticator({
apikey: '<iam-api-key>',
});
// Construct the service client.
const myService = new ExampleServiceV1({
authenticator, // required
serviceUrl: 'https://example-service.cloud.ibm.com/v1', // optional
});
// Service operations can now be invoked using the "myService" variable.
Python
from mysdk import ExampleServiceV1
from ibm_cloud_sdk_core.authenticators import IAMAuthenticator
# Create an IAM authenticator.
authenticator = IAMAuthenticator('<iam-api-key>')
# Construct the service client.
my_service = ExampleServiceV1(authenticator=authenticator)
# Set our custom service URL (optional)
my_service.set_service_url('https://example-service.cloud.ibm.com/v1')
# Service operations can now be invoked using the "my_service" variable.
For a typical application deployed to the IBM Cloud, it might be convenient or necessary to avoid hard-coding certain service client options (IAM API Key, service URL, etc.) within the application. Instead, the SDK allows you to store these values in configuration properties external to your application.
First, define the configuration properties to be used by your application. These properties can be implemented as either:
- Exported environment variables
- Stored in a credentials file.
In the examples that follow, we'll use environment variables to implement our configuration properties.
Each property name is of the form: <service-name>_<property-key>
.
Here is an example of some configuration properties for the "Example Service" service:
export EXAMPLE_SERVICE_URL=https://example-service.cloud.ibm.com/v1
export EXAMPLE_SERVICE_AUTH_TYPE=iam
export EXAMPLE_SERVICE_APIKEY=<iam-api-key>
The service name "example_service" is the default service name for the "Example Service" client, so the SDK will (by default) look for properties that start with this prefix folded to upper case.
After you have defined the configuration properties for your application, you can construct an instance of the service client like the examples below:
Go
// Construct service client via config properties using default service name ("example_service")
myService, err := exampleservicev1.NewExampleServiceV1UsingExternalConfig(
&exampleservicev1.ExampleServiceV1Options{})
if err != nil {
panic(err)
}
The NewExampleServiceV1UsingExternalConfig
function will:
- construct an authenticator using the environment variables above (an IAM authenticator using
"<iam-api-key>"
as the api key). - initialize the service client to use service URL "https://example-service.cloud.ibm.com/v1".
Java
import com.ibm.cloud.mysdk.example_service.v1.ExampleService;
ExampleService myService = ExampleService.newInstance();
The ExampleService.newInstance()
method will:
- construct an authenticator using the environment variables above (an IAM authenticator using
"<iam-api-key>"
as the api key). - initialize the service client to use service URL "https://example-service.cloud.ibm.com/v1".
Node.js
const ExampleServiceV1 = require('mysdk/example-service/v1');
const myService = ExampleServiceV1.newInstance();
The ExampleServiceV1.newInstance()
method will:
- construct an authenticator using the environment variables above (an IAM authenticator using
"<iam-api-key>"
as the api key). - initialize the service client to use service URL "https://example-service.cloud.ibm.com/v1".
Python
from mysdk import ExampleServiceV1
my_service = ExampleServiceV1.new_instance()
The ExampleServiceV1.new_instance()
method will:
- construct an authenticator using the environment variables above (an IAM authenticator using
"<iam-api-key>"
as the api key). - initialize the service client to use service URL "https://example-service.cloud.ibm.com/v1".
Instead of exporting your configuration properties as environment variables, you can store the properties in a credentials file. Here is an example of a credentials file that contains the properties from the examples above:
# Contents of "mycredentials.env"
EXAMPLE_SERVICE_URL=https://example-service.cloud.ibm.com/v1
EXAMPLE_SERVICE_AUTH_TYPE=iam
EXAMPLE_SERVICE_APIKEY=iam-api-key
You would then provide the name of the credentials file via the IBM_CREDENTIALS_FILE
environment variable:
export IBM_CREDENTIALS_FILE=/myfolder/mycredentials.env
When the SDK needs to look for configuration properties, it will detect the IBM_CREDENTIALS_FILE
environment
variable, then load the properties from the specified file.
The URLs used to construct service clients - either programmatically, or via external configuration - are not validated. Take care that your URL is valid, ensuring at least the presence of a valid protocol and host.
Note that a user information component should not be present as it may interfere with the correct operation of the configured authenticators, for example by forcing the SDK's underlying HTTP client to add an additional authentication scheme.
The above examples provide a glimpse of two specific ways to provide external configuration to the SDK
(environment variables and credentials file specified via the IBM_CREDENTIALS_FILE
environment variable).
The complete configuration-loading process supported by the SDK is as follows:
- Look for a credentials file whose name is specified by the
IBM_CREDENTIALS_FILE
environment variable - Look for a credentials file at
<current-working-directory>/ibm-credentials.env
- Look for a credentials file at
<user-home-directory>/ibm-credentials.env
- Look for environment variables whose names start with
<upper-case-service-name>_
(e.g.EXAMPLE_SERVICE_
)
At each of the above steps, if one or more configuration properties are found for the specified service, those properties are then returned to the SDK and any subsequent steps are bypassed.
IBM Cloud SDKs support a variety of authentication schemes through the use of authenticators.
An authenticator is a component that supports a specific type of authentication and is associated with a service client. When an operation is invoked on a service client, the service client uses the associated authenticator instance to "authenticate" the outbound request, which typically involves adding an Authorization header containing an appropriate security token.
Examples of authenticators include:
- Basic Authentication: supports a basic auth username and password
- Bearer Token Authentication: supports a user-supplied bearer token
- Identity and Access Management (IAM) Authentication: supports a user-supplied API key that is automatically exchanged for an IAM access token by interacting with the IAM token service.
- Container Authentication: supports IAM-based authentication within a Kubernetes-managed compute resource in which the Compute Resource Identity feature is configured
- VPC Instance Authentication: supports IAM-based authentication within a VPC-managed compute resource in which the Compute Resource Identity feature is configured
- Cloud Pack for Data Authentication: supports authentication flows implemented specifically as part of the Cloud Pack for Data offering
- Multi-Cloud Saas Platform (MCSP) Authentication: supports a user-supplied API key that is automatically exchanged for an access token by interacting with the MCSP offering's token service
Detailed information about these authenticators can be found in the various language-specific core libraries:
IBM Cloud services support token-based Identity and Access Management (IAM) authentication. The information within the rest of this section will focus on the use of Identity and Access Management (IAM) authentication and will demonstrate how you can construct and use an IAM Authenticator instance. For other types of authenticators, you can see similar usage details within the language-specific documentation linked above.
With IAM authentication, you supply an API key and the authenticator will exchange that API key for an access token (a bearer token) by interacting with the IAM token service. The access token is then added (via the Authorization header) to each outbound request to provide the required authentication information.
Access tokens are valid only for a limited amount of time and must be periodically refreshed. The IAM authenticator will automatically detect the need to refresh the access token and will interact with the IAM token service as needed to obtain a fresh access token, relieving the SDK user from that burden.
There are two ways to construct and use an IAM authenticator:
- programmatically
- from configuration
In this scenario, you construct an IAM authenticator instance, supplying your IAM API key programmatically.
The IAM authenticator will:
- Use your API key to obtain an access token from the IAM token service
- Ensure that the access token is valid
- Include the access token in each outbound request within an Authorization header
- Refresh the access token when it expires
Go
import {
"github.com/IBM/go-sdk-core/v5/core"
"<appropriate-git-repo-url>/exampleservicev1"
}
...
// Create the authenticator.
authenticator, err := core.NewIamAuthenticatorBuilder().
SetApiKey("myapikey").
Build()
if err != nil {
panic(err)
}
// Create the service options struct.
options := &exampleservicev1.ExampleServiceV1Options{
Authenticator: authenticator,
}
// Construct the service instance.
service, err := exampleservicev1.NewExampleServiceV1(options)
if err != nil {
panic(err)
}
// 'service' can now be used to invoke operations.
Java - for Java core versions prior to 9.7.0 (deprecated)
import com.ibm.cloud.sdk.core.security.Authenticator;
import com.ibm.cloud.sdk.core.security.IamAuthenticator;
import com.ibm.cloud.mysdk.example_service.v1.ExampleService;
Authenticator authenticator = new IamAuthenticator("<iam-api-key>");
ExampleService service = new ExampleService(ExampleService.DEFAULT_SERVICE_NAME, authenticator);
Java - for Java core version 9.7.0 and above
import com.ibm.cloud.sdk.core.security.IamAuthenticator;
import <sdk_base_package>.ExampleService.v1.ExampleService;
...
// Create the authenticator.
IamAuthenticator authenticator = new IamAuthenticator.Builder()
.apikey("myapikey")
.build();
// Create the service instance.
ExampleService service = new ExampleService(ExampleService.DEFAULT_SERVICE_NAME, authenticator);
// 'service' can now be used to invoke operations.
Node.js
const { IamAuthenticator } = require('ibm-cloud-sdk-core');
const ExampleServiceV1 = require('<sdk-package-name>/example-service/v1');
const authenticator = new IamAuthenticator({
apikey: 'myapikey',
});
const options = {
authenticator,
};
const service = new ExampleServiceV1(options);
// 'service' can now be used to invoke operations.
Python
from ibm_cloud_sdk_core.authenticators import IAMAuthenticator
from <sdk-package-name>.example_service_v1 import *
# Create the authenticator.
authenticator = IAMAuthenticator('myapikey')
# Construct the service instance.
service = ExampleServiceV1(authenticator=authenticator)
# 'service' can now be used to invoke operations.
In this scenario, you define the IAM API key in external configuration properties, and then construct the service client using the SDK's configuration-based interface. This allows you to avoid hard-coding your API key within your application code or having to concern yourself with loading it from configuration properties.
The programming examples in this section assume that external configuration properties like the following have been configured:
export EXAMPLE_SERVICE_AUTH_TYPE=iam
export EXAMPLE_SERVICE_APIKEY=myapikey
Go
import {
"<appropriate-git-repo-url>/exampleservicev1"
}
...
// Create the service options struct.
options := &exampleservicev1.ExampleServiceV1Options{
ServiceName: "example_service",
}
// Construct the service instance.
service, err := exampleservicev1.NewExampleServiceV1UsingExternalConfig(options)
if err != nil {
panic(err)
}
// 'service' can now be used to invoke operations.
Java
import <sdk_base_package>.ExampleService.v1.ExampleService;
...
// Create the service instance.
ExampleService service = ExampleService.newInstance("example_service");
// 'service' can now be used to invoke operations.
Node.js
const ExampleServiceV1 = require('<sdk-package-name>/example-service/v1');
const options = {
serviceName: 'example_service',
};
const service = ExampleServiceV1.newInstance(options);
// 'service' can now be used to invoke operations.
Python
from <sdk-package-name>.example_service_v1 import *
# Construct the service instance.
service = ExampleServiceV1.new_instance(service_name='example_service')
# 'service' can now be used to invoke operations.
In this scenario, you are responsible for obtaining the access token from the IAM token service and refreshing or reacquiring it as needed. Once you obtain the access token, construct a Bearer Token authenticator and supply the access token.
Note that you can also construct a Bearer Token authenticator using external configuration properties, similar to Scenario 2 above with the IAM authenticator, but it is less useful to use that approach with the Bearer Token authenticator because you must manage the access token yourself.
Go
import {
"github.com/IBM/go-sdk-core/v5/core"
"<appropriate-git-repo-url>/exampleservicev1"
}
...
// Create the authenticator.
bearerToken := // ... obtain bearer token value ...
authenticator := core.NewBearerTokenAuthenticator(bearerToken)
if err != nil {
panic(err)
}
// Create the service options struct.
options := &exampleservicev1.ExampleServiceV1Options{
Authenticator: authenticator,
}
// Construct the service instance.
service, err := exampleservicev1.NewExampleServiceV1(options)
if err != nil {
panic(err)
}
// 'service' can now be used to invoke operations.
...
// Later, if your bearer token value expires, you can set a new one like this:
newToken := // ... obtain new bearer token value
authenticator.BearerToken = newToken
Java
import com.ibm.cloud.sdk.core.security.BearerTokenAuthenticator;
import <sdk_base_package>.ExampleService.v1.ExampleService;
...
String bearerToken = // ... obtain bearer token value ...
// Create the authenticator.
BearerTokenAuthenticator authenticator = new BearerTokenAuthenticator(bearerToken);
// Create the service instance.
ExampleService service = new ExampleService(ExampleService.DEFAULT_SERVICE_NAME, authenticator);
// 'service' can now be used to invoke operations.
...
// Later, if your bearer token value expires, you can set a new one like this:
newToken = // ... obtain new bearer token value
authenticator.setBearerToken(newToken);
Node.js
const { BearerTokenAuthenticator } = require('ibm-cloud-sdk-core');
const ExampleServiceV1 = require('<sdk-package-name>/example-service/v1');
const bearerToken = // ... obtain bearer token value ...
const authenticator = new BearerTokenAuthenticator({
bearerToken: bearerToken,
});
const options = {
authenticator,
};
const service = new ExampleServiceV1(options);
// 'service' can now be used to invoke operations.
...
// Later, if your bearer token value expires, you can set a new one like this:
newToken = // ... obtain new bearer token value
authenticator.bearerToken = newToken;
Python
from ibm_cloud_sdk_core.authenticators import BearerTokenAuthenticator
from <sdk-package-name>.example_service_v1 import *
# Create the authenticator.
authenticator = BearerTokenAuthenticator(<your_bearer_token>)
# Construct the service instance.
service = ExampleServiceV1(authenticator=authenticator)
# 'service' can now be used to invoke operations.
...
# Later, if your bearer token value expires, you can set a new one like this:
new_token = '<new token>'
authenticator.set_bearer_token(new_token);
For certain languages (namely Go, Java and Node.js) a structure is defined for each operation as a container for the parameters associated with that operation.
The use of these parameter container structures (instead of listing each operation parameter within the argument list of the operations) allows for future expansion of the API (within certain guidelines) without impacting application compatibility.
The language-specific sections that follow provide additional information and examples regarding these parameter container structures:
Go
For Go, a struct is defined for each operation, where the name of the struct will be
<operation-name>Options
and it will contain a field for each operation parameter.
Here's an example of an options struct for the GetResource
operation:
// GetResourceOptions : The GetResource options.
type GetResourceOptions struct {
// The id of the resource to retrieve.
ResourceID *string `json:"resource_id" validate:"required"`
...
}
In this example, the GetResource
operation has one parameter - ResourceID
.
When invoking this operation, the application first creates an instance of the GetResourceOptions
struct, sets the parameter value within it, then passes the options struct instance to the operation.
Along with the "options" struct, a constructor function is also provided.
Here's an example:
options := myService.NewGetResourceOptions("resource-id-1")
result, detailedResponse, err := myService.GetResource(options)
Java
For Java, a class is defined for each operation, where the name of the class will be
<operation-name>Options
and it will contain a field for each operation parameter.
Here's an example of an options class for the getResource
operation:
/**
* The getResource options.
*/
public class GetResourceOptions extends GenericModel {
protected String resourceId;
...
}
In this example, the getResource
operation has one parameter - resourceId
.
When invoking this operation, the application first creates an instance of the GetResourceOptions
class, sets the parameter value within it, then passes the options class instance to the operation.
Along with the "options" class, a nested "Builder" class is also provided as a convenient way to
construct instances of the class using the Java "builder" pattern.
Here's an example:
import com.ibm.cloud.sdk.core.http.Response;
import com.ibm.cloud.mysdk.example_service.v1.ExampleService;
import com.ibm.cloud.mysdk.example_service.v1.model.GetResourceOptions;
import com.ibm.cloud.mysdk.example_service.v1.model.Resource;
...
ExampleService myService = /* construct service client instance */
GetResourceOptions options = new GetResourceOptions.Builder()
.resourceId("resource-id-1")
.build();
Response<Resource> response = myService.getResource(options).execute();
Resource result = response.getResult();
Node.js
For Node.js, an interface is defined for each operation, where the name of the interface will be
<operation-name>Params
and it will contain a field for each operation parameter.
Here's an example of a params object for the getResource
operation:
/** Parameters for the `getResource` operation. */
export interface GetResourceParams {
/** The id of the resource to retrieve. */
resourceId: string;
...
}
In this example, the getResource
operation has one parameter - resourceId
.
When invoking this operation, the application creates an instance of the GetResourceParams
interface, sets the parameter value within it, then passes the params object to the operation.
Here's an example:
const params = {
resourceId: 'resource-id-1',
}
myService.getResource(params).then(res => {
...
});
Python
Because the Python language supports named arguments (i.e. `kwargs`) there is no need to define any sort of container structure for parameters in order to allow for future expansion of the API without impacting applications.Here's an example of how the ExampleServiceV1.get_resource()
operation would be invoked:
detailedResponse = my_service.get_resource(resource_id='resource-id-1')
This section contains language-specific information about how an application receives operation responses.
Go
Each operation will return the following values:
result
- An operation-specific response object (if the operation is defined as returning a response object).detailedResponse
- An instance of thecore.DetailedResponse
struct. This will contain the following fields:
StatusCode
- the HTTP status code returned in the response messageHeaders
- the HTTP headers returned in the response message. Keys in the map are canonicalized (see CanonicalHeaderKey)Result
- the operation result (if available). This is the same value returned in theresult
return value mentioned above.RawResult
- the raw response body as a byte array if there was a problem un-marshalling a JSON response body or if the operation was unsuccessful and the response body content is not JSON.
err
- An error object. This will be nil if the operation was successful, or non-nil
if an error occurred.
Here is an example of how to access the response and get additional Information beyond the response object:
result, detailedResponse, err := myService.GetResource(options)
responseHeaders := detailedResponse.GetHeaders()
responseId := responseHeaders.Get("Response-Id")
Java
Each operation will return an instance of com.ibm.sdk.cloud.sdk.core.http.Response<T>
where T
is the class representing the specific
response model associated with the operation (operations that return no response object
will return an instance of com.ibm.sdk.cloud.sdk.core.http.Response<Void>
instead).
Here's an example of how to access that response and get additional information beyond the response object:
// Invoke the operation.
GetResourceOptions options = /* construct options model */
Response<Resource> response = myservice.getResource(options).execute();
// Extract the operation's response model instance (result).
Resource resource = response.getResult();
// Retrieve response headers.
Headers responseHeaders = response.getHeaders();
System.out.println("Response header names: " + responseHeaders.names());
String responseId = responseHeaders.values("response-id").get(0);
Node.js
Each operation will return a response via a Promise. The response is an object containing the result of the operation, HTTP status code and text message, and the HTTP response headers.
Here is an example of how to access the various fields and headers from an operation response:
myService.getResource({
'resourceId': 'resource-id-1',
}).then((response) => {
// result is the response object returned in the response body
// status is the HTTP status code returned in the response
// headers is the set of HTTP headers returned in the response
// statusText is the text message associated with the HTTP status code
const { result, status, headers, statusText } = response;
console.log(JSON.stringify(headers, null, 4));
transactionId = headers['response-id'];
}).catch((err) => {
if (err.status && err.statusText) {
console.log("Error status code: " + err.status + " (" + err.statusText + ")");
}
console.log("Error message: " + err.message);
});
Python
Each operation will return a DetailedResponse instance which encapsulates the operation response object (if applicable), the HTTP status code and response headers.
Here's an example of how to access that response and get additional information beyond the response object:
detailedResponse = my_service.get_resource(resource_id='resource-id-1')
print(detailedResponse)
responseHeaders = detailedResponse.get_headers()
responseId = responseHeaders.get('response-id')
This would display a DetailedResponse
instance having the structure:
{
'result': <response object returned by operation>,
'headers': { <http response headers> },
'status_code': <http status code>
}
For list-type operations that comply with the API Handbook's pagination requirements, SDKs may contain special "Pager" classes (Java, Node.js and Python) or structs (Go) that can be used as a convenience wrapper around the list-type operation.
This section provides language-specific examples of how to use these Pager classes and structs. Each Pager class or struct will contain the following methods (the actual language-specific names will be provided below in each language section):
has_next()
: returns true if there are potentially more items to be retrieved, or false otherwise.get_next()
: returns the next page of items by invoking the list-type operation. The number of items returned depends on the selected page size (limit parameter) and the number of remaining items that are available to be returned.get_all()
: returns all of the available items by repeatedly invoking the list-type operation. This operation should be used with caution. The use of this method with certain resource types might result in an excessive amount of data being returned. If in doubt, use thehas_next()
andget_next()
methods to retrieve a single page at a time, and process each page before retrieving the next page.
One thing to note is that each Pager class or struct uses the corresponding list-type operation to retrieve the actual items, and simply provides a more convenient way to invoke the operation. Examples will be provided in each language section below.
For the purposes of these examples, suppose that an API defines a Cloud
resource, and includes a list_clouds
operation that supports
token-based pagination
.
The operation returns an instance of the CloudCollection
schema, which contains a property named clouds
which is
an array of Cloud
instances. In this example, the Pager class or struct would be named CloudsPager
.
Go
For Go, the names of the methods provided in each Pager struct are:
HasNext()
GetNext()
GetAll()
This example shows how to use the HasNext()
and GetNext()
methods to
retrieve results one page at a time:
// Assume that 'myService' has already been initialized as in other code examples.
// Construct the 'ListClouds' options model and set page size to 10.
listCloudsOptions := myService.NewListCloudsOptions()
listCloudsOptions.SetLimit(int64(10))
// Construct the Pager.
pager, err := myService.NewCloudsPager(listCloudsOptions)
// Define a slice of Cloud instances to hold all of the results.
var allResults []exampleservicev1.Cloud
// Retrieve each page of results and add to "allResults".
for pager.HasNext() {
nextPage, err := pager.GetNext()
allResults = append(allResults, nextPage...)
}
// "allResults" will now contain all the Cloud instances that were
// returned by the successive invocations of the ListClouds() operation.
This example shows how to use the GetAll()
method to retrieve all the available results:
// Assume that 'myService' has already been initialized as in other code examples.
// Construct the 'ListClouds' options model and set page size to 10.
listCloudsOptions := myService.NewListCloudsOptions()
listCloudsOptions.SetLimit(int64(10))
// Construct the Pager.
pager, err := myService.NewCloudsPager(listCloudsOptions)
// Retrieve all of the results.
allResults, err := pager.GetAll()
// "allResults" will now contain all the Cloud instances that were
// returned by the successive invocations of the ListClouds() operation.
Java
For Java, the names of the methods provided in each Pager class are:
hasNext()
getNext()
getAll()
This example shows how to use the hasNext()
and getNext()
methods to
retrieve results one page at a time:
// Assume that 'myService' has already been initialized as in other code examples.
// Construct the 'listClouds' options model and set page size to 10.
ListCloudsOptions listCloudsOptions = new ListCloudsOptions.Builder()
.limit(10)
.build();
// Define a list of Cloud instances to hold all of the results.
List<Cloud> allResults = new ArrayList<>();
// Construct the Pager.
CloudsPager pager = new CloudsPager(myService, listCloudsOptions);
// Retrieve each page of results and add to "allResults".
while (pager.hasNext()) {
List<Cloud> nextPage = pager.getNext();
allResults.addAll(nextPage);
}
// "allResults" will now contain all the Cloud instances that were
// returned by the successive invocations of the listClouds() operation.
This example shows how to use the getAll()
method to retrieve all the available results:
// Assume that 'myService' has already been initialized as in other code examples.
// Construct the 'listClouds' options model and set page size to 10.
ListCloudsOptions listCloudsOptions = new ListCloudsOptions.Builder()
.limit(10)
.build();
// Construct the Pager.
CloudsPager pager = new CloudsPager(myService, listCloudsOptions);
// Retrieve all of the results.
List<Cloud> allResults = pager.getAll();
// "allResults" will now contain all the Cloud instances that were
// returned by the successive invocations of the listClouds() operation.
Node.js
For Node.js, the names of the methods provided in each Pager class are:
hasNext()
getNext()
getAll()
This example shows how to use the hasNext()
and getNext()
methods to
retrieve results one page at a time:
// Assume that 'myService' has already been initialized as in other code examples.
// Construct the 'listClouds' params object and set page size to 10.
const params = {
limit: 10,
};
// Define a list of Cloud instances to hold all of the results.
const allResults = [];
// Construct the Pager.
const pager = new ExampleServiceV1.CloudsPager(myService, params);
// Retrieve each page of results and add to "allResults".
while (pager.hasNext()) {
const nextPage = await pager.getNext();
allResults.push(...nextPage);
}
// "allResults" will now contain all the Cloud instances that were
// returned by the successive invocations of the listClouds() operation.
This example shows how to use the getAll()
method to retrieve all the available results:
// Assume that 'myService' has already been initialized as in other code examples.
// Construct the 'listClouds' params object and set page size to 10.
const params = {
limit: 10,
};
// Construct the Pager.
const pager = new ExampleServiceV1.CloudsPager(myService, params);
// Retrieve all of the results.
const allResults = await pager.getAll();
// "allResults" will now contain all the Cloud instances that were
// returned by the successive invocations of the listClouds() operation.
Python
For Python, the names of the methods provided in each Pager class are:
has_next()
get_next()
get_all()
This example shows how to use the has_next()
and get_next()
methods to
retrieve results one page at a time:
# Assume that 'my_service' has already been initialized as in other code examples.
# Define a list of Cloud instances to hold all of the results.
all_results = []
# Construct the Pager using 'my_service' as the client and a page size of 10.
pager = CloudsPager(
client=my_service,
limit=10,
)
# Retrieve each page of results and add to "all_results".
while pager.has_next():
next_page = pager.get_next()
all_results.extend(next_page)
# "all_results" will now contain all the Cloud instances that were
# returned by the successive invocations of the list_clouds() operation.
This example shows how to use the get_all()
method to retrieve all the available results:
# Assume that 'my_service' has already been initialized as in other code examples.
# Construct the Pager using 'my_service' as the client and a page size of 10.
pager = CloudsPager(
client=my_service,
limit=10,
)
# Retrieve all of the results.
all_results = pager.get_all()
# "all_results" will now contain all the Cloud instances that were
# returned by the successive invocations of the list_clouds() operation.
You can configure a set of custom HTTP headers in the service client instance and these headers will be included with all requests invoked from that client.
Go
For Go, the custom headers are set on the service client instance by using the
SetDefaultHeaders(http.Header)
function, like this:
customHeaders := http.Header{}
customHeaders.Add("Custom-Header", "custom_value")
myService.SetDefaultHeaders(customHeaders)
// "Custom-Header" will now be included with all requests invoked from "myservice".
Java
For Java, the custom headers are set on the service client instance by using the
setDefaultHeaders(Map<String, String> headers)
function, like this:
Map<String, String> headers = new HashMap<String, String>();
headers.put("Customer-Header", "custom_value");
myService.setDefaultHeaders(headers);
// "Custom-Header" will now be included with all subsequent requests invoked from "myservice".
Node.js
For Node.js, the custom headers are passed via the headers
field of the UserOptions
object
used to construct the service client instance, like this:
import ExampleServiceV1 from 'mysdk/example-service/v1';
const myService = ExampleServiceV1.newInstance({
headers: {
'Custom-Header': 'custom_value',
},
});
// "Custom-Header" will now be included with all requests invoked from "myService".
Python
For Python, the custom headers are set on the service client instance by using the
set_default_headers()
function, like this:
headers = {
'Custom-Header': 'custom_value'
}
my_service.set_default_headers(headers)
# "Custom-Header" will now be included with all requests invoked from "my_service".
You can also pass custom HTTP headers with an individual request.
Go
For Go, just add the custom headers to the "options" struct prior to calling the operation, like this:
options := myService.NewGetResourceOptions("resource-id-1")
customHeaders := make(map[string]string)
customHeaders["Custom-Header"] = "custom_value"
options.SetHeaders(customHeaders)
result, detailedResponse, err := myservice.GetResource(options)
// "Custom-Header" will be sent along with the "GetResource" request.
Java
For Java, just add the custom headers to the ServiceCall
object before calling the execute()
method, like this:
Response<Resource> response = myservice.getResource(options)
.addHeader("Custom-Header", "custom_value")
.execute();
Node.js
For Node.js, just add the custom headers to the "params" object via the optional headers
field prior to calling the operation, like this:
const getResourceParams = {
resourceId: 'resource-id-1',
headers: {
'Custom-Header': 'custom_value',
}
};
myService.getResource(getResourceParams).then(res => {
// Custom-Header will have been sent with this request
});
Python
For Python, just pass the optional headers
parameter when invoking the operation,
like this:
resourceInstance = my_service.get_resource(
resource_id='resource-id-1',
headers={'Custom-Header': 'custom_value'}).get_result()
Each API invocation will receive a response that contains a transaction ID in the HTTP header. This transaction ID can be useful for troubleshooting and accessing relevant logs from your service instance. Check the documentation of the service for the correct field name of this property.
Here are examples of how to retrieve the response header:
Go
result, detailedResponse, err := myService.GetResource(options)
transactionId := detailedResponse.GetHeaders().Get("transaction-id-field-name")
Java
For Java, you can retrieve headers from either the Response<T>
return value of the execute()
method, or from the exception in case of an error:
String transactionId;
try {
Response<Resource> response = myService.getResource(options).execute();
transactionId = response.getHeaders().values("transaction-id-field-name").get(0);
} catch (ServiceResponseException e) {
transactionId = e.getHeaders().values("transaction-id-field-name").get(0);
}
Node.js
const params = {
resourceId: 'resource-id-1',
}
myService.getResource(params).then(
response => {
transactionId = response.headers['transaction-id-field-name'];
},
err => {
transactionId = TBD;
}
);
Python
try:
response = my_service.get_resource(resource_id='resource-id-1')
transaction_id = response.get_headers().get('transaction-id-field-name')
except ApiException as e:
transaction_id = e.http_response.headers.get('transaction-id-field-name')
You have the ability to configure the underlying HTTP client that is used by the SDK to interact with the service endpoint. The sections below describe how this is done for each language.
Go
For Go, you can create your own http.Client
instance and set it on your service client,
like this:
import {
"net/http"
"time"
"github.com/IBM/go-sdk-core/v5/core"
}
// Construct a new http.Client instance with a user-supplied proxy function.
myHTTPClient := core.DefaultHTTPClient()
myHTTPClient.Transport.Proxy = myProxyFunc
// Set the service's Client field with the SetHTTPClient() method.
myService.Service.SetHTTPClient(myHttpClient)
// This request will use the user-supplied proxy function.
result, detailedResponse, err := myService.GetResource(options)
For more details on configuring the http.Client
instance,
see this link.
Java
For Java, you can configure certain HTTP client options by using the HttpConfigOptions
class
provided by the Java SDK Core library.
After configuring the HttpConfigOptions
instance, use the service client's
configureClient()
method to configure the HTTP client instance held by the service client,
like this:
import java.net.InetSocketAddress;
import java.net.Proxy;
import com.ibm.cloud.sdk.core.http.HttpConfigOptions;
// Configure a proxy in an HttpConfigOptions instance.
Proxy proxy =
new Proxy(Proxy.Type.HTTP, new InetSocketAddress("myproxy.mydomain.com", 8080));
HttpConfigOptions options =
new HttpConfigOptions.Builder().proxy(proxy).build();
myService.configureClient(options);
You can also use the service client's getClient()
and setClient()
methods to supply your own
OkHttpClient
instance, like this:
// Retrieve the current HTTP client instance.
OkHttpClient client = myService.getClient();
// Modify the call timeout to be 5 minutes.
client = client.newBuilder().callTimeout(5, TimeUnit.MINUTES).build();
// Set the new HTTP client on the service.
myService.setClient(client);
For more information about the OkHttpClient
class, please see
this link.
Node.js
For Node.js, you have full control over the HTTPS Agent used to make requests.
This is available for both the service client and the authenticators that make network requests
(e.g. IamAuthenticator
). The package axios
is used to make requests.
All axios
configuration parameters are supported by the
constructors of both service clients and authenticators.
Described below are scenarios where this configuration capability is needed.
Note that this functionality is applicable only for Node.js environments - these configurations will have
no effect in the browser.
In most scenarios, passing HTTP configuration parameters to the SDK client constructor is sufficient.
However, there may be cases in which access to the actual instance of axios
is necessary, such as setting interceptors.
For this purpose, use the method getHttpClient
on the service client instance.
import ExampleServiceV1 from 'ibm-mysdk/example-service/v1';
import { IamAuthenticator } from 'mysdk/auth';
const myService = new ExampleServiceV1({
authenticator: new IamAuthenticator({ apikey: '{apikey}' }),
});
const axiosInstance = myService.getHttpClient();
To invoke requests behind an HTTP proxy (e.g. firewall), a special tunneling agent must be used.
Use the package https-proxy-agent
for this.
Configure this agent with your proxy information, then pass it in as the HTTPS agent in the
service constructor and the authenticator constructor, if applicable.
Additionally, you must set proxy
to false
in the constructor(s).
Here's an example:
import { HttpsProxyAgent } from 'https-proxy-agent';
import ExampleServiceV1 from 'ibm-mysdk/example-service/v1';
import { IamAuthenticator } from 'mysdk/auth';
const proxyUrl = 'http://some.host.org:1234'; // Host: some.host.org, Port: 1234
const agent = new HttpsProxyAgent(proxyUrl);
const myService = new ExampleServiceV1({
authenticator: new IamAuthenticator({
apikey: '{apikey}',
httpsAgent: agent,
proxy: false,
}),
httpsAgent: agent,
proxy: false,
});
To send custom certificates as a security measure in your request, use the cert
, key
,
and/or ca
properties of the HTTPS Agent.
See this documentation
for more information about the options.
Note that the entire contents of the file must be provided - not just the file name.
import fs = require('fs');
import https = require('https');
import ExampleServiceV1 from 'ibm-mysdk/example-service/v1';
import { IamAuthenticator } from 'ibm-mysdk/auth';
const certFile = fs.readFileSync('./my-cert.pem');
const keyFile = fs.readFileSync('./my-key.pem');
const myService = new ExampleServiceV1({
authenticator: new IamAuthenticator({
apikey: '{apikey}',
httpsAgent: new https.Agent({
key: keyFile,
cert: certFile,
})
}),
httpsAgent: new https.Agent({
key: keyFile,
cert: certFile,
}),
});
Python
For Python, you can configure certain options in the underlying http client used to
invoke requests (e.g. timeout), you can use the set_http_config()
method, like this:
my_service.set_http_config({'timeout': 120})
response = my_service.get_resource(resource_id='resource-id-1').get_result()
Here is a list of some of the configuration properties that can be set with the set_http_config()
method:
To access the existing client, use the get_http_client
method. This returns the "Session" from the requests
package.
mySession = my_service.get_http_client()
mySession.headers.update({'x-my-header': 'true'})
The client can also be overriden or reset with the set_http_client
method.
newSession = requests.Session()
my_service.set_http_client(newSession)
For more information regarding http client configuration, please see this link
This section describes how to configure request timeouts in the various SDKs.
Go
The recommended way to configure request timeouts in a Go SDK is to use an instance of
context.Context
.
Starting with version 3.15.0 of the SDK generator, the Go generator now generates
two methods for each operation, one which accepts a context.Context
instance
as the first parameter and one with only the single "options model" parameter.
Here is an example of how to use the context.Context
to invoke an operation with a
10-second timeout:
// Create a context with a 10-second timeout.
ctx, cancelFunc := context.WithTimeout(context.Background(), 10 * time.Second)
defer cancelFunc()
// Create the resource.
result, detailedResponse, err := myService.CreateResourceWithContext(ctx, createResourceOptionsModel)
When constructing a Context, you receive two values - the context itself, along with the "cancel function".
The returned cancel function can also be invoked in order to cancel an in-flight request.
Note also that by using the context.Context
instance with the <operation-name>WithContext
method,
the timeout applies only to a single operation invocation.
By default, a service instance will use a default HTTP client with a 30-second connection timeout, and no request or read timeout. You can configure a client with your own timeout values, then set it on the service instance by calling the BaseService.SetHTTPClient()
method.
Java
Here is an example of how to set a request timeout in Java:// Retrieve the current HTTP client instance.
OkHttpClient client = myService.getClient();
// Modify the call timeout to be 10 seconds.
client = client.newBuilder().callTimeout(10, TimeUnit.SECONDS).build();
// Set the new HTTP client on the service.
myService.setClient(client);
The request timeout of 10 seconds will be used in each operation invoked using myService1
.
By default, the client has a 60-second connect timeout, a 90-second read timeout and a 60-second write timeout. The default client does not set a call timeout
(which covers the entire HTTP call... including the connection, write and read steps), but you can set that as in the example above.
Node
Here is an example of how to set a request timeout in Node:import ExampleServiceV1 from 'ibm-mysdk/example-service/v1';
import { IamAuthenticator } from 'ibm-mysdk/auth';
// Construct an instance of the service with a 10-second timeout (expressed in ms).
const myService = new ExampleServiceV1({
authenticator: new IamAuthenticator({ apikey: '{apikey}' }),
timeout: 10000,
});
The request timeout of 10 seconds will be used in each operation invoked using myService
.
By default the client has no request timeout.
Python
As mentioned in the "Configuring the HTTP Client" section above, you can configure the options in the http client as in this example:# Configure a 10-second combined timeout covering the connection and read operations.
# In other words, the server should start sending back the response within 10 seconds.
my_service.set_http_config({'timeout': 10})
This timeout setting will be used in each operation invoked using my_service
.
By default, the client will use a 60-second combined timeout, which means that the server should start sending back the response within 60 seconds.
Applications that invoke REST APIs sometimes encounter errors such as
429 - Too Many Requests
, 503 - Service Unavailable
, etc.
It can be inconvenient and time-consuming to code around these types of errors in your application.
This section provides information about how to enable automatic retries.
Go
The Go SDK supports a generalized retry feature that can automatically retry on common
errors. The default configuration (up to 4 retries with max retry interval of 30 seconds,
along with exponential backoff if no Retry-After
response header is present)
should suffice for most applications, but the retry feature
is customizable to support unique requirements.
Java
The Java SDK supports a generalized retry feature that can automatically retry on common
errors. The default configuration (up to 4 retries with max retry interval of 30 seconds,
along with exponential backoff if no Retry-After
response header is present)
should suffice for most applications, but the retry feature
is customizable to support unique requirements.
Node
The Node SDK supports a generalized retry feature that can automatically retry on common
errors. The default configuration (up to 4 retries,
max retry interval of 30 seconds, along with exponential backoff if no Retry-After
response
header is present) should suffice for most applications, but the retry feature is
customizable to support unique requirements.
Python
The Python SDK supports a generalized retry feature that can automatically retry on common
errors. The default configuration (up to 4 retries with max retry interval of 30 seconds,
along with exponential backoff if no Retry-After
response header is present)
should suffice for most applications, but the retry feature
is customizable to support unique requirements.
Go
To enable automatic retries programmatically in the Go SDK, use the service client's
EnableRetries()
method, as in this example:
// Construct the service client.
myService, err := exampleservicev1.NewExampleServiceV1(options)
// Enable automatic retries (with max retries 5, max interval 20 seconds).
myService.EnableRetries(5, 20 * time.Second)
// Create the resource.
result, detailedResponse, err := myService.CreateResource(createResourceOptionsModel)
In this example, the CreateResource()
operation will be retried up to 5 times
with a maximum retry interval of 20 seconds.
If a "retryable" error response (e.g. 429, 503, etc.) contains
the Retry-After
header, the value of that response header will be used
as the retry interval, subject to a maximum of 20 seconds. If no Retry-After
header
is found in the response, then an exponential backoff policy will be used such
that successive retries would use wait times of 1, 2, 4, 8 and 16 seconds.
Java
To enable automatic retries programmatically in the Java SDK, use the service client's `enableRetries()` method, as in this example:// Construct the service client.
myService = new ExampleServiceV1(serviceName, authenticator);
// Enable automatic retries (with max retries 5, max interval 20 seconds).
myService.enableRetries(5, 20);
// Create the resource.
CreateResourceOptions options = /* construct options model */
Response<Resource> response = myService.createResource(options).execute();
In this example, the createResource()
operation will be retried up to 5 times
with a maximum retry interval of 20 seconds.
If a "retryable" error response (e.g. 429, 503, etc.) contains
the Retry-After
header, the value of that response header will be used
as the retry interval, subject to a maximum of 20 seconds. If no Retry-After
header
is found in the response, then an exponential backoff policy will be used such
that successive retries would use wait times of 1, 2, 4, 8 and 16 seconds.
Node.js
To enable automatic retries programmatically in the Node SDK, use the service client's `enableRetries()` method, as in this example:// Construct the service client.
const myService = new ExampleServiceV1({ authenticator: myAuthenticator })
// Enable automatic retries (with max retries 5, max retry interval 20 seconds).
myService.enableRetries({ maxRetries: 5, maxRetryInterval: 20 });
// Create the resource.
const response = myService.createResource({ resourceId: "3", name: "Sample Book Title" });
In this example, the createResource()
operation will be retried up to 5 times
with a maximum retry interval of 20 seconds.
If a "retryable" error response (e.g. 429, 503, etc.) contains
the Retry-After
header, the value of that response header will be used
as the retry interval. If no Retry-After
header
is found in the response, then an exponential backoff policy will be used such
that successive retries would use wait times of 1, 2, 4, 8, and 16 seconds.
Python
To enable automatic retries programmatically in the Python SDK, use the service client's `enable_retries()` method, as in this example:// Construct the service client.
my_service = ExampleServiceV1(authenticator=my_authenticator)
// Enable automatic retries (with max retries 5, max retry interval 20.0 seconds).
my_service.enable_retries(max_retries=5, retry_interval=20.0)
// Create the resource.
response = my_service.create_resource(resource_id="3", name="Sample Book Title")
In this example, the create_resource()
operation will be retried up to 5 times
with a maximum retry interval of 20 seconds.
If a "retryable" error response (e.g. 429, 503, etc.) contains
the Retry-After
header, the value of that response header will be used
as the retry interval. If no Retry-After
header
is found in the response, then an exponential backoff policy will be used such
that successive retries would use wait times of 1, 2, 4, 8, and 16 seconds.
If you are constructing your service client with external configuration properties, you can enable automatic retries in the service client by setting properties as in the example below for the "Example Service" service:
export EXAMPLE_SERVICE_URL=https://example-service.cloud.ibm.com/v1
export EXAMPLE_SERVICE_AUTH_TYPE=iam
export EXAMPLE_SERVICE_APIKEY=<iam-api-key>
export EXAMPLE_SERVICE_ENABLE_RETRIES=true
export EXAMPLE_SERVICE_MAX_RETRIES=3
export EXAMPLE_SERVICE_RETRY_INTERVAL=20
If the <service-name>_ENABLE_RETRIES
property is defined as true
, then retries will be enabled.
You can optionally define the <service-name>_MAX_RETRIES
and <service-name>_RETRY_INTERVAL
properties to configure values for the maximum number of retries (default is 4) and maximum retry
interval (default is 30 seconds).
After setting these properties, be sure to construct your service client similar to the examples in the Construct service client section above.
The SDK allows you to configure the HTTP client to disable SSL verification.
Note that this has serious security implications - only do this if you really mean to!
If you are constructing your service client with external configuration properties, you can
disable SSL verification in both the authenticator and the service client by setting
the <service-name>_DISABLE_SSL
(service client) and <service-name>_AUTH_DISABLE_SSL
(authenticator) properties true
.
Here's an example of how to do this for the "Example Service" service:
export EXAMPLE_SERVICE_URL=https://example-service.cloud.ibm.com/v1
export EXAMPLE_SERVICE_AUTH_TYPE=iam
export EXAMPLE_SERVICE_APIKEY=<iam-api-key>
export EXAMPLE_SERVICE_DISABLE_SSL=true
export EXAMPLE_SERVICE_AUTH_DISABLE_SSL=true
After setting these properties, be sure to construct your service client similar to the examples in the Construct service client section above.
Alternatively, you can disable SSL verification programmatically. See the expandable sections below to see how this is done in each language:
Go
For Go, you can disable SSL verification in both the service client and in the authenticator like this:
// Construct authenticator with DisableSSLVerification true
authenticator := &core.IamAuthenticator{
ApiKey: "<iam-api-key>",
DisableSSLVerification: true,
}
// Construct service client
myService, err := exampleservicev1.NewExampleServiceV1(
&exampleservicev1.ExampleServiceV1Options{
Authenticator: authenticator,
}
}
if err != nil {
panic(err)
}
// Disable SSL verification in service client
myService.Service.DisableSSLVerification()
Note: for a given instance of a service client, the "disable SSL" and "automatic retries" features are mutually exclusive. Each feature requires a specific configuration of the underlying HTTP client and are not currently supported simultaneously.
Java - for Java core versions prior to 9.7.0 (deprecated)
For Java, you can disable SSL verification in both the authenticator and service client, like this:
Authenticator authenticator = new IamAuthenticator("<iam-api-key>");
authenticator.setDisableSSLVerification(true);
myService = new ExampleService(ExampleService.DEFAULT_SERVICE_NAME, authenticator);
HttpConfigOptions options =
new HttpConfigOptions.Builder().disableSslVerification(true).build();
myService.configureClient(options);
Java - for Java core version 9.7.0 and above
For Java, you can disable SSL verification in both the authenticator and service client, like this:
Authenticator authenticator = new IamAuthenticator.Builder()
.apikey("<iam-api-key>")
.disableSSLVerification(true)
.build();
myService = new ExampleService(ExampleService.DEFAULT_SERVICE_NAME, authenticator);
HttpConfigOptions options =
new HttpConfigOptions.Builder().disableSslVerification(true).build();
myService.configureClient(options);
Node.js
For Node.js, set `disableSslVerification` to `true` in the service constructor and/or authenticator constructor, like this:import ExampleServiceV1 from 'ibm-mysdk/example-service/v1';
import { IamAuthenticator } from 'ibm-mysdk/auth';
const myservice = new ExampleServiceV1({
authenticator: new IamAuthenticator({
apikey: '<apikey>',
disableSslVerification: true, // this will disable SSL verification for requests to the IAM token server
}),
disableSslVerification: true, // this will disable SSL verification for any requests invoked with this service client instance
});
Python
For Python, use the `set_disable_ssl_verification()` method on the service client, like this:my_service.set_disable_ssl_verification(True)
When you disable SSL verification, the python urllib3
library might log an excessive number of warning
messages, like this:
.../connectionpool.py:1004: InsecureRequestWarning: Unverified HTTPS request is being made to host '<my-insecure-host>'.
Adding certificate verification is strongly advised.
See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
To suppress these warning messages, you can add this code to your application:
import urllib3
urllib3.disable_warnings()
See this link for more details.
This section provides information about how to deal with errors resulting from request invocations.
The SDK uses standard HTTP response codes to indicate whether a method completed successfully. HTTP response codes in the 2xx range indicate success. A response in the 4xx range is some sort of failure, and a response in the 5xx range usually indicates an internal system error that cannot be resolved by the user.
Go
In the case of an error response from the server endpoint, the Go SDK will do the following:
- The service method (operation) will return a non-nil
error
object. Thiserror
object will contain the error message retrieved from the HTTP response if possible, or a generic error message otherwise. - The
detailedResponse
return value will contain the following fields: -
StatusCode
: the HTTP status code returned in the response.Headers
: the HTTP headers returned in the response.Result
: if the operation returned a JSON error response, this will contain the unmarshalled response in the form of amap[string]interface{}
. This allows the application to examine all of the error information returned in the HTTP response message.RawResult
: if the operation returned a non-JSON error response, this will contain the raw response body as a[]byte
.
Here's an example of checking the error
object after invoking the GetResource
operation:
// Call the GetResource operation and receive the returned Resource.
options := myservice.NewGetResourceOptions("bad-resource-id")
result, detailedResponse, err := myservice.GetResource(options)
if err != nil {
fmt.Println("Error retrieving the resource: ", err.Error())
fmt.Println(" status code: ", detailedResponse.StatusCode)
if (detaliedResponse.Result != nil) {
fmt.Println(" full error response: ", detailedResponse.Result)
} else {
fmt.Println(" raw error response: ", detailedResponse.RawResult)
}
}
Java
In the case of an error response from the server endpoint, the Java SDK will throw an exception
from the com.ibm.cloud.sdk.core.service.exception
package.
All service exceptions contain the following fields:
statusCode
: the HTTP response code that was returned in the responsemessage
: a message that describes the errorheaders
: the HTTP headers returned in the responsedebuggingInfo
: aMap<String, Object>
which contains the unmarshalled error response object in the event that a JSON error response is returned. This will provide more information beyond the error message.responseBody
: a string containing the entire body from the response
An operation may also throw an IllegalArgumentException
if it detects missing or invalid
input arguments.
Here's an example of how to catch and process specific exceptions that may be returned from an operation:
import com.ibm.cloud.sdk.core.service.exception.BadRequestException;
import com.ibm.cloud.sdk.core.service.exception.NotFoundException;
import com.ibm.cloud.sdk.core.service.exception.RequestTooLargeException;
import com.ibm.cloud.sdk.core.service.exception.ServiceResponseException;
import com.ibm.cloud.sdk.core.service.exception.UnauthorizedException;
...
try {
// Invoke an operation
Response<Resource> response = myService.getResource(options).execute();
// Process response...
} catch (BadRequestException e) {
// Handle Bad Request (400) exception
} catch (UnauthorizedException e) {
// Handle Unauthorized (401) exception
} catch (NotFoundException e) {
// Handle Not Found (404) exception
} catch (RequestTooLargeException e) {
// Handle Request Too Large (413) exception
} catch (ServiceResponseException e) {
// Base class for all exceptions caused by error responses from the service
System.out.println("Service returned status code "
+ e.getStatusCode() + ": " + e.getMessage());
System.out.println("Detailed error info:\n" + e.getDebuggingInfo().toString());
System.out.println("Error response body:\n" + e.getResponseBody());
}
Node.js
In the case of an error response from the server endpoint, the Node SDK will
create an Error
object with information that describes the error that occurred.
This error object is passed as the first parameter to the callback function for the method,
and will contain the following fields:
status
: the HTTP status code that was returned in the responsestatusText
: a text description of the status codemessage
: the error message returned in the responsebody
: the error response body. If a JSON response was returned, this will be the stringified response body. If a non-JSON response was returned, this will simply be the raw response body obtained from the response.
Here's an example of how to access the error object:
myService.getResource({
'resourceId': 'bad-resource-id',
}).then((response) => {
// ...handle successful response...
}).catch((err) => {
// ...handle error response...
console.log("Error status code: " + err.status + " (" + err.statusText + ")");
console.log("Error message: " + err.message);
});
Python
In the case of an error response from the server endpoint, the Python SDK will throw an exception with the following fields:
code
: the HTTP status code that was returned in the responsemessage
: a message that describes the errorhttp_response
: arequests.Response
instance that contains the operation response information
Here's an example:
from ibm_cloud_sdk_core import ApiException
try:
response = my_service.get_resource(resource_id='does not exist')
except ApiException as e:
print("Method failed with status code " + str(e.code) + ": " + e.message)
print("Response body: " + e.http_response.text)
This section describes how to enable logging within the various SDKs.
Go
Within Go SDKs, the underlying Go core library uses a basic logging facility that supports various logging levels: Error, Info, Warn, Debug. By default, the Go core logger is configured with log level "Error", which means that only error messages will be displayed. A logger configured at log level "Warn" would display "Error" and "Warn" messages (but not "Info" or "Debug"), etc.
For details on how to enable and configure logging in the Go core library, see this.
Java
For Java SDKs, the underlying Java core library uses the java.util.logging framework for logging various messages.
For details on how to enable and configure logging in the Java core library, see this.
Node.js
For Node.js SDKs, the underlying Node.js core library uses the debug
package
for logging various messages.
For details on how to enable and configure logging in the Node.js core library, see this.
Python
For Python SDKs, the underlying Python core library uses Python's builtin logging
module for logging various messages.
For details on how to enable and configure logging in the Python core library, see this.
For some languages, the SDK supports both synchronous (blocking) and asynchronous (non-blocking) execution of service methods.
Go
The Go SDK supports only synchronous execution of service methods.Java
For Java, all service methods implement the ServiceCall
interface.
To call a method synchronously, use the execute()
method of the ServiceCall<T>
interface,
like this:
// Invoke the operation.
GetResourceOptions options = /* construct options model */
Response<Resource> response = myservice.getResource(options).execute();
// Continue execution...
To call a method asynchronously, use the enqueue()
method of the ServiceCall<T>
interface
to receive a callback when the response arrives.
The ServiceCallback<T>
interface provides onResponse
and onFailure
methods that you
override to handle the callback, like this:
// Invoke the operation in the background
GetResourceOptions options = /* construct options model */
myservice.getResource(options).enqueue(new ServiceCallback<ResourceInstance>() {
@Override
public void onResponse(Response<Resource> response) {
System.out.println("We did it! " + response);
}
@Override
public void onFailure(Exception e) {
System.out.println("Whoops...");
}
});
// Continue execution in the meantime!
Node.js
The Node.js SDK executes each request asynchronously and returns the response as a `Promise`. The Node SDK also supports `async/await`, which processes the `Promise` without needing to formally chain the functions, to provide synchronous-like behavior.// Without async/await
const resourceMetadata = () => {
return getResource('my-resource')
.then(res => getResourceMetadata(res))
}
// With async/await
const resourceMetadata = async () => {
const res = await getResource('/users.json')
const data = await getResourceMetadata(res)
return data
}
Python
The Python SDK supports only synchronous execution of service methods.If you are having difficulties using an SDK or have a question about the IBM Cloud Services, please ask a question at Stack Overflow.
Find more open source projects on the IBM Github Page
This project is released under the Apache 2.0 license. The license's full text can be found in LICENSE.