💨

typescriptでいい感じにクエリパラメータを管理する

2022/09/01に公開

背景

fatFrontになりがちな部分をリファクタリングしている最中に、クエリパラーメータのフロントエンド管理で迷ったので暫定対応を備忘録として記録する。
あんまり真面目にやってこなかった部分なのでいずれより良い設計が分かったときに修正する。

課題

同じリソースをフェッチするが、ある画面ではリソースに対してすべてのクエリパラメータの適用を認めるけど、別の画面では一部のクエリパラメータを認めないときにどうするか?

できれば、、、

アクションごとに定義するコストをなるべく減らしたい。
リソースに対してどのようなクエリパラメータが使えるのかは1箇所で管理したい。

暫定対応

例えば、本というリソースに対して、新品・中古・ビンテージ、価格、著者名でフィルターできる時

types/BooksQueries.ts
interface StatusFilter {
  new?: boolean;
  secondHand?: boolean;
  vintage?: boolean;
}

type StatusFilterKeys = keyof StatusFilter;

interface PriceFilter {
  min?: number;
  max?: number;
}

type PriceFilterKeys = keyof PriceFilter;

interface AuthorFilter {
  authorName?: string;
}

type AuthorFilterKeys = keyof AuthorFilter;

type BooksQueries = StatusFilter & PriceFilter & AuthorFilter;

omit使うケース

pages/consumer.tsx
const getBooks = (
  queries?: BooksQueries
) => {
  axios.get("/api/books", {
    params: queries,
  });
};
pages/lp.tsx
const getBooks = (
  queries?: Omit<BooksQueries, PriceFilterKeys>
) => {
  axios.get("/api/books", {
    params: queries,
  });
};

pick使うケース

pages/consumer.tsx
const getBooks = (
  queries?: BooksQueries
) => {
  axios.get("/api/books", {
    params: queries,
  });
};
pages/lp.tsx
const getBooks = (
  queries?: Pick<BooksQueries, StatusFilterKeys | AuthorFilterKeys>
) => {
  axios.get("/api/books", {
    params: queries,
  });
};

設定可能なパラメータは一元管理しつつ、各フェッチの際に何が使えるのかを明示しておくことで、クライアントが迷いにくい形にはできたので一旦良しとした。

Discussion