SnowGuest

SnowGuest

这里是 SnowGuest的博客站点,只会记录一些有意思的日常事
bilibili
github

正しいリクエストの封装方法と優雅なビジネスの埋め込み (1)

今まで様々なリクエストのラッピングと使用を見てきましたが、例外なく多くは無効なラッピングであったり、使用者をより複雑にしてしまうものでした。そこで、ラッピングの一般的な実践について書こうと思い、本記事が生まれました。

以下の例には Axios Fetch UseFetch (Nuxt3) が含まれます。

DX 体験#

チーム内の主導として、DX 体験(開発者体験)に合ったラッピングを行うことは非常に重要です。結局、あなたがラッピングしたものは他の人によって大量に使用され、プロジェクト全体のアプリケーションシーンを考慮する必要があります。DX 体験は最優先にすべきです。

そのため、以下のポイントを挙げました...

  1. 優雅な API 呼び出し
  2. ビジネスロジックとの切り分け
  3. カスタム例外処理の能力
  4. デフォルトの動作を阻止することを許可
  5. 生データを取得する能力をサポート
  6. 新しいインターフェースの負担を軽減

これらのポイントについて、順に分析していきます。

優雅な API 呼び出し#

まずはケースを見てみましょう。

/* 1. フォルダ分類のAPI */ 
import { getList } from "@/api/demo";

/* 2. 別名で全APIを統一してインポート */ 
import api from "api";

async function preload(){
  try {
    /* 1のインポート方式で呼び出し */ 
    const result = await getList();
    
    /* 2のインポート方式で呼び出し */ 
    const result = await api.demo.getList();

    // 応答が成功コードであればここに到達します

    
  } catch (error){
    // すべてのビジネスコードの例外とhttpStatusの例外はここに到達します。自分で例外を処理する必要がある場合
    if(error instanceof Error){
        // トースト....
    }
  } 
}

上記のケースでは、2 つのインポート方式と使用例を区別しました。次に、一般的なビジネス、例えば ページネーション について詳しく掘り下げます。

 const result = await list();
 type C = () => Promise<boolean>
 /**
 resultのデータ構造はページネーションを例に
 result = {
  pageNum:number
  pageSize:number
  list:Map<number,T>
  to:C // 指定ページへ
  next:C // 次のページ
  back:C // ホームページに戻る
  status:"loading" | "end"
 }
 */ 

このようにして、他のビジネス担当者が API に費やす時間と労力を減らし、不要な変数を定義することなく、必要なのは API を呼び出すことだけです。

次に、どのようにこのようなカスタム Hook を設計するかについて説明します。

API の流れ#

上記のロジックに基づいて、具体的な呼び出しの流れを簡単に導き出すことができます。

ページ ---> ビジネス API ---> 根リクエスト
根リクエスト --> httpStatus の処理 -> ビジネスコードの処理 ->
--> ページネーションのラッピング -> 戻す
--> ラッピングしない -> 戻す

封装を開始します。Axios を例に#

// request.ts

import axios from "axios"
import type { AxiosRequestConfig } from "axios"

/* グローバルaxiosインスタンスを作成 */ 
const axiosiInstance =  axios.create({
  baseUrl:"https://api.example.com/",
  timeOut:6000
});

/* バックエンドの共通応答体 */ 
export interface Request<T=null>{
  code: number;
  data: T;
  success: boolean;
  msg: string | null
}

/* カスタムErrorCodeをサポート */ 
export interface ErrorInstall {
    [key:string|number]: string;
}
const StatusCode = 200;
export default async function request<R=null>(conf:AxiosRequestConfig,err:ErrorInstall,dialog=true){

    
    /* 通常のビジネスロジックでは、さまざまなカスタムヘッダーを持つことが常に求められます */ 
    /* ここでconfのクローンを作成 */ 
    const config: AxiosRequestConfig = {
        // headersを上に置くことでconfigにheadersのデフォルト値を持たせることができます
        // 下の...confにheadersがあればデフォルト値を上書きしてheadersを常に存在させることができます
        headers:{},
        ...conf,
    }
    /* ここで共通ヘッダーを追加します。例えばトークン */ 
    // TODO ....
    const {status,data,statusText} = await axiosiInstance<Request<R>>(config);
    let error:Error;
  
    /* httpStatusの処理 */ 
    if(status !== StatusCode) error = new Error(statusText);
    /* ビジネスコードがあればhttpStatusを上書き */ 
    if (data && data.code !== StatusCode && err[data.code]) {
      error = new Error(err[data.code]); 
    }
    /* errorが存在する場合は共通のエラーポップアップをトリガー */ 
    if(error instanceof Error){ 
      if(dialog) showFailToast(error.message);
      throw { error, data };
    }
    // 応答
    return data;
}

これで、根リクエストのラッピングが完了しました。

次の章では、応答内容のページネーションラッピング処理について説明します。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。