1# softlayer-go 2 3[![Build Status](https://travis-ci.org/softlayer/softlayer-go.svg?branch=master)](https://travis-ci.org/softlayer/softlayer-go) 4[![GoDoc](https://godoc.org/github.com/softlayer/softlayer-go?status.svg)](https://godoc.org/github.com/softlayer/softlayer-go) 5[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](http://www.apache.org/licenses/LICENSE-2.0) 6 7The Official and Complete SoftLayer API Client for Golang (the Go programming language). 8 9## Introduction 10 11This library contains a complete implementation of the SoftLayer API for client application development in the Go programming language. Code for each API data type and service method is pre-generated, using the SoftLayer API metadata endpoint as input, thus ensuring 100% coverage of the API right out of the gate. 12 13It was designed to feel as natural as possible for programmers familiar with other popular SoftLayer SDKs, and attempts to minimize unnecessary boilerplate and type assertions where possible. 14 15## Usage 16 17### Basic example: 18 19Three easy steps: 20 21```go 22// 1. Create a session 23sess := session.New(username, apikey) 24 25// 2. Get a service 26accountService := services.GetAccountService(sess) 27 28// 3. Invoke a method: 29account, err := accountService.GetObject() 30``` 31 32[More examples](https://github.com/softlayer/softlayer-go/tree/master/examples) 33 34### Sessions 35 36In addition to the example above, sessions can also be created using values 37set in the environment, or from the local configuration file (i.e. ~/.softlayer): 38 39```go 40sess := session.New() 41``` 42 43In this usage, the username, API key, and endpoint are read from specific environment 44variables, then the local configuration file (i.e. ~/.softlayer). First match ends 45the search: 46 47* _Username_ 48 1. environment variable `SL_USERNAME` 49 1. environment variable `SOFTLAYER_USERNAME` 50 1. local config `username`. 51* _API Key_ 52 1. environment variable `SL_API_KEY` 53 1. environment variable `SOFTLAYER_API_KEY` 54 1. local config `api_key`. 55* _Endpoint_ 56 1. environment variable `SL_ENDPOINT_URL` 57 1. environment variable `SOFTLAYER_ENDPOINT_URL` 58 1. local config `endpoint_url`. 59* _Timeout_ 60 1. environment variable `SL_TIMEOUT` 61 1. environment variable `SOFTLAYER_TIMEOUT` 62 1. local config `timeout`. 63 64*Note:* Endpoint defaults to `https://api.softlayer.com/rest/v3` if not configured through any of the above methods. Timeout defaults to 120 seconds. 65 66Example of the **~/.softlayer** local configuration file: 67``` 68[softlayer] 69username = <your username> 70api_key = <your api key> 71endpoint_url = <optional> 72timeout = <optional> 73``` 74 75### Instance methods 76 77To call a method on a specific instance, set the instance ID before making the call: 78 79```go 80service := services.GetUserCustomerService(sess) 81 82service.Id(6786566).GetObject() 83``` 84 85### Passing Parameters 86 87All non-slice method parameters are passed as pointers. This is to allow for optional values to be omitted (by passing `nil`) 88 89```go 90guestId := 123456 91userCustomerService.RemoveVirtualGuestAccess(&guestId) 92``` 93 94For convenience, a set of helper functions exists that allocate storage for a literal and return a pointer. The above can be refactored to: 95 96```go 97userCustomerService.RemoveVirtualGuestAccess(sl.Int(123456)) 98``` 99 100### Using datatypes 101 102A complete library of SoftLayer API data type structs exists in the `datatypes` package. Like method parameters, all non-slice members are declared as pointers. This has the advantage of permitting updates without re-sending the complete data structure (since `nil` values are omitted from the resulting JSON). Use the same set of helper functions to assist in populating individual members. 103 104```go 105package main 106 107import ( 108 "fmt" 109 "log" 110 111 "github.com/softlayer/softlayer-go/datatypes" 112 "github.com/softlayer/softlayer-go/services" 113 "github.com/softlayer/softlayer-go/session" 114 "github.com/softlayer/softlayer-go/sl" 115) 116 117func main() { 118 sess := session.New() // See above for details about creating a new session 119 120 // Get the Virtual_Guest service 121 service := services.GetVirtualGuestService(sess) 122 123 // Create a Virtual_Guest struct as a template 124 vGuestTemplate := datatypes.Virtual_Guest{ 125 // Set Creation values - use helpers from the sl package to set pointer values. 126 // Unset (nil) values are not sent 127 Hostname: sl.String("sample"), 128 Domain: sl.String("example.com"), 129 MaxMemory: sl.Int(4096), 130 StartCpus: sl.Int(1), 131 Datacenter: &datatypes.Location{Name: sl.String("wdc01")}, 132 OperatingSystemReferenceCode: sl.String("UBUNTU_LATEST"), 133 LocalDiskFlag: sl.Bool(true), 134 } 135 136 // Tell the API to create the virtual guest 137 newGuest, err := service.CreateObject(&vGuestTemplate) 138 // optional error checking... 139 if err != nil { 140 log.Fatal(err) 141 } 142 143 // Print the ID of the new guest. Don't forget to dereference 144 fmt.Printf("New guest %d created", *newGuest.Id) 145} 146``` 147 148### Object Masks, Filters, Result Limits 149 150Object masks, object filters, and pagination (limit and offset) can be set 151by calling the `Mask()`, `Filter()`, `Limit()` and `Offset()` service methods 152prior to invoking an API method. 153 154For example, to set an object mask and filter that will be applied to 155the results of the Account.GetObject() method: 156 157```go 158accountService := services.GetAccountService(sess) 159 160accountService. 161 Mask("id;hostname"). 162 Filter(`{"virtualGuests":{"domain":{"operation":"example.com"}}}`). 163 GetObject() 164``` 165 166The mask and filter are applied to the current request only, and reset after the 167method returns. To preserve these options for future requests, save the return value: 168 169```go 170accountServiceWithMaskAndFilter = accountService.Mask("id;hostname"). 171 Filter(`{"virtualGuests":{"domain":{"operation":"example.com"}}}`) 172``` 173 174Result limits are specified as separate `Limit` and `Offset` values: 175 176```go 177accountService. 178 Offset(100). // start at the 100th element in the list 179 Limit(25). // limit to 25 results 180 GetVirtualGuests() 181``` 182 183#### Filter Builder 184 185There is also a **filter builder** you can use to create a _Filter_ instead of writing out the raw string: 186 187```go 188// requires importing the filter package 189accountServiceWithMaskAndFilter = accountService. 190 Mask("id;hostname"). 191 Filter(filter.Path("virtualGuests.domain").Eq("example.com").Build()) 192``` 193 194You can also create a filter incrementally: 195 196```go 197// Create initial filters 198filters := filter.New( 199 filter.Path("virtualGuests.hostname").StartsWith("KM078"), 200 filter.Path("virtualGuests.id").NotEq(12345), 201) 202 203// .... 204// Later, append another filter 205filters = append(filters, filter.Path("virtualGuests.domain").Eq("example.com")) 206 207accountServiceWithMaskAndFilter = accountService. 208 Mask("id;hostname"). 209 Filter(filters.Build()) 210``` 211 212Or you can build all those filters in one step: 213 214```go 215// Create initial filters 216filters := filter.Build( 217 filter.Path("virtualGuests.hostname").StartsWith("KM078"), 218 filter.Path("virtualGuests.id").NotEq(12345), 219 filter.Path("virtualGuests.domain").Eq("example.com"), 220) 221 222accountServiceWithMaskAndFilter = accountService. 223 Mask("id;hostname").Filter(filters) 224``` 225 226See _filter/filters.go_ for the full range of operations supported. 227The file at _examples/filters.go_ will show additional examples. 228Also, [this is a good article](https://sldn.softlayer.com/article/object-filters) that describes SoftLayer filters at length. 229 230### Handling Errors 231 232For any error that occurs within one of the SoftLayer API services, a custom 233error type is returned, with individual fields that can be parsed separately. 234 235```go 236_, err := service.Id(0). // invalid object ID 237 GetObject() 238 239if err != nil { 240 // Note: type assertion is only necessary for inspecting individual fields 241 apiErr := err.(sl.Error) 242 fmt.Printf("API Error:") 243 fmt.Printf("HTTP Status Code: %d\n", apiErr.StatusCode) 244 fmt.Printf("API Code: %s\n", apiErr.Exception) 245 fmt.Printf("API Error: %s\n", apiErr.Message) 246} 247``` 248 249Note that `sl.Error` implements the standard `error` interface, so it can 250be handled like any other error, if the above granularity is not needed: 251 252```go 253_, err := service.GetObject() 254if err != nil { 255 fmt.Println("Error during processing: ", err) 256} 257``` 258 259### Session Options 260 261To set a different endpoint (e.g., the backend network endpoint): 262 263```go 264session.Endpoint = "https://api.service.softlayer.com/rest/v3" 265``` 266 267To enable debug output: 268 269```go 270session.Debug = true 271``` 272 273By default, the debug output is sent to standard output. You can customize this by setting up your own logger: 274 275```go 276import "github.com/softlayer/softlayer-go/session" 277 278session.Logger = log.New(os.Stderr, "[CUSTOMIZED] ", log.LstdFlags) 279``` 280 281You can also tell the session to retry the api requests if there is a timeout error: 282 283```go 284// Specify how many times to retry the request, the request timeout, and how much time to wait 285// between retries. 286services.GetVirtualGuestService( 287 sess.SetTimeout(900).SetRetries(2).SetRetryWait(3) 288).GetObject(...) 289``` 290 291### Password-based authentication 292 293Password-based authentication (via requesting a token from the API) is 294only supported when talking to the API using the XML-RPC transport protocol. 295 296To use the XML-RPC protocol, simply specify an XML-RPC endpoint url: 297 298```go 299func main() { 300 // Create a session specifying an XML-RPC endpoint url. 301 sess := &session.Session{ 302 Endpoint: "https://api.softlayer.com/xmlrpc/v3", 303 } 304 305 // Get a token from the api using your username and password 306 userService := services.GetUserCustomerService(sess) 307 token, err := userService.GetPortalLoginToken(username, password, nil, nil) 308 if err != nil { 309 log.Fatal(err) 310 } 311 312 // Add user id and token to the session. 313 sess.UserId = *token.UserId 314 sess.AuthToken = *token.Hash 315 316 // You have a complete authenticated session now. 317 // Call any api from this point on as normal... 318 keys, err := userService.Id(sess.UserId).GetApiAuthenticationKeys() 319 if err != nil { 320 log.Fatal(err) 321 } 322 323 log.Println("API Key:", *keys[0].AuthenticationKey) 324} 325``` 326 327## Development 328 329### Setup 330 331To get _softlayer-go_: 332 333``` 334go get github.com/softlayer/softlayer-go/... 335``` 336 337### Build 338 339``` 340make 341``` 342 343### Test 344 345``` 346make test 347``` 348 349### Updating dependencies 350 351``` 352make update_deps 353``` 354 355## Copyright 356 357This software is Copyright (c) 2016 IBM Corp. See the bundled LICENSE file for more information. 358