GASでスプレッドシートを
JSON APIとして公開する方法
スプレッドシートを簡易データベースにして、doGetとContentServiceでJSONを返すAPI(アプリ同士がデータをやり取りする窓口)をサーバーなしで作る方法を、動くコードで解説します。
Table of Contents
GASでJSON APIを作るとできること
GASのdoGet関数とWebアプリ公開機能を使うと、スプレッドシートの中身をJSON(アプリ間でデータをやり取りする軽量な形式)で返すURLをサーバーなしで作れます。 担当者が普段どおりシートを編集するだけで、その内容をそのままWebサイトやアプリから読み取れるのが利点です。
お知らせ・料金表の配信
シートで管理したお知らせや価格を、コーポレートサイトやLPから読み込んで表示する
商品・在庫マスタの提供
商品リストや在庫数をシートで更新し、外部アプリにJSONで渡す
簡易な設定サーバー
アプリの表示切り替えフラグなどを、コード修正なしでシートから変更する
ノーコードツール連携
他サービスからHTTPで呼び出し、シートのデータを取り込む窓口にする
doGetでJSONを返す基本コード
GASではdoGet(e)という決まった名前の関数を用意すると、公開URLにアクセスがあったときに自動で呼ばれます。 1行目を見出し(キー)として使い、2行目以降を1行=1オブジェクトに変換して返すのが基本の形です。MimeType.JSONを指定することで、レスポンスがJSONとして扱われます。
function doGet(e) {
const sheet = SpreadsheetApp.getActive().getSheetByName("商品マスタ");
const rows = sheet.getDataRange().getValues();
const header = rows.shift(); // 1行目を見出しとして取り出す
const items = rows.map((row) => {
const obj = {};
header.forEach((key, i) => {
obj[key] = row[i];
});
return obj;
});
return ContentService
.createTextOutput(JSON.stringify({ ok: true, items: items }))
.setMimeType(ContentService.MimeType.JSON);
}「商品マスタ」シートの1行目に「商品名」「カテゴリ」「価格」といった見出しがあれば、 各行が{ "商品名": "...", "カテゴリ": "...", "価格": 500 }の形で返ります。
行をオブジェクトに変換する共通関数
このあと絞り込みやキャッシュを足していくので、「シートを読む処理」と「JSONを返す処理」を先に共通関数に切り出しておきます。doGet本体がすっきりし、他の関数からも使い回せます。
// JSONレスポンスを作る共通関数
function jsonResponse(obj) {
return ContentService
.createTextOutput(JSON.stringify(obj))
.setMimeType(ContentService.MimeType.JSON);
}
// シートを「見出しをキーにしたオブジェクトの配列」に変換する
function readItems() {
const sheet = SpreadsheetApp.getActive().getSheetByName("商品マスタ");
const rows = sheet.getDataRange().getValues();
const header = rows.shift();
return rows.map((row) => {
const obj = {};
header.forEach((key, i) => {
obj[key] = row[i];
});
return obj;
});
}クエリパラメータで絞り込む
URLの末尾に付ける?category=文房具&limit=20のような値(クエリパラメータ)は、e.parameterで受け取れます。カテゴリ絞り込み・キーワード検索・件数制限を組み合わせれば、必要なデータだけを返すAPIになります。
function doGet(e) {
const params = e.parameter; // 例: ?category=文房具&limit=20
let items = readItems();
// カテゴリで絞り込む
if (params.category) {
items = items.filter((item) => item["カテゴリ"] === params.category);
}
// キーワードを含む商品名で絞り込む
if (params.q) {
items = items.filter((item) =>
String(item["商品名"]).indexOf(params.q) !== -1
);
}
// 件数を制限する
if (params.limit) {
items = items.slice(0, Number(params.limit));
}
return jsonResponse({ ok: true, count: items.length, items: items });
}呼び出し例:.../exec?category=文房具&limit=20。日本語の値はブラウザやfetchが自動でURLエンコードするため、GAS側はe.parameterをそのまま扱えます。
CacheServiceでアクセスを高速化する
アクセスのたびにgetValues()で全行を読むと、行数が多いほど遅くなります。CacheServiceに組み立て済みのJSON文字列を数分ためておくと、多くのリクエストをキャッシュから即座に返せます。
function doGet(e) {
const cache = CacheService.getScriptCache();
const cached = cache.get("products_json");
if (cached) {
return ContentService
.createTextOutput(cached)
.setMimeType(ContentService.MimeType.JSON);
}
const json = JSON.stringify({ ok: true, items: readItems() });
cache.put("products_json", json, 300); // 300秒(5分)キャッシュ
return ContentService
.createTextOutput(json)
.setMimeType(ContentService.MimeType.JSON);
}キャッシュ時間はデータの更新頻度に合わせて調整します。頻繁に書き換わるなら短く、ほぼ固定のマスタなら長めにすると効果的です。 シートを更新した瞬間に反映したい場合は、onEditでキャッシュを消す設計も検討します。
JSONPで外部サイトから呼び出す
ブラウザから直接fetchすると、GASのリダイレクト仕様やCORS(別ドメインへのアクセス制限)でエラーになることがあります。 外部サイトのJavaScriptから読みたい場合は、callbackパラメータを受け取り、JSONP(関数呼び出しの形でJSを返す方式)で返すと回避できます。
function doGet(e) {
const json = JSON.stringify({ ok: true, items: readItems() });
// ?callback=render が付いていればJSONPとして返す
if (e.parameter.callback) {
return ContentService
.createTextOutput(e.parameter.callback + "(" + json + ")")
.setMimeType(ContentService.MimeType.JAVASCRIPT);
}
return ContentService
.createTextOutput(json)
.setMimeType(ContentService.MimeType.JSON);
}呼び出し側は<script src="...?callback=render">のように読み込み、render(data)関数でデータを受け取ります。サーバー側から呼べる環境なら、素直にサーバー経由でアクセスするほうが安全です。
認証とエラー処理を加える
公開範囲を「全員」にするとURLを知っている人は誰でも読めます。社内データを扱うなら、合言葉となるトークンをクエリで受け取り、一致しないリクエストを拒否する簡易認証を入れます。 あわせてtry-catchで例外を握り、エラー時もJSONで返すようにします。
function doGet(e) {
try {
// 簡易トークン認証(合言葉が一致しないリクエストは拒否する)
const TOKEN = "your-secret-token";
if (e.parameter.token !== TOKEN) {
return jsonResponse({ ok: false, error: "unauthorized" });
}
const items = readItems();
return jsonResponse({ ok: true, count: items.length, items: items });
} catch (err) {
return jsonResponse({ ok: false, error: String(err) });
}
}トークンはコードに直書きせず、PropertiesServiceのスクリプトプロパティに保存すると、ソースを共有しても値が漏れません。あくまで簡易認証なので、機密性の高いデータはこの方式に頼りすぎないようにします。
Webアプリとして公開する手順
コードを書いたら、エディタから公開してURLを発行します。手順は次のとおりです。
1. デプロイ画面を開く
スクリプトエディタ右上の「デプロイ」→「新しいデプロイ」を選び、種類として「ウェブアプリ」を指定します。
2. 実行者とアクセス範囲を決める
「次のユーザーとして実行」は通常「自分」、「アクセスできるユーザー」は用途に応じて「全員」または「同じドメインのユーザー」などを選びます。誰でも読ませたいAPIは「全員」です。
3. 発行されたURLにアクセスする
デプロイすると.../execで終わるURLが発行されます。ブラウザで開いてJSONが表示されれば成功です。コードを直したら「デプロイを管理」から更新すると、同じURLのまま反映されます。
実務での注意点
1. 機密データを「全員」に公開しない
個人情報や社外秘のデータをそのまま「全員」公開のAPIにすると、URLが漏れた時点で誰でも読めてしまいます。返す列を必要最小限に絞り、機密は載せない設計にします。
2. 大量アクセス・大量データに備える
GASには実行時間や1日あたりの実行回数などの上限があります。行数が多い、アクセスが集中する用途では、キャッシュの活用と返却件数の制限が欠かせません。
3. 書き込みはdoPostで慎重に
データの登録・更新をさせたい場合はdoPostを使います。ただし公開URLへの書き込みは悪用リスクがあるため、トークン認証と入力チェックを必ず入れ、LockServiceで同時書き込みの競合も防ぎます。
まとめ
GASのdoGetとContentServiceを使えば、スプレッドシートをそのままJSON APIとして無料で公開できます。行→オブジェクト変換、クエリでの絞り込み、CacheServiceでの高速化、JSONPでの外部連携、トークン認証とエラー処理まで押さえれば、実務でも十分使えるエンドポイントになります。 担当者がシートを更新するだけでデータが配信される仕組みは、小規模なマスタ配信や設定サーバーとして特に相性が良い構成です。
よくある質問
必要ありません。GASのdoGet関数とWebアプリ公開機能を使えば、サーバーを用意せずにスプレッドシートの中身をJSONで返すエンドポイント(URL)を無料で作れます。公開すると「https://script.google.com/macros/s/.../exec」のようなURLが発行され、そこにアクセスするとJSONが返ります。
doGetはURLにアクセスする(GETリクエスト)ときに呼ばれ、データの取得・表示に使います。doPostはデータを送信する(POSTリクエスト)ときに呼ばれ、スプレッドシートへの書き込みや登録に使います。読み取り専用のAPIならdoGetだけで十分です。
ブラウザからのfetchはGASのリダイレクト仕様やCORSの制約でエラーになることがあります。対策は2つあります。1つはサーバー側(自社のバックエンドや別のGAS)から呼び出す方法。もう1つはcallbackパラメータを付けてJSONP形式(MimeType.JAVASCRIPT)で返す方法です。本文でJSONPのコードを紹介しています。
毎回getValues()で全行を読むと遅くなります。CacheServiceでJSON文字列を数分キャッシュすると、多くのアクセスをキャッシュから返せて高速かつ安定します。データの更新頻度に合わせてキャッシュ時間(秒数)を調整してください。
Webアプリの公開設定を「全員」にするとURLを知っている人は誰でも読めます。社内限定にしたい場合は「自分のみ」「同じドメインのユーザー」に設定するか、クエリパラメータに合言葉となるトークンを付け、doGet内でトークンが一致しないリクエストは拒否する簡易認証を入れると安全性が上がります。
スプレッドシート連携・
業務Webシステムを相談する。
スプレッドシートをデータベース代わりに使ったAPI公開・Webアプリ・外部サービス連携まで、GASを活かした業務システム開発をご相談いただけます。