🖼️

[備忘録]TypeScriptでAPIから画像を取得~react-native/Imageで出力まで

2025/03/10に公開1

やろうとしたこと

Spring BootのAPIからバイト配列のデータを取得し、FE側でbase64へ変換し出力する。

環境

  • BE: Java, Spring Boot
  • FE: TypeScript, React Native(0.71.19)
    • axios
    • js-base64

ポイント

axiosのヘッダー設定を'arraybuffer'にする

通常の場合jsonに設定されているが、画像を受け取る通信に関しては事前にresponseTypeを設定する必要があるらしい。

自分の場合、axios.create()でインスタンスを作成し、それをプロジェクト内で使いまわしていたので、作成されたインスタンスにあとから設定する形で実装した。

インスタンスの設定(読まなくてよい)

function createAxiosInstance() {
  const customAxios = axios.create({
    baseURL: `https://example.com/hoge/`,
    timeout: 45000,
    headers: {
      Accept: '*/*',
      'Content-Type': 'application/json',
    },
  });
  customAxios.interceptors.request.use((request) => {
    if (request.headers) {
      request.headers['AUTHENTICATION-ID'] = "authID";
      request.headers['DEVICE-TOKEN-ID'] = String("deviceTokenID");
    }
    return request;
  });
  return customAxios;
}

export const AXIOS = createAxiosInstance();

↑のように定義されているものを使っていたので

AXIOS.get<ArrayBuffer>(END_POINT_URI, {
    responseType: 'arraybuffer', // ここで設定
});

これでaxios側の設定はok

https://axios-http.com/ja/docs/req_config

個人的に沼った点

自分は動作確認でconsole.logなどでresponseの中身を表示したりすることが多いのですが、今回受け取ったレスポンスをログで確認したところ、response.dataにはからオブジェクト的な{}としか表示されておらず、もしかして受け取れていない?と思い、中身が存在していないと勘違いをしていました。

ArrayBufferはコンソールで適切に表示されないことがあるらしく、単に容量が表示されたり自分のように空オブジェクトのように見えるようです。

この場合、ちゃんとデータが返ってきているか確認する方法ですが、バイナリデータのサイズを確認するとよかったです。

console.log(response.data.byteLength)

Base64に変換

ArrayBufferだとImageコンポーネントで使用できないようでしたので、Base64へ変換します。

import { btoa } from 'js-base64';

const createBase64 = (arrayBuffer: ArrayBuffer) => {
  const buffer = arrayBuffer // APIで取得したデータ
  const bytes = new Uint8Array(buffer);

  let binary = '';
  for (let i = 0; i < bytes.byteLength; i++) {
    binary += String.fromCharCode(bytes[i]);
  }
  const base64Data = btoa(binary);

  return base64Data;
}

Imageコンポーネントで表示

APIで画像データを取得しBase64へ変換した後はreduxなりなんなりにデータを保持しておいて、そのデータをreact-nativeで提供されているImageコンポーネントに渡して使用します。

<Image 
  source={{ uri: `data:image/png;base64,${base64Data}` }}  // base64データをわたす
  style={{ width: 48, height: 48, borderRadius: 48 }}
/>

バイナリデータ取り扱うことがいままであまりなかったので手こずってしまった。
最終的にclaudeくんに助けてもらって2時間くらいで解決。
AI、強い(確信)

エルデンリングのマレニアのほうが時間かかってんじゃんね。

Discussion

junerjuner

axiosのヘッダー設定を'arraybuffer'にする

ヘッダー設定というよりかは 戻り型設定とかの方がニュアンスいい気もする


Base64に変換

base64 の場合、 実際の容量の 1/3 増えるので Blob -> objectUrl の変換でも良さそう

https://developer.mozilla.org/ja/docs/Glossary/Base64#符号化によるサイズの増加

const blob = new Blob([arrayBuffer], {type:'image/png'});
const url = URL.createObjectURL(blob);

https://developer.mozilla.org/ja/docs/Web/API/Blob/Blob

https://developer.mozilla.org/ja/docs/Web/API/URL/createObjectURL_static

url が不要になったら URL.revokeObjectUrl() が必要ではありますが。

https://developer.mozilla.org/ja/docs/Web/API/URL/revokeObjectURL_static