TECH

ついに公開されたAPIをSwfitから利用する(SSH公開鍵を取得する)

TECH
中津川 篤司

CloudGarageのインスタンス操作などを自動化できるAPIがついに公開されました。これでインスタンスの立ち上げや停止を自動化できるようになります。

そこで今回はSwiftを使ってAPI操作を行う方法を解説します。処理内容としては、コントロールパネルで設定した公開鍵を取得します。

必要なソフトウェア、ライブラリ

今回必要なソフトウェア、ライブラリは以下の通りです。

  • Xcode
  • Ruby(CocoaPods用)
    • cocoapods-keys
  • CocoaPods
    • HydraAsync
    • SwiftyJSON

APIキーを取得する

まずはCloudGarageの管理画面にてAPIキーを取得します。管理画面の右上にあるメニューをクリックして、アカウント情報確認/変更を選択します。

一度パスワードを入力する必要があります。

そして一番下にあるAPI Key管理にてAPI Keyを発行します。私はすでに発行済みなので再発行になっていますが、最初はAPIキーがないはずです。Client ID(クライアントID)とClient Secret(クライアントシークレット)の二つで認証します。重要なキーなので漏洩したりしないよう注意してください。

Xcodeで新しいプロジェクトを作成する

最初にXcodeでiOSプロジェクトを作成します。作成したら、一旦終了します。

Gemfileを作成する

クライアントIDなどを隠すため、 cocoapods-keys をインストールします。以下の内容で Gemfile を作成します。

source 'https://rubygems.org'
gem 'cocoapods-keys'

そしてbundlerを実行します。

$ bundle

Podfileを作成する

次にCocoaPodsで必要なライブラリをインストールします。 Podfile の内容は次の通りです。 {YOUR_PROJECT} は自分のプロジェクト名に置き換えてください。インストールするのはSwiftでasync/awaitを利用するHydraAsync、そしてJSONを扱いやすくするSwiftyJSONです。cocoapods-keysの設定も行っています。

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target '{YOUR_PROJECT}' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!
  pod 'HydraAsync'
  pod 'SwiftyJSON'
  
  # Pods for ncmbPush
  target '{YOUR_PROJECT}Tests' do
    inherit! :search_paths
    # Pods for testing
  end

  target '{YOUR_PROJECT}UITests' do
    inherit! :search_paths
    # Pods for testing
  end

end

plugin 'cocoapods-keys', {
  :project => "{YOUR_PROJECT}",
  :keys => [
    "clientId",
    "clientSecret"
  ]}

これをインストールした状態で pod install を実行すると、clientIdとclientSecretの入力が求められます。先ほどCloudGarageのコントロールパネルで取得したものをそれぞれ指定してください。

$ pod install

 CocoaPods-Keys has detected a keys mismatch for your setup.
 What is the key for clientId
 > ylk...t1P

Saved clientId to cloudgarage.
 What is the key for clientSecret
 > iIG...oUo

Saved clientSecret to cloudgarage.
Analyzing dependencies
Fetching podspec for `Keys` from `Pods/CocoaPodsKeys`
Downloading dependencies
Using HydraAsync (1.2.1)
Using Keys (1.0.1)
Using SwiftyJSON (4.2.0)
Generating Pods project
Integrating client project
Sending stats
Pod installation complete! There are 3 dependencies from the Podfile and 3 total pods installed.

Xcodeでの作業

.xcworkspace という拡張子のファイルが生成されているので、それを開きます。Xcodeで、新しいヘッダーファイルを作成します。名前は任意ですが BridgeHeader.h などとします。

内容は次の通りです。 CloudgarageKeys.h というファイル名はそれぞれ変わりますが、PodsプロジェクトのDevelopment Pods/Keysの中にあるヘッダーファイルが対象です。

#ifndef BridgeHeader_h
#define BridgeHeader_h

#import "Keys/CloudgarageKeys.h"

#endif /* BridgeHeader_h */

そして作成したXcodeプロジェクトのBuild SettingsにあるObjective-C Bridging Headerにて作成した BridgeHeader.h ファイルを指定します。例えば cloudgarage/BridgeHeader.h といった具合です。

Swiftによる開発

では準備ができましたので実際にコードを書いてみます。まず全体像です。HydraAsyncを使って非同期処理をasync/await化しています。

let baseUrl = "https://api.cloudgarage.jp"
async({ _ -> Int in
  // トークンを取得
  let token:String = try await(self.getToken(baseUrl: baseUrl))
  // 公開鍵一覧を取得
  let keyPairs = try await(self.getKeyPairs(baseUrl: baseUrl, token: token)) as! JSON
  // 公開鍵の詳細情報を取得
  let keyPair = try await(self.getKeyPair(baseUrl: baseUrl, token: token, id: keyPairs[0]["id"].int ?? 0))
  // デバッグ出力
  print(keyPair)
  return 0
}).then({stats in
  print(stats)
})
.catch {error in
  print("Error")
  print(error)
}

