Back

Nuxt3で$fetchにbodyいれてGETするとエラーになる挙動をみる

Nuxt3で$fetchにbodyいれてGETするとエラーになる挙動をみる

こんにちは、合同会社Stegの@keigoです。 今回は、Nuxt3にて、$fetchuseFetchにてAPIを叩く時、bodyいれてGETするとエラーになる件について書いていきます。 例えば$fetchでbody含むgetしようとすると、以下のようなエラーメッセージになるかと思います。

Uncaught (in promise) FetchError: Failed to execute 'fetch' on 'Window': Request with GET/HEAD method cannot have body. (/api/hoge)

つまり、GETではbody指定できないよ〜ということですね。

解決策

クエリパラメータなどにするか、POSTにしましょう。 取得が目的なら、getのままでクエリパラメータがよきです。

実装をみていく

cURLやpostmanなどでGET指定でbodyを含めたことがあったので、あれ?だめなんだ?になりました。

気になったので実装を見にいきました。

useFetch

Nuxt3でのuseFetchは、useAsyncData$fetchをwrapしたものです。

$fetchって?

nuxtのコードを読みに行くと、

import { $fetch } from 'ofetch'

という記述がありました。つまり、$fetchというのは、unjs/ofetchっぽいですね。

今回の記事でのGETでbodyが対応していないというのは、ofetchのほうに書いてありそうです。

unjs/ofetchの実装みる

fetch.tsにて、以下のようなコードがありました。(記事執筆時点)

if (
  context.options.body &&
  isPayloadMethod(context.options.method) &&
  isJSONSerializable(context.options.body)
) {
  // Automatically JSON stringify request bodies, when not already a string.
  context.options.body =
    typeof context.options.body === "string"
      ? context.options.body
      : JSON.stringify(context.options.body);

  // Set Content-Type and Accept headers to application/json by default
  // for JSON serializable request bodies.
  context.options.headers = new Headers(context.options.headers);
  if (!context.options.headers.has("content-type")) {
    context.options.headers.set("content-type", "application/json");
  }
  if (!context.options.headers.has("accept")) {
    context.options.headers.set("accept", "application/json");
  }
}

context.options.bodyでbodyがありつつ、isPayloadMethod(context.options.method)という関数がtrueを返すかどうかが今回のポイントになりそうです。

isPayloadMethodを見に行くと、

const payloadMethods = new Set(
  Object.freeze(["PATCH", "POST", "PUT", "DELETE"])
);
export function isPayloadMethod(method = "GET") {
  return payloadMethods.has(method.toUpperCase());
}

こうなってました。完全にGETが省かれてますね。

ここらへんの実装から、$fetchでGETにbodyいれるとエラー返すんだな〜と理解できました。