[備忘録]TypeScriptでAPIから画像を取得~react-native/Imageで出力まで
やろうとしたこと
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
個人的に沼った点
自分は動作確認で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
ヘッダー設定というよりかは 戻り型設定とかの方がニュアンスいい気もする
base64 の場合、 実際の容量の 1/3 増えるので Blob -> objectUrl の変換でも良さそう
url が不要になったら
URL.revokeObjectUrl()
が必要ではありますが。