Article
· Jan 19, 2018 3m read

DigitalOcean API implementation

Recently DigitalOcean introduced new plans for droplets, but as existing droplets stayed on the old plans  I decided to use API to resize them automatically.  After reading tutorial, I wrote partial client for DigitalOcean API, which I would like to share today.

API

The core part of the API which controls requests consists of three methods:

  • Get access key
  • Generate request template
  • Send request and convert results

Here's how it looks:

/// Get Access Key
/// https://www.digitalocean.com/community/tutorials/how-to-use-the-digitalocean-api-v2
ClassMethod GetKey() As %Net.HttpRequest [ CodeMode = expression ]
{
$Get(^DigitalOcean)
}

/// Get basic request.
ClassMethod GetRequest() As %Net.HttpRequest
{
    #Dim Request As %Net.HttpRequest = ##class(%Net.HttpRequest).%New()
    Set Request.Https = $$$YES
    Set Request.SSLConfiguration = ..#SSLConfiguration
    Set Request.Server = ..#Server    
    Set Request.ContentType = ##class(%CSP.REST).#CONTENTTYPEJSON
    Do Request.SetHeader("Authorization", "Bearer " _ ..GetKey())
    Quit Request
}

/// Ececute request against DigitalOcean API.
ClassMethod ExecuteRequest(Method As %String(VALUELIST="GET,POST,PUT,DELETE"), Location As %String, Output Result As %DynamicObject, Request As %Net.HttpRequest = {..GetRequest()}, SuccessCode As %Integer = {$Case(Method, "POST":201,:200)}, Test As %Integer(MINVAL=0,MAXVAL=2) = 0) As %Status
{
    Kill Result
    #Dim Status As %Status = $$$OK
    Set Status = Request.Send(Method, Location, Test)
    
    If (Test '= 1) {
        If (Request.HttpResponse.StatusCode '= SuccessCode) {
            Set Status = $$$ERROR($$$GeneralError, $$$FormatText("Received %1 expected %2. Responce body: %3", Request.HttpResponse.StatusCode, SuccessCode, Request.HttpResponse.Data.Read($$$MaxStringLength)))
        }
        Set Result = {}.%FromJSON(Request.HttpResponse.Data)
    }
    
    
    Quit Status
}

All other methods just:

  • specify endpoint (required)
  • specify parameters
  • specify body
  • call ExecuteRequest (required)
  • process response

Example

Most calls to API are asynchronous, so in response the client gets ActionId which holds the current status of the original call:

/// Get information about action.
/// https://developers.digitalocean.com/documentation/v2/#retrieve-an-existing-action
/// Do ##class(Utils.DigitalOcean).GetStatus()
ClassMethod GetAction(ActionId As %Integer, Output Progress As %String(VALUELIST="in-progress,completed,errored,"), Test As %Integer(MINVAL=0,MAXVAL=2) = 0) As %Status
{
    Kill Progress
    #Dim Status As %Status = $$$OK
    
    Set Location = "/v2/actions/" _ ActionId
    Set Status = ..ExecuteRequest("GET", Location, .Result, , , Test)    
    Quit:$$$ISERR(Status) Status
    Set Progress = Result.action.status
    Quit Status
}

This way we can minimize the amount of code for an API client since the task of technical response processing is done once (in ExecuteRequest) and API methods hold just the business logic.

Usage

To use this project:

  1. Import API class
  2. Create SSLConfiguration DefaultSSL or change SSLConfiguration parameter of Utils.DigitalOcean class to a name of a valid configuration
  3. Set ^DigitalOcean global to your access key value

After that,  call existing API methods or add the new ones.

Conclusion

DigitalOcean API is easy to use. Structuring your API client can improve readability and lessen the amount of code you need to write.

Links

Discussion (0)1
Log in or sign up to continue