RXJSを使ったHTTPデータのマッピング


フロントエンドの開発では、何らかのバックエンドリソースからデータを取得するAPIリクエストを作成します.しかし、いくつかのバックエンドは、あまりにも多くのデータを送信したり、十分なデータを返さないように設定されています.
我々が反応プログラミングとRXJSについてすでに知っているものを結合するとき、我々はRXJSが我々に提供するいくつかの役に立つオペレーターを使用して非常にエレガントな方法でこれらの状況を扱うことができます.
この記事では、両方のシナリオを扱い、特に4つの演算子を見ていきます.map , mergeMap , concatMap and switchMap . また、いくつかのリンクを提供しますStackBlitz 例これらのライブを見ることができます.
楽しみのために、我々はStar Wars API データを取得するAngular HTTPライブラリとしての我々のフロントエンドフレームワークとして、ボックスから無効な結合があります.

データの扱い過ぎ(第1回)
を、シナリオを設定しましょう.いくつかの詳細を知りたいLuke Skywalker 彼の名前、誕生年、身長、体重、目の色など.
角で、HTTPリクエストを作るだけでこれを行うことができます.
this.http.get("https://swapi.dev/api/people/1")
    .subscribe(response => console.log(response));
我々がこれをするならば、我々は我々が必要とする情報を取り戻します、しかし、我々はAPIエントリがつくられて、編集されたとき、ルークの種、彼の車両などのような必要がない多くの情報を取り戻します、現在、我々はそれらの詳細について気にかけません.
我々がRXJSのものを使うことができる方法を見ましょうmap 演算子は、必要なデータを返すだけです.
this.http.get("https://swapi.dev/api/people/1")
    .pipe(map(response => ({
        name: response.name,
        birthYear: response.birth_year,
        height: Number(response.height),
        weight: Number(response.mass),
        eyeColor: response.eye_color
    })))
    .subscribe(luke => console.log(luke))
上の例から見ると、レスポンスオブジェクトから必要な値を引くのは簡単です.

ノート
また、SnakeRankケースからCamelCaseに対する応答のフィールドのいくつかをマップする方法を見ることができます.これは、JavaScript Runningでのコンベンションのより多くのものです.また、いくつかの型を他の型に変換することもできます.これはあなたのフロントエンドCodeBaseのドメイン言語をそのまま維持するのに非常に役立つことができます.

生の例
あなたは、このコードを行動の上でチェックアウトすることができますlive example here Stackblitzについて自由にフォークし、それを再生してください.

データの扱い過ぎ(その2 )
あまりにも多くのデータを持つ別の一般的なユースケースは検索結果です.いくつかの回我々は検索結果の束から最初の結果を表示します.
新しいシナリオを設定しましょう.
最も適切な検索結果を示すタイプの検索を作成します.我々は、ユーザーが作るすべてのキーを押した後に検索結果を要求しますしかし、我々はまた、必要でない要求をしたくありません.したがって、ユーザータイプとして作成された任意の機内リクエストをキャンセルします.
このシナリオのために、我々は混合物を使用していますmap and switchMap 演算子
また、いくつかの無効な結合を提供するために、角度の反応形式モジュールを使用します.
このコードはとても簡単です.
this.searchResult$ = this.search.valueChanges.pipe(
    // We get the search term the user has typed
    // And use switchMap to cancel any inflight requests
    // then create a new request and switch to that
    // Observable stream
    switchMap(term =>
      this.http.get<any>(`https://swapi.dev/api/people/?search=${term}`)
    ),
    // Next we check that there is results, if so we pick the first one
    // If not we create an object to show there are no results
    map(response =>
      response.count > 0 ? response.results[0] : { name: "No results" }
    ),
    // We then map the full response data down to only the fields we 
    // care about.
    map(
      response =>
        ({
          name: response.name,
          birthYear: response.birth_year,
          height: Number(response.height),
          weight: Number(response.mass),
          eyeColor: response.eye_color
        } as PeopleData)
    )
);
それは角度とRXJSと熱心なタイプの検索を作成することは簡単です.
このライブの例を見ることができますhere on StackBlitz .

取り扱いが少ないデータ
私たちはRXJSでAPI応答であまりに多くのデータを扱う方法を見ました、しかし、我々があまりに少しのデータを持っているとき、どうですか?
我々は完全にスターウォーズAPIでこのシナリオを構築することができます.我々が我々が捜しているどんな映画が見えるかについて見たいと言いましょう.文字に対するAPI応答は、どんなフィルムが入っているかを含んでいますが、それは私たちに詳細を与えません.これはまた、フィルムの配列であるので、我々は彼らが現時点で現われるすべての映画の詳細を得たいかもしれません.
検索コードをどのように変換し、結果に関連するより多くのデータを取得し、データをレンダリングするために使用する最終的なオブジェクトにマップするかを確認しましょう.
this.searchResult$ = this.search.valueChanges.pipe(
    // Again we take the search term and map to a new api request
    switchMap(term =>
      this.http.get<any>(`https://swapi.dev/api/people/?search=${term}`)
    ),
    // Now we use mergeMap as we do not need cancellation
    mergeMap(response =>
        // We use from to iterate over each film for the character
        from(response.films).pipe(
            // We need to massage the url to be correct as SW API returns http rather 
            // than https in the character details
            map(
              (film: string) => `${film.substring(0, 4)}s${film.substring(4)}`
            ),
            // Now we use concatMap as this will force RxJS to wait for each request
            // to complete before starting the next one, ensuring we have all the 
            // data needed for each film
            concatMap((film: string) => this.http.get<any>(film)),
            // The film API also returns more data than we care about so we map it down
            // to only the fields we care about
            map(film => ({
              title: film.title,
              releaseDate: film.release_date
            })),
            // We then need to collect each of these API responses and map them back into
            // a single array of films
            reduce((films, film) => [...films, film], []),
            // Finally we then map the character data and the film data into one percise
            // object that we care about
            map(
              films =>
                ({
                  name: response.name,
                  birthYear: response.birth_year,
                  height: Number(response.height),
                  weight: Number(response.mass),
                  eyeColor: response.eye_color,
                  films
                } as PeopleData)
            )
        )
    )
);
私は非常にこのシナリオを達成するために正確にどのように理解するために上記のコードとコメントを読んでお勧めします.このパターンは非常に強力です.たとえば、ユーザーIDの配列を反復処理し、それらのIDに関連付けられたユーザーの詳細を取得する必要がある場合などです.
このライブ例もありますhere on StackBlitz あなたがそれを試してみることができます.

結論
これは、RXJSでHTTPリクエストから返されたデータをマッピングするための小さな導入ですが、API APIリクエストを含む複雑なデータマッピングを実行する必要がある場合は、これを参照ポイントとして使用できます.
このドットラボは、企業のデジタル変換の努力を実現支援に焦点を当てた現代のWebコンサルティングです.専門家の建築指導、訓練、またはコンサルティング、角度、Vue、Webコンポーネント、Graphql、ノード、バゼル、またはポリマー、訪問thisdotlabs.com .
このドットメディアは、すべての包括的で教育的なウェブを作成することに集中します.我々は最新のイベント、ポッドキャスト、および無料のコンテンツを介して近代的なWebの進歩と最新の状態に保つ.学ぶthisdot.co .