GoogleAppsScript(GAS)でConfluence APIを使用する

AvatarPosted by

グリフォン Advent Calendar 2018 25日目の記事を担当しました、CTOの川村です。この記事ではGoogleAppsScriptからConfluence APIを使用する方法をご紹介します。

※この記事はGRIPHONE Advent Calendar 2018 25日目の記事です。
https://adventar.org/calendars/3147
https://qiita.com/advent-calendar/2018/griphone

GoogleAppsScript(GAS)とは

GoogleAppsScript(以下GAS)とは、Googleが提供しているJavaScriptベースのプログラム環境です。
非常に手軽にwebアプリを開発することが出来るため、弊社ではちょっとした自動化や効率化ツールにGASを用いるケースが多々あります。

以前このブログでご紹介したシャッフルランチのツールもGASで作られています。

Confluence API

弊社では情報共有ツールとしてConfluenceを使用しています。
ConfluenceはREST APIが公開されています。このAPIを使用してページの参照、作成、更新等を実行することが出来ます。

【REST APIドキュメント:https://developer.atlassian.com/cloud/confluence/rest/

GASからConfluence APIを使用する

それではここから早速サンプルコードです。
※2つ目以降、それ以前のサンプルコードと重複する部分は省略しています

1. ページ参照の例

【該当ドキュメント:https://developer.atlassian.com/cloud/confluence/rest/#api-content-id-get

 
var API_BASE_URL = 'https://XXXXX.atlassian.net/wiki';

function create_auth_data(user_id, password) {
  return Utilities.base64Encode(user_id + ':' + password);
}

function create_headers(auth_data) {
  return {
    'content-type'  : 'application/json',
    'Authorization' : 'Basic ' + auth_data
  };
}

function get_content_sample(headers, page_id, expand_string) {
  var options = {
    'headers' : headers,
    'method'  : 'get'
  };

  var api_url      = API_BASE_URL + '/rest/api/content/' + page_id + '?expand=' + expand_string;
  var response     = UrlFetchApp.fetch(api_url, options).getContentText('UTF-8');
  var content_json = JSON.parse(response);

  return content_json;
}

function sample1() {
  var auth_data    = create_auth_data('user_id', 'password');
  var headers      = create_headers(auth_data);
  var content_json = get_content_sample(headers, '00000', 'body.storage');
  Logger.log(content_json);
}

ページのIDを指定してその内容を取得する、シンプルな例です。
『expand』パラメータで取得する情報の範囲を指定しています。デフォルトでは『space,history,version』が設定されます。ページ内容を取得するには『body.storage』が必要になります。

2. ページ作成の例

【該当ドキュメント:https://developer.atlassian.com/cloud/confluence/rest/#api-content-post

function post_content_sample(headers, page_space_key, ancestors_page_id, page_title, page_body, expand_string) {
  var payload = {
    'type'      : 'page',
    'space'     : {'key' : page_space_key},
    'ancestors' : [{'id' : ancestors_page_id}],
    'title'     : page_title,
    'body'      : {
      'storage' : {
        'value'          : page_body,
        'representation' : 'storage'
      }
    }
  };
  payload = JSON.stringify(payload);

  var options = {
    'headers' : headers,
    'payload' : payload,
    'method' : 'post'
  };

  var api_url      = API_BASE_URL + '/rest/api/content/' + '?expand=' + expand_string;
  var response     = UrlFetchApp.fetch(api_url, options).getContentText('UTF-8');
  var content_json = JSON.parse(response);

  return content_json;
}

function sample2() {
  var auth_data    = create_auth_data('user_id', 'password');
  var headers      = create_headers(auth_data);
  var content_json = post_content_sample(headers, 'space_key', '00000', 'ページタイトル', 'ページ内容', null);
  Logger.log(content_json);
}

REST APIなので新規登録系の処理はHTTPメソッドが『post』になります。

ページを作成するスペース、親となるページを指定し、新規作成ページのタイトル名と内容をパラメータとして渡します(『payload』の部分)。

親ページの指定が無ければスペース直下にページが作成されます。
スペース指定は表示名ではなく『キー』を指定することに注意です。キーはそのスペースのURL、もしくはSpace Settingsから確認出来ます。
既に存在するタイトル名を指定するとエラーになることにも注意しましょう。

3. ページ更新の例

【該当ドキュメント:https://developer.atlassian.com/cloud/confluence/rest/#api-content-id-put

function put_content_sample(headers, page_id, current_version, new_page_title, new_page_body, expand_string) {
  var new_version = current_version + 1; // バージョンをインクリメントする
  var payload = {
    'type'    : 'page',
    'version' : {'number' : new_version},
    'title'   : new_page_title,
    'body'    : {
      'storage' : {
        'value'          : new_page_body,
        'representation' : 'storage'
      }
    }
  };
  payload = JSON.stringify(payload);

  options = {
    'headers' : headers,
    'payload' : payload,
    'method'  : 'put'
  };

  var api_url      = API_BASE_URL + '/rest/api/content/' + page_id;
  var response     = UrlFetchApp.fetch(api_url, options).getContentText('UTF-8');
  var content_json = JSON.parse(response);

  return content_json;
}

function sample3() {
  var auth_data = create_auth_data('user_id', 'password');
  var headers   = create_headers(auth_data);

  // 現在のバージョンを調べるため、更新対象のページ情報を取得
  var old_content_json = get_content_sample(headers, '00000', 'version');

  // 更新
  var content_json = put_content_sample(headers, '00000', old_content_json['version']['number'], '新ページタイトル', '新ページ内容', null);
  Logger.log(content_json);
}

REST APIなので更新系の処理はHTTPメソッドが『put』になります。

更新の際は『version』をインクリメントする必要があるので、『old_content_json』取得時に『expand』に『version』を指定しています。versionが正しくインクリメントされていないとエラーとなってしまいます。

4. CQLを使った検索の例

【該当ドキュメント:https://developer.atlassian.com/cloud/confluence/rest/#api-content-search-get

function search_content_sample(headers, cql_string, expand_string) {
  var options = {
    'headers' : headers,
    'method'  : 'get',
  };

  var api_url      = API_BASE_URL + '/rest/api/content/search?cql=' + cql_string + '&expand=' + expand_string;
  var response     = UrlFetchApp.fetch(api_url, options).getContentText('UTF-8');
  var content_json = JSON.parse(response);

  return content_json;
}

function sample4() {
  var auth_data    = create_auth_data('user_id', 'password');
  var headers      = create_headers(auth_data);
  var content_json = search_content_sample(headers, 'parent=00000 order by created desc', null);
  Logger.log(content_json);
}

ConfluenceにはCQL(Confluence Query Language)という専用のクエリ言語が提供されており、自由度の高い検索が可能となっています。
CQLについての詳細はこちらのドキュメントをご確認下さい。
https://ja.confluence.atlassian.com/confcloud/confluence-search-syntax-724765423.html

サンプルでは、あるページの子ページのリストを、作成時間の降順で取得しています。

'parent=00000 order by created desc'

SQLと同じノリで書けるのが便利ですね!

まとめ

弊社ではこのAPIを使用し、定例MTGの議事録ページを自動生成したり、議事録のサマリーを自動生成する等しています。地味に面倒なルーティン作業が減り、業務効率化が進みました!

今回はcontent系のAPIのみの紹介となりましたが、ドキュメントを見てみると非常に様々なAPIがあることが分かります。色んな可能性を感じますね!Confluenceを使用されている方には、このAPIの活用を強くオススメします!