デプロイ API を使ってコマンドラインでアプリをコピーしてみよう

著者名: KADOYA Ryo (External link)

目次

はじめに

今回は、コマンドラインHTTPクライアントのcurlを使って、既存のアプリを別のkintoneにコピーしてみたいと思います。
デプロイAPIでアプリをコピーするときのハマりどころについて重点的に説明します。

アプリ情報を取得・設定するAPIやデプロイAPIについて、次のAPIドキュメントを参考してください。
アプリの設定を操作する kintone REST API

下準備

コマンドラインでcurlを利用します。
curlはLinuxやMacOS Xで標準搭載されています。
Windowsでもcygwinなどを使って利用できます。

curl (External link)

curlの基本的な使い方

curlでkintoneにアクセスするうえでの基本的なオプションは以下です。

1
curl -X <メソッド> -H <ヘッダー情報> -d <パラメータ>

共通のパラメーターを事前に定義しておきます。
以下をターミナルで実行します。
user:passwordおよびsubdomainの部分は適宜置き換えてください。

1
2
3
4
BASE64=`echo -n 'user:password' | openssl base64`
AUTH="X-Cybozu-Authorization: ${BASE64}"
JSON="Content-Type: application/json"
HOST=“https://subdomain.cybozu.com/k"

次は、curlでkintoneから情報を取得してみました。

1
2
3
curl -X GET -H "$AUTH" -H "$JSON" -d '{id:160}'  ${HOST}/v1/app.json

{"appId":"160","code":"","createdAt":"2015-08-21T10:42:16.000Z","creator":{"code":"Ita","name":"ita"},"description":"日々の業務内容、報告事項、所感などを記載していくアプリです。\u003Cdiv\u003E記録を行うだけでなく、あとからの振り返りやメンバー間のコミュニケーションにも活用できます。\u003C/div\u003E","modifiedAt":"2015-08-21T10:43:25.000Z","modifier":{"code":"Ita","name":"ita"},"name":"日報","spaceId":null,"threadId":null}

BASIC認証を使用する場合は、以下のようにBASIC認証用のヘッダーを追加してください。

1
2
BASIC="basic\_user:basic\_password"
curl -X GET --user "$BASIC" -H "$AUTH" -H "$JSON" -d '{id:160}'  ${HOST}/v1/app.json

この日報アプリを、APIを使ってコピーしてみることにします。

アプリの作成

動作テスト環境にアプリを作成する APIを使用してアプリを作成します。

1
2
3
curl -X POST -H "$AUTH" -H "$JSON" -d '{name:"コピーされたアプリ"}'  ${HOST}/v1/preview/app.json

{"app":"162","revision":"2"}

アプリID: 162のアプリが作成されました。
まだ運用環境には適用されていないのでトップページには表示されませんが、以下のURLから管理画面にアクセスできます。
https://subdomain.cybozu.com/k/admin/app/flow?app=162

一般設定情報のコピー

コピー元アプリの設定情報を取得する

それではまず、コピー元のアプリから一般設定情報を取得します。

1
curl -X GET -H "$AUTH" -H "$JSON" -d '{app:160}'  ${HOST}/v1/preview/app/settings.json > settings.json

取得した設定情報を編集する

ここで取得した一般設定情報を、新しく作成したアプリに適用しますが、取得したjsonをそのまま適用できません。
appパラメーターを付与し、revisionパラメーターを除外する必要があります。

取得したsettings.jsonの中身は次のとおりです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
    "description":"日々の業務内容、報告事項、所感などを記載していくアプリです。\u003Cdiv\u003E記録を行うだけでなく、あとからの振り返りやメンバー間のコミュニケーションにも活用できます。\u003C/div\u003E",
    "icon":{
        "key":"APP15",
        "type":"PRESET"
    },
    "name":"日報",
    "revision":"7",
    "theme":"CLIPBOARD"
}

appパラメーターを付与し、revisionパラメーターを除外します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
    "app":162,
    "description":"日々の業務内容、報告事項、所感などを記載していくアプリです。\u003Cdiv\u003E記録を行うだけでなく、あとからの振り返りやメンバー間のコミュニケーションにも活用できます。\u003C/div\u003E",
    "icon":{
        "key":"APP15",
        "type":"PRESET"
    },
    "name":"日報",
    "theme":"CLIPBOARD"
}

設定情報を適用する

修正したjsonをPUTメソッドで送信します。
curlでは-dオプションに@をつけてファイルを指定できます。

1
2
3
curl -X PUT -H "$AUTH" -H "$JSON" -d '@settings.json' ${HOST}/v1/preview/app/settings.json

