Help us understand the problem. What is going on with this article?

Cloud Functions for FirebaseでRequest has invalid method. GETかBad Request, INVALID_ARGUMENTならこれかも?

Overview

私はFunctionsからBigQueryに問い合わせて、結果をただ返したかっただけだった。
しかし、"message:"Bad Request", status:"INVALID_ARGUMENT"の闇に遭難することになる。
今回はその中で、FunctionsのログにRequest has invalid method. GETと出るケースを扱う。
Bad Requestは様々な理由が考えられるため、Functionsのログをみて該当するケースか確認してほしい。
(巨大なオブジェクトが出力されているため冒頭のエラーを見るのはなかなか大変だが)

Target reader

Request has invalid method. GETが解決できないユーザー

Body

いきなり結論

結論的には似たようなケースを扱ったことがあるのでそこから抜粋する。
https://qiita.com/qrusadorz/items/40234ac0b5c5c2315cad

FirebaseのCloud Functionsには2つの関数があります。
1. functions.https.onCall
2. functions.https.onRequest

1はSDKが用意されているAndroid,iOS,Javascriptから呼び出されるタイプ。
https://firebase.google.com/docs/functions/callable?hl=ja
2はSDKがない場合、汎用のWebAPIとして作成するタイプ。
https://firebase.google.com/docs/functions/http-events?hl=ja

functions.https.onCallで作っている場合、汎用のWebAPIとは異なりhttps.onCall のプロトコルの仕様に従わなくてはならない。
どういう縛りがあるのか、公式ドキュメントから仕様を抜粋する。
https://firebase.google.com/docs/functions/callable-reference?hl=ja

リクエストの形式: ヘッダー
呼び出し可能なトリガー エンドポイントへの HTTP リクエストは、次のヘッダーが含まれる POST にする必要があります。

必須: Content-Type: application/json
オプション: Authorization: Bearer
オプション: Firebase-Instance-ID-Token:

その他のヘッダーが含まれる場合は、下記のレスポンスに関するドキュメントで説明されているように、リクエストは拒否されます。

まずヘッダーにapplication/jsonが必須。
日本語がおかしいが、リクエストはGETではなくPOSTでなくてはならない。

リクエスト本文
HTTP リクエストの本文は、次のいずれかのフィールドが含まれる JSON オブジェクトにする必要があります。

必須: data - 関数に渡される引数です。これには任意の有効な JSON 値を使用できます。これは、以下で説明するシリアル化形式に従って、>JavaScript のネイティブ型に自動的にデコードされます。
リクエストに他のフィールドが存在する場合、バックエンドはそのリクエストの形式を不正とみなし、リクエストは拒否されます。

そして本体にはdataフィールドが必須。

私がどうやってAPIにアクセスしていたか、確認しよう。
serveコマンドでローカルサーバーを立てる。
準備ができると、以下のようなログがVSCodeのターミナルに出力される。(Function名はsearchItems)

functions[searchItems]: http function initialized (http://localhost:5000/<project-Id>/asia-northeast1/searchItems).

ここでツールチップの通り、Ctrl+クリックで()n内のURLにアクセスしていた。
つまりhttps.onCall のプロトコルの仕様を完全に無視したわけだ。
それは1時間たっても解決するはずないですわ:joy:

POSTでリクエストを送るため、POSTMAN…、ここはVSCodeでお手軽なやつを探して、@toshi0607さんの紹介されているREST Clientを採用。
https://qiita.com/toshi0607/items/c4440d3fbfa72eac840c

request.httpというファイルを作って、下記のリクエストを作成。
<projectId>は自身のものを利用すること。
Content-TypeとBodyの間に1行の空行は必須。

request.http
POST https://asia-northeast1-<projectId>.cloudfunctions.net/searchItems
Content-Type: application/json

{
    "data": {}
}

Send Requestボタンをクリックすると正常に応答が来る。
めでたくBigQueryよりデータが取れている。

response
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
(中略)

{
  "result": [
    {
      "id": 1,
      "text": "item1",
      "timestamp": 1
    },
    {
      "id": 2,
      "text": "item2",
      "timestamp": 2
    }
  ]
}

Conclusion

VSCodeの甘い誘いにより、泥沼に引き込まれた話でした。
functions.https.onCallはクライアントからコールする際は便利ですが、WebAPIとして利用する場合には隠蔽されている部分に準拠する必要があるので注意しましょう。
今回は認証を使っていないため軽傷でしたが、認証が必須のFunctionではAuthorizationにログイン後にuserオブジェクトが持つトークンが必要になります。
トークンは1時間で無効になるおまけ付きなので、REST Clientからコールするよりアプリからコールすることを検討したほうがいいでしょう。
(アプリでは自動的にトークンの期限が延長されるため、期限切れの心配が不要です)

qrusadorz
就業先では大規模サイト向けにAzure、プライベートでは中規模サイト向けにGCP(with Firebase)を運用中。フルスタックエンジニアとして、企画からマネタイズまで全工程に携わる。10年後にはサイトの収益のみで生活するセミリタイヤに向けて邁進中。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした