cloapi-go-lib is the official CLO API library for the Go programming language.
Use go get to retrieve the library to add it to your GOPATH workspace, or project's Go module dependencies.
go get github.com/clo-ru/cloapi-go-client/v2
To update the library use go get -u to retrieve the latest version of the library.
go get -u github.com/clo-ru/cloapi-go-client/v2
To get a specific release version of the SDK use @ in your go get command.
go get -u github.com/clo-ru/cloapi-go-client/v2@v2.0.0
To get the latest SDK repository change use @latest.
go get -u github.com/clo-ru/cloapi-go-client/v2@latest
package main
import (
"github.com/clo-ru/clo_go_client/clo"
"github.com/clo-ru/clo_go_client/services/servers"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
"context"
"fmt"
"time"
)
const (
projectID = "my-cool-project"
baseUrl = "https://clo.ru"
)
func initLogger() clo.Logger {
return logrus.New()
}
//initConfig provides a typical config struct to initialize the ApiClient
func initConfig() clo.Config {
viper.SetEnvPrefix(projectID)
viper.BindEnv("auth_key")
return clo.Config{
AuthKey: viper.GetString("auth_key"),
BaseUrl: baseUrl,
}
}
//createServer make a POST http request to the CLO API to create a new server.
//it will retry 2 times if the response's status code will be not one of: 200, 201, 202 or 204.
func createServer(cli *clo.ApiClient) (*clo.ResponseCreated, error) {
req := servers.ServerCreateRequest{
ProjectID: projectID, //id of the user's project
Body: servers.ServerCreateBody{
Name: "my_server",
Image: "debian-9",
Flavor: servers.ServerFlavorBody{Ram: 12, Vcpus: 2},
Storages: []servers.ServerStorageBody{{Size: 20, Bootable: true, StorageType: "volume"}},
},
}
req.WithLog(initLogger())
req.WithRetry(2, 0)
return req.Do(context.Background(), cli)
}
func main() {
cfg := initConfig()
httpCli, e := clo.NewDefaultClientFromConfig(cfg)
if e != nil {
panic(e)
}
res, e := createServer(httpCli)
if e != nil {
panic(e)
}
fmt.Printf("%v", res)
}
The library is using a concept of requests that are working over the clo.ApiClient
struct.
The client relies on a simple HttpClient
interface implementation, like a http.DefaultClient
.
auth_key
and base_url
should be provided to the client's Option
map.
Requests represent the flat structure of the API and encapsulate different provider's services, such as: disks, servers
or snapshots.
According to the documentation some requests don't return response. And all of them include retry
logic.
You could tune the request's parameters before the actual make:
- Use
req.WithRetry(int, time.Duration)
to retry the request if the response's ends with error or return code >= 500. - Use
req.WithLogger(clo.Logger)
to pass the logger to handle the request errors. - Use
req.WithQueryParams(map[string][]string)
to add query parameters to the request. - Use
req.WithHeaders(map[string][]string)
to add headers to the request.
The Content-Type: application/json
and Authorization
header will be automatically added to the request's headers
before the actual make.
The request endpoints are hardcoded as a consts.
Requests are not thread-safety.
There are two main types of responses: single
and lists
.
The single
responses used to provide information about a single entity or result over an entity.
The list
responses used to provide a list of the entities like servers or volumes. It contains the actual result and
the count
field that is used for pagination.
The paginator
- it is an object that is responsible for paging the actual entity's list request.
The paginator
using a request
object and the clo.ApiClient
to make a request.
It uses options like limit
and offset
to locate a position over the list of entities.
Every lists
object like servers or volumes has its own variation of a paginator
that has functions the following
functions:
NextPage()
- provides the response based on a passed request or an error if there are no more pages.LastPage()
- returntrue
if the last page was already returned.
Paginators are not thread-safety.
package main
func snapListPagination(l int) (e error) {
cli, e := NewDefaultClient("authKey", "baseUrl")
if e != nil {
return
}
req := &SnapshotListRequest{}
paginator := clo.NewPaginator(cli, req, 3, 3)
response := &SnapshotListResponse{}
for !paginator.LastPage() {
if err := paginator.NextPage(context.Background(), response); err != nil {
return err
}
fmt.Print(response)
}
return
}
Lists
request could be filtered and/or ordered based on the fields.
Use -field
for the descending ordering and field
for the ascending.
For filtering using next conditions:
gt
- greater thangte
- greater or equallt
- lesslte
- less or equalrange
- for range in{val1:val2}
in
- for values in{val1, val2, val3}
Conditions' parameters will not validate and will pass as is.
Filtering/ordering methods support chaining.
package main
func filtering(req clo.FilterableRequest) {
ff := []clo.FilteringField{
{
FieldName: "field_gt",
Condition: "gt",
Value: "3",
},
{
FieldName: "field_in",
Condition: "in",
Value: "2,3,4",
},
{
FieldName: "field_range",
Condition: "range",
Value: "2:3",
},
}
of := []string{"field3", "-field4"}
for _, f := range ff {
req.FilterBy(f)
}
for _, or := range of {
req.OrderBy(or)
}
}
A responses' status code will be checked by clo.ApiClient
. If it will be not one of: 200, 201, 202 or 204 - the client
return a clo.DefaultError
.
To read more about errors that could be returned use the documentation