{"revision":"3"}

フォーム情報のコピー

フォーム情報を取得する

同様に、コピー元のアプリから情報を取得します。

1
curl -X GET -H "$AUTH" -H "$JSON" -d '{app:160}' ${HOST}/v1/preview/app/form/fields.json > fields.json

取得したフォーム情報を編集する

ここで取得したデータも、やはりそのままでは送信できません。
app/revisionパラメーターの処理に加えて、ビルトインフィールドの問題があるためです。

ビルトインフィールドは、アプリの作成時に自動的に追加されるため、フィールドの追加APIでの追加はできません。
したがってこれらのフィールドはアプリの新規追加時でも、変更APIを使用する必要があります。

ビルトインフィールドの一覧
  • レコード番号(type:"RECORD_NUMBER")
  • 作成者(type:"CREATOR")
  • 作成日時(type”:"CREATED_TIME")
  • 更新者(type:"MODIFIER")
  • 更新日時(type:"UPDATED_TIME")
  • ステータス(type:"STATUS")
  • 作業者(type:"STATUS_ASSIGNEE")
  • カテゴリー(type:"CATEGORY")

カテゴリーやプロセス管理を使わない設定でも、内部的にカテゴリー、作業者フィールドは追加されています。
取得したjsonをビルトインフィールドとビルトインでないフィールドに分けます。

builtin_fields.json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
{
  "app": 162,
  "properties": {
    "更新日時": {
      "code": "更新日時",
      "label": "更新日時",
      "noLabel": false,
      "type": "UPDATED_TIME"
    },
    "作成者": {
      "code": "作成者",
      "label": "作成者",
      "noLabel": false,
      "type": "CREATOR"
    },
    "ステータス": {
      "code": "ステータス",
      "enabled": false,
      "label": "ステータス",
      "type": "STATUS"
    },
    "更新者": {
      "code": "更新者",
      "label": "更新者",
      "noLabel": false,
      "type": "MODIFIER"
    },
    "カテゴリー": {
      "code": "カテゴリー",
      "enabled": false,
      "label": "カテゴリー",
      "type": "CATEGORY"
    },
    "作業者": {
      "code": "作業者",
      "enabled": false,
      "label": "作業者",
      "type": "STATUS_ASSIGNEE"
    },
    "レコード番号": {
      "code": "レコード番号",
      "label": "レコード番号",
      "noLabel": false,
      "type": "RECORD_NUMBER"
    },
    "作成日時": {
      "code": "作成日時",
      "label": "作成日時",
      "noLabel": false,
      "type": "CREATED_TIME"
    }
  }
}
fields.json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
{
  "app": 162,
  "properties": {
    "日付": {
      "code": "日付",
      "defaultNowValue": true,
      "defaultValue": "",
      "label": "日付",
      "noLabel": false,
      "required": false,
      "type": "DATE",
      "unique": false
    },
    "文字列__複数行_": {
      "code": "文字列__複数行_",
      "defaultValue": "",
      "label": "業務内容",
      "noLabel": false,
      "required": false,
      "type": "MULTI_LINE_TEXT"
    },
    "文字列__複数行__0": {
      "code": "文字列__複数行__0",
      "defaultValue": "",
      "label": "所感、学び",
      "noLabel": false,
      "required": false,
      "type": "MULTI_LINE_TEXT"
    },
    "ドロップダウン": {
      "code": "ドロップダウン",
      "defaultValue": "",
      "label": "部署",
      "noLabel": false,
      "options": {
        "サポート": {
          "index": "3",
          "label": "サポート"
        },
        "営業": {
          "index": "0",
          "label": "営業"
        },
        "開発": {
          "index": "4",
          "label": "開発"
        },
        "総務": {
          "index": "2",
          "label": "総務"
        },
        "マーケティング": {
          "index": "1",
          "label": "マーケティング"
        }
      },
      "required": false,
      "type": "DROP_DOWN"
    },
    "添付ファイル": {
      "code": "添付ファイル",
      "label": "添付ファイル",
      "noLabel": false,
      "required": false,
      "thumbnailSize": "150",
      "type": "FILE"
    },
    "ラジオボタン": {
      "align": "HORIZONTAL",
      "code": "ラジオボタン",
      "defaultValue": "達成",
      "label": "目標達成度",
      "noLabel": false,
      "options": {
        "達成": {
          "index": "0",
          "label": "達成"
        },
        "未達": {
          "index": "1",
          "label": "未達"
        }
      },
      "required": true,
      "type": "RADIO_BUTTON"
    }
  }
}

フォーム情報を適用する

