5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

TS, JS: fetchをミスなく快適に書く方法(fetcha!)

Last updated at Posted at 2023-07-04

通常のfetchの例

コメントで問題点を記載

fetch("https://example.com/api", {
  method: "POS", // 1. エディタ上でエラーにならない
  headers: {
    "Content-Typ": "application/jso", // 2. エディタ上でエラーにならない
    Authorization: `Bearer ${"foo"}`,
  },
  credentials: "include",
  mode: "cors",
  body: JSON.stringify({ name: "bar" }), // 3. JSON.stringify が必要
})
  .then((resp) => {
    if (resp.ok) return resp.json();

    // 4. then なのにエラー処理が入る
    switch (resp.status) {
      case 500:
        location.href = "/500.html";
        return;
      case 404:
        location.href = "/404.html";
        return;
      case 401:
        location.href = "/login.html";
        return;
      default:
        alert(resp.statusText);
    }
  })
  .then(({ id }: { id: number }) => console.log(id))
  .catch((e) => alert(e.message));

解決

コード補完が効くので、ミスなく快適に

fetcha("https://example.com/api")
  .contentType("application/json")
  .header("Authrization", `Bearer ${"foo"}`)
  .credentials("include")
  .mode("cors")
  .post({ name: "bar" })
  .then((resp) => resp.toJson<{ id: number }>())
  .then(({id}) => console.log(id))
  .catch((e: FetchaError) => {
    switch (e.status) {
      case 500:
        location.href = "/500.html";
        return;
      case 404:
        location.href = "/404.html";
        return;
      case 401:
        location.href = "/login.html";
        return;
      default:
        alert(e.message);
    }
  });

利用方法

npm i @co-labo-hub/fetcha
import { fetcha, FetchaError } from '@co-labo-hub/fetcha';

bodyの渡し方

  • Content-Type が application/json で始まっている場合、
    かつ body が objectの場合、JSON.stringify が実行されます
fetcha('https://example.com/api')
    .contentType('application/json')
    .post({name: 'foo'})
const form = new URLSearchParams();
form.set("name", "foo");
fetcha('https://example.com/api')
    .contentType('application/json')  // 一致しないため無視される
    .post(form)

ヘッダの指定方法

Content-Type は contentType メソッドで設定できますが、引数は空文字列か application/json の2択です。
参考:https://m0rter.anyfrog.net/2019/56/
空文字列の場合はヘッダから Content-Type を削除します。
他の Content-Type を設定する場合は header メソッドが使えます。

fetcha('https://example.com/api')
    .header('Content-Type', 'text/plain')

メソッドの指定方法

fetch実行は下記メソッドが利用できます。
{method: string} でのタイプミスが避けられます。
参考:https://www.ohitori.fun/entry/how-to-fix-a-bug-in-the-fetch_api-patch-request

.get()
.head()
.delete()
.post(body?)
.patch(body?)
.put(body?)

//または
.fetch(method: "GET" | "POST" | "PATCH" | "PUT" | "HEAD" | "DELETE" = "GET")

JSON返値の型指定

// 標準のresp.json()の場合
const data = await fetcha('https://example.com/api')
    .get()
    .then(resp => resp.json() as Promise<{id: number}>)

// resp.toJson<T>()の場合
const data = await fetcha('https://example.com/api')
    .get()
    .then(resp => resp.toJson<{id: number}>());

URLの指定方法

柔軟に対応可能

//1
fetcha('https://example.com/api')
//2
fetcha().url('https://example.com/api')
//3
fetcha(new URL('/api', 'https://example.com/'))
//4
fetcha('/api')
    .origin('https://example.com/')
//5
fetcha()
    .origin('https://example.com/')
    .url('/api')

エラー処理

エラーオブジェクトにレスポンスの各種プロパティが同名で含まれており
HTTPステータスコードを見て処理の振り分けなどが可能

.post()
.then(/* ... */)
.catch((e: FetchaError) => {
    switch (e.status) {
      case 500:
        location.href = "/500.html";
        return;
      case 404:
        location.href = "/404.html";
        return;
      case 401:
        location.href = "/login.html";
        return;
      default:
        alert(e.statusText);
    }
})

詳細

サンプル
https://github.com/co-labo-hub/fetcha/blob/main/src/example.ts

最後に

fetchは実行前の組み立てが面倒ですが
エディタ上でメソッドの候補が表示され
選択していくことでメソッドチェーンが組み上がるのは気持ちいいです。

また、fetchは実行後のエラー処理が汚くなりがちですが、
catch内で必要な情報が揃った状態で処理が書けるので
クリーンなコードになるように思います。

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?