Google Cloud Print を Web API で操作 - Unirest 使用

リフレッシュトークンを使って Google Cloud Print を Web API で操作してみます。

以前、「Google アカウントで Google API を利用 - google-api-services-gmail」 では Apache HTTPClient を使いましたが、今回は Unirest を使っています。

ソースは http://github.com/fits/try_samples/tree/master/blog/20151222/

はじめに

事前準備としてリフレッシュトークンを取得しておきます。

今回は、「Google アカウントで・・・」 にて発行したクライアント ID をそのまま使用します。

(1) コードの取得

下記パラメータを付け https://accounts.google.com/o/oauth2/auth へ Web ブラウザ等でアクセスし API の利用を許可する事でコードを取得します。

パラメータ
response_type code
client_id クライアント ID の client_id 値(※1)
scope https://www.googleapis.com/auth/cloudprint
redirect_uri oob (※2)
(※1)クライアント ID 発行時にダウンロードした JSON ファイルの client_id 値

(※2)リダイレクトしない場合の設定。
       何らかのアプリケーション内から実行する際は
       それに合わせたリダイレクト先を指定する

例えば、以下のような URL へアクセスします。

URL 例
https://accounts.google.com/o/oauth2/auth?redirect_uri=oob&response_type=code&client_id=xxx.apps.googleusercontent.com&scope=https://www.googleapis.com/auth/cloudprint

Google アカウントでログインすると以下のような画面が表示されますので、「許可」ボタンを押下します。

f:id:fits:20151221233721p:plain

コードが表示されるのでコピーしておきます。

f:id:fits:20151221233746p:plain

(2) リフレッシュトークンの取得

次に、下記パラメータを https://www.googleapis.com/oauth2/v3/token へ POST し、リフレッシュトークンを含んだ JSON を取得します。

パラメータ
code (1) で取得したコード
client_id クライアント ID の client_id 値
client_secret クライアント ID の client_secret 値
grant_type authorization_code
redirect_uri oob (※1)
(※1)(1) の場合と同様です。

       ただし、以下のスクリプトでは
       urn:ietf:wg:oauth:2.0:oob を設定しています

Groovy スクリプト化すると以下のようになります。

get_refresh-token.groovy
@Grab('com.mashape.unirest:unirest-java:1.4.9')
import com.mashape.unirest.http.Unirest
import groovy.json.JsonSlurper

addShutdownHook {
    Unirest.shutdown()
}

def json = new JsonSlurper()

def conf = json.parse(new File(args[0])).installed
def code = args[1]

def res = Unirest.post('https://www.googleapis.com/oauth2/v3/token')
    .field('code', code)
    .field('client_id', conf.client_id)
    .field('client_secret', conf.client_secret)
    .field('grant_type', 'authorization_code')
    .field('redirect_uri', conf.redirect_uris[0])
    .asJson()

println res.body

クライアント ID 発行時にダウンロードした JSON (ここでは client_secret.json) を第1引数、(1) で取得したコードを第2引数へ指定して実行します。

取得したリフレッシュトークン JSON は後で使うので保存しておきます。 (ここでは token.json へ保存)

実行例
> groovy get_refresh-token.groovy client_secret.json 4/9ic・・・ > token.json

プリンタ一覧の取得

リフレッシュトークンを使う場合は、以下のような手順で API を呼び出します。

  1. リフレッシュトークンからアクセストークンを取得
  2. アクセストークンを使って API を実行

リフレッシュトークンからアクセストークン取得

アクセストークンを取得するには、下記パラメータを https://www.googleapis.com/oauth2/v3/token へ POST します。

パラメータ
client_id クライアント ID の client_id 値
client_secret クライアント ID の client_secret 値
grant_type refresh_token
refresh_token リフレッシュトークンの値 (※1)
(※1)リフレッシュトークン取得で保存した JSON の refresh_token 値

この処理は共通的に使用するため、Groovy の BaseScript として定義しました。

TokenScript.groovy
import com.mashape.unirest.http.Unirest
import groovy.json.JsonSlurper

abstract class TokenScript extends Script {
    // アクセストークンの取得
    def accessToken(String clientId, String clientSecret, String refreshToken) {
        def res = Unirest.post('https://www.googleapis.com/oauth2/v3/token')
            .field('client_id', clientId)
            .field('client_secret', clientSecret)
            .field('grant_type', 'refresh_token')
            .field('refresh_token', refreshToken)
            .asJson()

        res.body.object
    }
}

API 実行 (プリンタの一覧取得)

アクセストークンは HTTP ヘッダーへ Authorization: Bearer <アクセストークン> のように設定して使います。(例. Authorization: Bearer ya26.pw・・・)

クラウドプリンタ一覧は https://www.google.com/cloudprint/search へ GET すれば取得できます。 (q や type パラメータを付けて条件検索することも可能)