フォームにフィールドを追加するため、それぞれ次のAPIを実行します。

  • ビルトインでないフィールド: フィールドを追加する API

    1
    2
    3
    
    curl -X POST -H "$AUTH" -H "$JSON" -d '@fields.json' ${HOST}/v1/preview/app/form/fields.json
    
    {"revision":"4"}
  • ビルドインフィールド: フィールドの設定を変更する API

    1
    2
    3
    
    curl -X PUT -H "$AUTH" -H "$JSON" -d '@builtin_fields.json' ${HOST}/v1/preview/app/form/fields.json
    
    {"revision":"5"}

なお、フィールドを追加した後は、ビルトインでないフィールドも フィールドの設定を変更する APIで変更します。

レイアウト情報のコピー

レイアウト情報を取得する

元のアプリから一レイアウト情報を取得します。

1
curl -X GET -H "$AUTH" -H "$JSON" -d '{app:160}'  ${HOST}/v1/preview/app/form/layout.json > layout.json

レイアウト情報を編集して適用する

appを追加しrevisionを削除して、PUTメソッドで送信します。

1
2
3
curl -X PUT -H "$AUTH" -H "$JSON" -d '@layout.json' ${HOST}/v1/preview/app/form/layout.json

{"revision":"6"}

一覧のコピー

一覧情報を取得する

元のアプリから一覧情報を取得します。

1
curl -X GET -H "$AUTH" -H "$JSON" -d '{app:160}'  ${HOST}/v1/preview/app/views.json > views.json

一覧情報を編集する

取得したviews.jsonの中身は次のとおりです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
  "revision": "7",
  "views": {
    "自分の日報(カレンダー形式)": {
      "date": "日付",
      "filterCond": "作成者 in (LOGINUSER())",
      "id": "9265",
      "index": "1",
      "name": "自分の日報(カレンダー形式)",
      "sort": "作成日時 desc",
      "title": "文字列__複数行_",
      "type": "CALENDAR"
    },
    "日報一覧": {
      "fields": ["日付", "作成者", "文字列__複数行_", "文字列__複数行__0"],
      "filterCond": "",
      "id": "2128",
      "index": "0",
      "name": "日報一覧",
      "sort": "作成日時 desc",
      "type": "LIST"
    }
  }
}

これまでと同様にappを追加してrevisionを削除します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
  "app":162,
  "views": {
    "自分の日報(カレンダー形式)": {
      "date": "日付",
      "filterCond": "作成者 in (LOGINUSER())",
      "id": "9265",
      "index": "1",
      "name": "自分の日報(カレンダー形式)",
      "sort": "作成日時 desc",
      "title": "文字列__複数行_",
      "type": "CALENDAR"
    },
    "日報一覧": {
      "fields": ["日付", "作成者", "文字列__複数行_", "文字列__複数行__0"],
      "filterCond": "",
      "id": "2128",
      "index": "0",
      "name": "日報一覧",
      "sort": "作成日時 desc",
      "type": "LIST"
    }
  }
}

一覧情報を適用する

PUTメソッドで送信します。

1
2
3
curl -X PUT -H "$AUTH" -H "$JSON" -d '@views.json' ${HOST}/v1/preview/app/views.json

{"revision":"7","views":{"自分の日報(カレンダー形式)":{"id":"5259991"},"日報一覧":{"id":"5259990"}}}
caution
警告

一覧をコピーする際に注意する点としては、以下があります。

  • プロセス管理を使う場合、builtinType=ASSIGNEEの一覧が生成されますが、この一覧は移行できないため、jsonから除外する必要があります。
  • コピー元で作業者をフィルター条件とした一覧が存在する場合、コピー先でプロセス管理が有効でないとこの一覧を移行できません。

アプリを運用環境に適用する

最後に、deploy.jsonを使ってアプリを運用環境に適用します。

1
curl -X POST -H "$AUTH" -H "$JSON" -d '{apps:[{app:162}]}' ${HOST}/v1/preview/app/deploy.json

GET deploy.jsonstatus:SUCCESSが帰ってきたらデプロイ成功です。

1
2
3
curl -X GET -H "$AUTH" -H "$JSON" -d '{apps:[162]}' ${HOST}/v1/preview/app/deploy.json

{"apps":[{"app":"162","status":"SUCCESS"}]}

おわりに

いかがだったでしょうか。
デプロイAPIを使えば、カスタマイズしたJSやCSSの設定や、アクセス権の移行もできます。
今回は同一のkintoneへコピーしましたが、別の環境のkintoneへもアプリを移行できます。
これまで、手動で行っていたアプリの設定はAPIを使って行えることになって、運用の手間が省けられるかと思います。