経緯(時系列順)
-
GCPのAPI Gatewayでお手軽簡単にPublic APIを立てようとしたら、CORS(オリジン間リソース共有) が無効になっていて、ブラウザ上のJavaScriptからFetchできなかった
-
悲しい
-
何かCORSを有効化する方法あるはずだから調べてやってみよう
結論
下記を全部やれば、できるようになるよ!
-
Google Cloud API GatewayのAPI定義(OpenAPI仕様)で、CORSサポートを有効にする
-
同上のAPI定義で、CORSの Preflight request のパスを定義する
-
APIバックエンド(Cloud Functionsとか)で、CORS Preflight request時と通常のリクエスト時の双方について、CORS周りのヘッダを追加する
とりあえずコード見せて欲しい
Hello WorldするだけのWeb-APIを例に、CORS対応前後を比較するよ。
なお構成はこんな感じだよ
- APIバックエンド(今回は Cloud Functions で実装する)
- Cloud FunctionsのURL: 仮に「
https://asia-northeast1-hogehoge.cloudfunctions.net/hello
」とする
- Cloud FunctionsのURL: 仮に「
- API Gateway
- URL「
/greet
」 で上記のCloud Functionsをコールする
- URL「
Google Cloud API GatewayのAPI定義(OpenAPI仕様)
CORS対応前
swagger: '2.0'
info:
title: api-gateway-on-hogehoge
description: Sample API on API Gateway with a Google Cloud Functions backend
version: 1.0.0
schemes:
- https
produces:
- application/json
paths:
/greet:
get:
summary: Greet a user
operationId: hello
x-google-backend:
address: https://asia-northeast1-hogehoge.cloudfunctions.net/hello
responses:
'200':
description: A successful response
schema:
type: string
CORS対応後
# https://cloud.google.com/api-gateway/docs/secure-traffic-console?hl=ja
swagger: '2.0'
info:
title: api-gateway-on-hogehoge
description: Sample API on API Gateway with a Google Cloud Functions backend
version: 1.0.0
schemes:
- https
produces:
- application/json
x-google-endpoints:
- name: endpoints-for-hogehoge-api
allowCors: True
paths:
/greet:
options:
summary: cors
operationId: corsHello
x-google-backend:
address: https://asia-northeast1-hogehoge.cloudfunctions.net/hello
responses:
'200':
description: A successful response
schema:
type: string
get:
summary: Greet a user
operationId: hello
x-google-backend:
address: https://asia-northeast1-hogehoge.cloudfunctions.net/hello
responses:
'200':
description: A successful response
schema:
type: string
APIバックエンド(今回は Cloud Functions で実装)
CORS対応前
exports.helloWorld = (req, res) => {
const message = req.query.message || req.body.message || 'Hello World!';
res.status(200).send(message);
};
CORS対応後
exports.helloWorld = (req, res) => {
// ---- CORS有効化 ----
res.setHeader("Access-Control-Allow-Origin", "*");
if (req.method === "OPTIONS") {
// ---- CORS Preflight requestに応える ----
res.setHeader("Access-Control-Allow-Methods", "POST, GET");
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
res.setHeader("Access-Control-Max-Age", "3600");
res.status(204).send("");
return;
}
const message = req.query.message || req.body.message || 'Hello World!';
res.status(200).send(message);
};
実際にブラウザからコールしてみる
Webページのどこかにたとえばこんな感じでコールできる処理書いてみると...
<!-- URLは API Gatewayのものを指定 -->
<div onclick="fetch('https://api-gateway-on-hogehoge-aqiduyfc.an.gateway.dev/greet').then(res=>res.ok ? res.text().then(console.log) : console.log('error occured'))">hogehoge</div>
無事応答が返ってきた!
Hello World!
まとめ
- before: Google Cloud API Gateway をブラウザから叩けなくて悲しい(悲しみのあまり仕事が捗らなくなる)
- after: OpenAPI仕様とAPIバックエンドいじってCORS有効化できたことで、Webページ上からドメイン(正確にはオリジン)違っててもAPI叩けるようになって嬉しい(テンションが上がって仕事が捗るようになる)
著者プロフィール
faable01です。かつては創作仲間と小説を書いたり、製菓業界で楽しくやっていたはずが、紆余曲折を経て、サーバーレス技術を触るのが好きなITエンジニアになっていました。AWSのIaC兼サーバレス爆速開発ツール 「SST」 が好きです。個人ブログでもたまに記事を書いています。
それから、業務日報SaaS 「RevisNote」 を運営しています。リッチテキストでの日報と、短文SNS感のある分報を書けるのが特徴で、組織に所属する人数での従量課金制です。アカウント開設後すぐ使えて、無料プランもあるから、気軽にお試しください。