fake-gcs-serverでは署名付きURLを発行しなくてよい

## あらすじ

GoogleのIdentity PlatformやCloud Storageを使ったアプリ開発をしていると、複数のエンジニア間でデータの衝突や相違が起きることがある。例えばデータベースには登録されているが、Cloud Storageには登録されていないとかその逆とか、名前が重複しちゃったとか。

こういう場合ローカルの開発環境でエミュレーターを使うという方法があるのだが、Identity PlatformやCloud Storageは公式のエミュレーターが存在しない。
なので大抵の場合はFirebase Emulatorを使うことになる。
これについては `firebase emulator docker` でググればそれなりに情報量の多いブログや記事が出てくるので参考にすればなんとかなる。
参照してもらうとわかるのだが、実はそんなにすんなり導入できるわけではなく、それなりにDockerの知識が要求される。

ということで、他にもう少し楽な選択肢はないかと検索すると、 **[fake-gcs-server](https://github.com/fsouza/fake-gcs-server)** というものが出てくる。今回はこの謎いエミュレーターでCloud Storageをエミュレートしてみる。

## 導入

以下の記事を参考に。

https://y-ohgi.blog/entry/2023/01/26/GCS_%E3%82%92%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%81%AEdocker-compose%E3%81%A7%E3%82%A8%E3%83%9F%E3%83%A5%E3%83%AC%E3%83%BC%E3%83%88%E3%81%99%E3%82%8B

https://qiita.com/he23inw3/items/02ad426c4b0fb817498b

```:docker-compose.yml
・
・
(その他の記述）
・
・
cloud-storage:
    container_name: local-cloud-storage
    image: fsouza/fake-gcs-server:latest
    tty: true
    ports:
      - "4443:4443"
    volumes:
      - ./tmp/cloud-storage/data:/data
      - ./tmp/cloud-storage/storage:/storage
    command: -scheme http -public-host ${URL:-localhost}:4443
```

非常に簡単ではあるが、コマンド引数とvolumesの説明をする。

* `- ./tmp/cloud-storage/data:/data`
例えば`./tmp/cloudstorage/data`の下に `test` というディレクトリを作るとそれがバケットになる。 

* `- ./tmp/cloud-storage/storage:/storage`
アプリからファイルをアップロードするとこのstorageにファイルが溜まっていく。

* `-scheme http`
httpでのアクセスを許可する

* `-public-host ${URL:-localhost}:4443`
localhost:4443 をホストに設定する

これらを総合すると、アップロードしたファイル（例えばtest.txt）には以下のURLでアクセスするとブラウザで表示orダウンロードできる。

`http:localhost:4443/バケット名/test.txt`

## 署名付きURLの発行

ようやく本題。公式ドキュメントには以下のように記述されている。

> Using with signed URLs
It is possible to use fake-gcs-server with signed URLs, although with a few caveats:
> 
> * No validation is made on the query params (signature, expiration ...)
> * You need your client to modify the URL before passing it around (replace storage.googleapis.com with something that points to fake-gcs-server)
> * You need to configure fake-gcs-server to accept this local URL (by setting -public-host)

正直わけがわからないので実際に試した結果何が言いたいのかを超訳すると **署名付きURLはURLに署名するだけなんでアプリの機能じゃない。`-public-host` に指定したURLで直接ファイルにアクセスしてちょ** である。

## TypeScript + Node.jsでの実装例

つまりこういうこと。

```TypeScript:client.ts
import { Storage } from '@google-cloud/storage';

import type { GetSignedUrlConfig } from '@google-cloud/storage';

// NODE_ENVがproduction以外の場合はfake-gcs-serverを使用する
const storage = process.env.NODE_ENV !== 'production'
  ? new Storage({
    apiEndpoint: 'http://localhost:4443',
    projectId: 'test',
  })
  : new Storage({
    keyFilename: rocess.env.GOOGLE_APPLICATION_CREDENTIALS
    projectId: process.env.GCP_PROJECT_ID,
  });

const bucketName = process.env.GCS_BUCKET_NAME || 'your-bucket-name';

const getSignedUrl = async (filePath: string): Promise<string> => {
  try {
    // NODE_ENVがproduction以外の場合はローカルのURLをそのまま返す
    if (process.env.NODE_ENV !== 'production') {
      const signedUrl = `http://localhost:4443/${bucketName}/${filePath}`;
      return signedUrl;
    }
    const [signedUrl] = await storage
      .bucket(bucketName)
      .file(fileName)
      .getSignedUrl();
    return signedUrl;
  }
  catch (error) {
    throw error;
  }
};
```

ドキュメントにも明確には載ってないけどこれでOKらしい。
ちなみに無理に署名付きURLを発行しようとすると以下のエラーが発生してしまう。

```
 Error: Could not load the default credentials. Browse to https://cloud.google.com/docs/authentication/getting-started for more information.
 ```