トークンの取得

まずトークンの取得です。CloudgarageKeysを使ってキーを取得しています。そしてPOSTリクエストを行った後、token.idがあるのかを確認してトークンを返します。

func getToken(baseUrl: String) -> Promise<String> {
  return Promise<String>(in: .background, {resolve, reject, _ -> Void in
    let keys = CloudgarageKeys.init()
    let url = "\(baseUrl)/tokens"
    let request = NSMutableURLRequest(url: URL(string: url)!)
    request.httpMethod = "POST"
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    let params:[String:Any] = [
      "client_id": keys.clientId,
      "client_secret": keys.clientSecret
    ]
    
    request.httpBody = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
          do {
              let task = URLSession.shared.dataTask(with: request as URLRequest) { (data, response, error) in
                  if error != nil {
                      reject(error ?? NSError(domain: "Request error", code: 1))
                  } else {
                      let json = try? JSON(data: data!)
                      if let token = json?["token"]["id"].string {
                          resolve(token)
                      }
                      return reject(NSError(domain: "Parse error", code: 1))
                  }
              }
              task.resume()
          } catch let error as NSError  {
              reject(error)
          }
  })
}

公開鍵の一覧を取得

続いて公開鍵の一覧を取得します。get処理を関数化し、一覧を取得する処理自体短くしています。トークンを取得していますので、それを X-Auth-Token ヘッダーに適用して実行します。

func getKeyPairs(baseUrl: String, token: String) -> Promise<Any> {
      return Promise<Any>(in: .background, {resolve, reject, _ -> Void in
          let url = "\(baseUrl)/keypairs"
          self.get(url: url, token: token)
          .then {json in
              if json["keypairs"].array != nil {
                  return resolve(json["keypairs"])
              } else {
                  return reject(NSError(domain: "Parse error on getKeyPairs \(json)", code: 1))
              }
          }
          .catch{error in
              return reject(error)
          }
      })
}

// GET処理を関数化
func get(url: String, token: String) -> Promise<JSON> {
    return Promise<JSON>(in: .background, {resolve, reject, _ -> Void in
        let request = NSMutableURLRequest(url: URL(string: url)!)
        request.httpMethod = "GET"
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        request.addValue(token, forHTTPHeaderField: "X-Auth-Token")
      
        let task = URLSession.shared.dataTask(with: request as URLRequest) { (data, response, error) in
            if error != nil {
                reject(error ?? NSError(domain: "Request error", code: 1))
            } else {
                let json = try? JSON(data: data!)
                return resolve(json!)
            }
        }
        task.resume()
    })
}

公開鍵の詳細を取得

取得した公開鍵のID(数値)を使って公開鍵詳細を取得します。ここは先ほどのget処理を使って行います。

func getKeyPair(baseUrl: String, token: String, id: Int) -> Promise<Any> {
      return Promise<Any>(in: .background, {resolve, reject, _ -> Void in
          let url = "\(baseUrl)/keypairs/\(id)"
          self.get(url: url, token: token)
          .then {json in
            if json["keypair"].dictionary != nil {
                resolve(json["keypair"])
            } else {
                return reject(NSError(domain: "Parse error on getKeyPair \(json)", code: 1))
            }
          }
          .catch{error in
              reject(error)
          }
      })
}

結果として以下のような公開鍵情報が得られます。

{
  "keypair_created_time" : "2018\/09\/03 13:44:29.684",
  "publicKey" : "ssh-rsa AAA...F+w== nakatsugawa@macpro.local",
  "name" : "macpro",
  "id" : 1217
}

SwiftはiOSやmacOSアプリの開発はもちろん、サーバサイドでも利用できる言語となっています。静的型付けながら、スクリプト言語のような書き方ができるのが特徴です。ぜひiOSアプリからCloudGarage Public APIを呼び出してみてください!

APIリファレンスはCloudGarage API リファレンスにありますので、ぜひご覧ください。

この記事を書いた人

中津川 篤司

株式会社MOONGIFT 代表取締役。CloudGarage、ニフクラ mobile backend、hifive エバンジェリスト。プログラマ、エンジニアとしていくつかの企業で働き、28歳のときに独立。2004年、まだ情報が少なかったオープンソースソフトの技術ブログ『MOONGIFT』を開設し、毎日情報を発信している。2013年に法人化、ビジネスとエンジニアを結ぶエバンジェリスト業「DevRel」活動をスタートした。 Twitter:@goofmint | GitHub:@goofmint | Facebook: goofmint

この記事のタグ

オススメの記事

ページトップへ