get_printers.groovy
@Grab('com.mashape.unirest:unirest-java:1.4.9')
import com.mashape.unirest.http.Unirest
import groovy.json.JsonSlurper
import groovy.transform.BaseScript

// TokenScript を BaseScript へ設定
@BaseScript TokenScript baseScript

addShutdownHook {
    Unirest.shutdown()
}

def json = new JsonSlurper()

def conf = json.parse(new File(args[0])).installed
def token = json.parse(new File(args[1]))

// アクセストークン取得
def newToken = accessToken(
    conf.client_id,
    conf.client_secret,
    token.refresh_token
)

// API の実行
def printers = Unirest.get('https://www.google.com/cloudprint/search')
    .header('Authorization', "${newToken.token_type} ${newToken.access_token}")
    .asJson()

println printers.body

実行結果は以下の通りです。
まだプリンタを登録していないためデフォルトの 「ドライブに保存」 しかありません。

実行結果 (出力結果は加工済、実際は改行・字下げは無し)
> groovy get_printers.groovy client_secret.json token.json

{
    "request":{・・・},
    "printers":[{
        "isTosAccepted":false,
        "displayName":"ドライブに保存",
        "capsHash":"",
        "description":"ドキュメントを Google ドライブで PDF として保存します",
        "updateTime":"1370287324050",
        "ownerId":"cloudprinting@gmail.com",
        "type":"DRIVE",
        "tags":["save","docs","pdf","google","__google__drive_enabled"],
        "proxy":"google-wide",
        "ownerName":"Cloud Print",
        "createTime":"1311368403894",
        "defaultDisplayName":"ドライブに保存",
        "connectionStatus":"ONLINE",
        "name":"Save to Google Docs",
        "id":"__google__docs",
        "accessTime":"1316132041869",
        "status":""
    }],
    "success":true,
    ・・・
}

また、https://www.google.com/cloudprint/list?proxy=<プロキシ> へ GET すると、指定プロキシへ属するプリンタ一覧を取得できます。

印刷処理 (Google Drive へ保存)

最後に、「ドライブに保存」 プリンタへファイルを印刷してみます。 (実際は Google Drive へファイル保存)

印刷は、下記の必須パラメータ(他にもパラメータあり)を multipart/form-datahttps://www.google.com/cloudprint/submit へ POST します。

パラメータ
printerid プリンタ ID (※1)
title 印刷タイトル
ticket 印刷設定 (※2)
content 印刷するファイルの内容
(※1)今回は __google__docs を使用
(※2)CJT (Cloud Job Ticket) フォーマットで印刷オプションなどを指定
submit_file.groovy
@Grab('com.mashape.unirest:unirest-java:1.4.9')
import com.mashape.unirest.http.Unirest
import groovy.json.JsonSlurper
import groovy.json.JsonBuilder
import groovy.transform.BaseScript

@BaseScript TokenScript baseScript

addShutdownHook {
    Unirest.shutdown()
}

def ticketBuilder = new JsonBuilder()

// ticket の内容
ticketBuilder (
    version: '1.0',
    print: {}
)

def json = new JsonSlurper()

def conf = json.parse(new File(args[0])).installed
def token = json.parse(new File(args[1]))
def file = new File(args[2])

// アクセストークンの取得
def newToken = accessToken(
    conf.client_id,
    conf.client_secret,
    token.refresh_token
)

// ticket の JSON 文字列化
def ticket = ticketBuilder.toString()

// 印刷
def res = Unirest.post('https://www.google.com/cloudprint/submit')
    .header('Authorization', "${newToken.token_type} ${newToken.access_token}")
    .field('printerid', '__google__docs')
    .field('title', file.name)
    .field('ticket', ticket)
    .field('content', file)
    .asJson()

println res.body

PDF ファイルを POST した結果は以下の通りです。
Google Drive で確認すると sample1.pdf ファイルが保存されていました。

実行結果 (出力結果は加工済、実際は改行・字下げは無し)
> groovy submit_file.groovy client_secret.json token.json data/sample1.pdf

{
    "request":{・・・},
    "success":true,"xsrf_token":"AIp・・・",
    "message":"印刷ジョブが追加されました。",
    "job":{
        "ticketUrl":"https://www.google.com/cloudprint/ticket?format=xps&output=xml&jobid=0db・・・",
        "printerName":"",
        "errorCode":"",
        ・・・
        "title":"sample1.pdf",
        "tags":["^own"],
        ・・・
        "printerid":"__google__docs",
        ・・・
        "contentType":"application/pdf",
        "status":"DONE"
    }
}

また、試しに以下のような拡張子のファイルを POST してみたところ、自動的に PDF へ変換され Google Drive へ保存されました。 (例えば sample1.html は sample1.html.pdf で保存)

  • .html
  • .docx
  • .odt