GCPのAPI GatewayでCORSを有効にする方法を解説するよ

## 経緯（時系列順）
1. GCPのAPI Gatewayでお手軽簡単にPublic APIを立てようとしたら、[CORS（オリジン間リソース共有）](https://developer.mozilla.org/ja/docs/Web/HTTP/CORS) が無効になっていて、ブラウザ上のJavaScriptからFetchできなかった

2. 悲しい

3. 何かCORSを有効化する方法あるはずだから調べてやってみよう

## 結論

下記を全部やれば、できるようになるよ！

1. Google Cloud API GatewayのAPI定義（OpenAPI仕様）で、CORSサポートを有効にする

2. 同上のAPI定義で、[CORSの Preflight request](https://developer.mozilla.org/ja/docs/Glossary/Preflight_request) のパスを定義する

3. 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`」とする
* API Gateway
    * URL「`/greet`」 で上記のCloud Functionsをコールする

### Google Cloud API GatewayのAPI定義（OpenAPI仕様）

#### CORS対応前

```yaml
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対応後

```yaml
# 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対応前

```javascript
exports.helloWorld = (req, res) => {
  const message = req.query.message || req.body.message || 'Hello World!';
  res.status(200).send(message);
};
```

#### CORS対応後

```javascript
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ページのどこかにたとえばこんな感じでコールできる処理書いてみると...

```html
<!-- 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」** が好きです。個人ブログでもたまに記事を書いています。

https://signote.link

それから、業務日報SaaS **「RevisNote」** を運営しています。リッチテキストでの日報と、短文SNS感のある分報を書けるのが特徴で、組織に所属する人数での従量課金制です。アカウント開設後すぐ使えて、無料プランもあるから、気軽にお試しください。

https://revisnote.com?1710501811980