The softlayer-go library helps users make API calls to the SoftLayer (aka IBM Cloud Classic Infrastructure) API.
To get started, here is a simple example.
(We are working in the go/src/github.ibm.com/SoftLayer/sl-test
directory for these examples)
This file will be main.go
|
|
Then we need to download the libraries into the go.mod
file.
go mod init
go mod tidy
Then just build and run
go build main.go
./main
Calling services.GetAccountService(sess).Filter(filterObject).Mask(objectMask).GetHardware()
2022/05/24 15:24:44 [DEBUG] Request URL: GET https://api.softlayer.com/rest/v3.1/SoftLayer_Account/getHardware.json?objectFilter=%7B%22hardware%22%3A%7B%22hostname%22%3A%7B%22operation%22%3A%22%5E%3Dspectrum%22%7D%7D%7D&objectMask=mask%5Bid%2Chostname%2Cdomain%5D
2022/05/24 15:24:44 [DEBUG] Parameters:
2022/05/24 15:24:44 [DEBUG] Status Code: 200
2022/05/24 15:24:44 [DEBUG] Response: [{"domain":"test.com","hostname":"spectrum-virtualize-par-1","id":3071920}]
Id, Hostname, Domain
3071920, spectrum-virtualize-par-1, test.com
Line 1 is easy enough, just set the package name, main works well if this is just for testing.
|
|
|
|
The softlayer-go package has several sub-packages we can make use of.
github.com/softlayer/softlayer-go/sl
Has some helper and error handling functionsgithub.com/softlayer/softlayer-go/session
Will always be required, as it sets up the Authentication Session for actually making the API callgithub.com/softlayer/softlayer-go/services
These are autogenerated from the list of available Services in the SoftLayer API. When building an API call, you will first need an instance of the specific service you are working with.Some other imports that are available, but not used here:
github.com/softlayer/softlayer-go/datatypes
Has the datatype definitions, if you need them. Generally these are required if you are sending in data to the SoftLayer API, for example when ordering, or making changes to an object.github.com/softlayer/softlayer-go/filter
Has some helper functions for building more complex fiters, although we just use a string in our examplegithub.com/softlayer/softlayer-go/helpers
Contains some functions that might be useful when working some of the more complex API calls, like ordering. A good souce of example on how the softlayer-go client makes API calls as wellgithub.com/softlayer/softlayer-go/examples
Has some simple examples.
|
|
This sets up our main()
function, which is required for any go program. From there it sets up a new session
object. By default it will look in the ~/.softlayer config file, or environment variables for your username and API key so you don’t have to put them in the code itself. While SLDN has some examples where the username/api key is passed directly to session.New()
this is a bit of a bad practice.
From there it sets sess.Debug = true
which tells the softlayer-go library to print out all the API calls and results, which can be useful in understanding what exactly is going on under the hood.
|
|
In this example we are making an API call to the SoftLayer_Account
service, which has a GetHardware()
method. In golang any public method or property must start with a capital letter, which is why here the method is GetHardware
but in the documentation it is getHardware
. The same applies for any property returned, they will all need to start with a capital letter, as we will see as we continue this example.
Because SoftLayer_Account::getHardware()
returns a SoftLayer_Hardware object, our object mask can include any property listed on the SoftLayer_Hardware datatype page. Here we just select the local properties id, hostname, domain
. Read more about Object Masks
Next we setup an Object Filter, which are generally optional. For this example though we just want to get any hardware that have a hostname that starts with the string spectrum
. Here we setup a simple string filter, but more complex filters might benefit from using the Filter Builder. Since this filter is using the Account
service, the filter needs to start at the SoftLayer_Account datatype (unlike the object mask).
Lastly, we put all these pieces together to make an API call. Most API calls will return 2 objects, the first being whatever the API method itself is set to return (in this case a map of SoftLayer_Hardware
objects), and an error if there was one. Usually this is an either/or situation, you won’t ever get an error and data back.
|
|
Generally if there is an error, simply printing out a message and the actual error itself is enough.
|
|
Printing out data is usually simple enough. The only thing you might need to be aware of is that the results of the API calls are all going to be pointers. In this example we use sl.Get()
to resolve those pointers, but the following would work too:
fmt.Printf("%v, %v, %v\n", *server.Id, *server.Hostname, *server.Domain)
The services and datatypes packages are kept updated monthly (although not usually attached to a new version every month). If for some reason there is an API you want to use, but not included in the latest version, please let us know about it on our github issues page.
To update those manually however, you will need to run make generate
in the softlayer-go library in your build, and use the replace directive in go.mod to make sure go uses the local softlayer-go when building your app.
cd ~/go/src/github.com/softlayer/softlayer-go/
git pull origin master
make generate
If you dont have make installed:
go run tools/main.go tools/loadmeta.go tools/common.go tools/version.go generate
On occasions where the result you want from the API is too large to be done in one request, or takes too long for a single request, iterating (paginating) through the results is always a good idea.
ALWAYS use an orderBy objectFilter when paginating through results. Otherwise the API might not order the results the same way between queries.
For these cases, the following is a good pattern to use
import (
"github.com/softlayer/softlayer-go/datatypes"
"github.com/softlayer/softlayer-go/filter"
"github.com/softlayer/softlayer-go/services"
"github.com/softlayer/softlayer-go/session"
"github.com/softlayer/softlayer-go/sl"
)
func ListInstances() ([]datatypes.Virtual_Guest, error) {
sess := session.New()
filters := filter.New()
filters = append(filters, filter.Path("virtualGuests.id").OrderBy("DESC"))
accountService := services.GetAccountService(session)
limit := 50
i := 0
resourceList := []datatypes.Virtual_Guest{}
for {
// Get limit results to start off with
resp, err := vs.AccountService.Mask(mask).Filter(filters.Build())
.Limit(limit).Offset(i * limit).GetMonthlyVirtualGuests()
// increment the offset so we get a new page next request
i++
// If there was an error, return that and nothing else
if err != nil {
return []datatypes.Virtual_Guest{}, err
}
// append the results to our resourceList
resourceList = append(resourceList, resp...)
// if we got fewer results than what we asked for, we are done.
if len(resp) < limit {
break
}
}
return resourceList, nil
}
For any error that occurs within one of the SoftLayer API services, a custom error type is returned, with individual fields that can be parsed separately.
Note that sl.Error implements the standard error interface, so it can be handled like any other error, if the above granularity is not needed:
_, err := service.Id(0).GetObject()
if err != nil {
fmt.Println("Error during processing: ", err)
// Note: type assertion is only necessary for inspecting individual fields
apiErr := err.(sl.Error)
fmt.Printf("API Error:")
fmt.Printf("HTTP Status Code: %d\n", apiErr.StatusCode)
fmt.Printf("API Code: %s\n", apiErr.Exception)
fmt.Printf("API Error: %s\n", apiErr.Message)
}
When running into issues, its always important to know exactly what the softlayer-go client is sending into the API, and getting back in return. For this, simply set session.Debug=True
. This will cause softlayer-go to print out API calls it makes, and the JSON data it gets back.
sess := session.New()
sess.Debug = true
Output will look something like this:
2022/05/26 11:51:51 [DEBUG] Request URL: GET https://api.softlayer.com/rest/v3.1/SoftLayer_Account/getHardware.json?objectFilter=%7B%22hardware%22%3A%7B%22hostname%22%3A%7B%22operation%22%3A%22%5E%3Dspectrum%22%7D%7D%7D&objectMask=mask%5Bid%2Chostname%2Cdomain%5D
2022/05/26 11:51:51 [DEBUG] Parameters:
2022/05/26 11:51:52 [DEBUG] Status Code: 200
2022/05/26 11:51:52 [DEBUG] Response: [{"domain":"test.com","hostname":"spectrum-virtualize-par-1","id":3071920}]
For a good example of how the softlayer-go library works, the ibmcloud sl command is a good place to start. SLDN GO Library also has a nice collection of smaller single use examples that could be useful.
If you ever feel the softlayer-go library could be improved please feel free to make a pull request, or even open an issue on the project’s github would be very helpful.