ZAF (Zendesk Apps Framework) のクライアントサイドアプリでインフラのコストと責任分界が消える
はじめに
Zendesk のチケット画面に社内システムの情報を出すサイドバーアプリを作りました。設計で最初に迷ったのは、アプリをどこで動かすかです。

Zendesk のアプリは、ZAF (Zendesk Apps Framework) という枠組みの上で作ります。ZAF は、アプリの画面を Zendesk の管理画面に埋め込み、外部 API の呼び出しや認証情報の扱いまで面倒を見てくれるフレームワークです。この ZAF アプリには、アセットを Zendesk が配信するクライアントサイドアプリと、自前サーバでアセットをホストするサーバサイドアプリの 2 種類があります。
最初は使い慣れた自前サーバを思い浮かべましたが、クライアントサイドで十分に組めると分かり、そちらを選びました。実際に作って配信してみて一番ありがたかったのは、機能そのものよりも、自前サーバ方式なら自分が負っていたインフラのコストと責任分界が、まるごと消えたことでした。
本記事では、ZAF アプリで Zendesk が何をどこまで肩代わりするのかと、サーバサイド方式と比べて何が消えるのかをまとめます。
対象読者
- Zendesk アプリの実行環境を、クライアントサイドとサーバサイドのどちらにするか迷っている方
- 外部 API を呼ぶ社内向けの Zendesk アプリを、なるべく運用の負担を増やさずに作りたい方
参考
- Choose your own app adventure
- Using the Apps framework
- Manifest reference
- Making API requests from a Zendesk app
- Using ZCLI
Zendesk が肩代わりする 3 つのこと
ZAF のクライアントサイドアプリを選ぶと、Zendesk が次の 3 つを肩代わりします。
1 つ目はアセットの配信です。
公式ドキュメントには次のように書かれています。
Zendesk stores your app's assets and serves them up to your agent's browser -- no need to host any of your app's assets on some other server.
manifest.json の location にローカルの HTML を指定すると、その HTML と JavaScript や CSS を Zendesk がエージェントのブラウザへ配信します。アセットを置くためのサーバは要りません。
{
"location": {
"support": {
"ticket_sidebar": "assets/iframe.html"
}
},
"frameworkVersion": "2.0"
}
2 つ目は外部 API 呼び出しの中継です。
社内システムの API をブラウザの JavaScript から直接呼ぶと、多くの場合 CORS の制約で弾かれます。
呼ばれる API 側が許可のヘッダを返さない限り、リクエストは通りません。社内向けの API にそのための設定をわざわざ足すのは、手間もリスクもあります。
ZAF の client.request() は、この問題を中継によって解決します。Zendesk 以外の URL を呼ぶと、既定ではリクエストが Zendesk のプロキシサーバを経由します。ブラウザから外部 API への直接アクセスではなく、Zendesk のサーバから外部 API へのサーバ間の通信になるため、CORS の制約を受けません。呼ばれる API 側に手を入れなくても、そのまま呼べます。
3 つ目はシークレットの秘匿です。
外部 API を呼ぶには、API キーや Basic 認証などの認証情報が要ります。これをフロントエンドに直接書くと、認証情報が手元まで届いてしまいます。開発者ツールを開けば、誰でもその値を読める状態です。
これを避けようとすると、本来はサーバの出番になります。認証情報を持つプロキシを自分で立て、ブラウザからはそのプロキシ経由で外部 API を呼ぶ、という構成です。クライアントサイドで完結させたいだけなのに、認証情報を隠すためだけにサーバを 1 台用意することになります。
Zendesk はここも肩代わりします。認証情報を Secure Settings という設定値として登録し、リクエストのヘッダには実値の代わりに {{setting.名前}} というプレースホルダを書きます。リクエストがプロキシを通るとき、プロキシがサーバ側でプレースホルダを実値に差し替えてから外部 API へ送ります。認証情報はプロキシより手前には出ないため、フロントエンドにはプレースホルダだけが現れます。自分でプロキシを用意しなくても、認証情報を隠せます。
アプリの配信経路とリクエストの流れを図にすると次のようになります。
配信は zcli (Zendesk CLI) で行います。サーバの構築も監視も登場しません。apps:validate で manifest.json とアセットを検証し、apps:create で初回アップロード、2 回目以降は apps:update で反映します。
npx @zendesk/zcli apps:validate
npx @zendesk/zcli apps:create
npx @zendesk/zcli apps:update
自前サーバ方式と比べて消えるもの
ここからが、実際に作って一番実感した点です。同じアプリをサーバサイドで自前ホストしていたら、自分が負っていたはずのものを並べてみます。
サーバサイドアプリでは、アセットを自前のサーバに置くため、そのサーバの面倒を最後まで自分で見ることになります。具体的には、常時稼働するサーバの費用、OS やミドルウェアのパッチ、TLS 証明書の更新、監視やログ、障害時の切り分けが、すべて自分の責任範囲に入ります。数エージェントが使う社内向けのサイドバーのために、24 時間動くサーバを 1 台抱え続ける構図です。
クライアントサイドアプリを選ぶと、この責任範囲が Zendesk 側へ移ります。自分が持つのはアプリのコードだけになり、アセットの配信もその土台の運用も Zendesk の責任分界に入ります。
両者の違いを並べると次のようになります。
| 負担 | サーバサイド ( 自前ホスト ) | クライアントサイド ( Zendesk ホスト ) |
|---|---|---|
| サーバ費用 | 常時稼働分を負担 | 不要 |
| パッチ・脆弱性対応 | 自分で対応 | Zendesk 側 |
| TLS 証明書の更新 | 自分で管理 | Zendesk 側 |
| 監視・可用性 | 自分の責任 | Zendesk 側 |
| 障害時の切り分け範囲 | サーバからアプリまで | アプリのコードに閉じる |
特に助かると感じたのは、障害時の切り分け範囲が狭まる点です。
アプリが期待通り動かないとき、疑う範囲がアプリのコードに閉じるので、切り分けが速く済みました。インフラのコストと、落ちたら誰の責任かという線引きが最初から消えているのは、社内向けの小さなアプリほど楽だと感じました。
まとめ
Zendesk のクライアントサイドアプリでは、アセット配信・CORS 回避・シークレット秘匿の 3 点を Zendesk が肩代わりします。その結果、自前サーバ方式なら自分が負っていたインフラのコストと責任分界が、まるごと消えます。独自のバックエンド処理が本当に必要になるまでは、クライアントサイドアプリで十分に足ります。実行環境を迷っている方の判断材料になれば幸いです。





