めちゃくちゃハマってしまった。解決したので残しておく
前提条件
- Nuxt .. v3.0.0-rc.6
- nitropack .. v0.4.12
- h3 .. v0.7.13
- ohmyfetch .. v0.4.18
# 結論
以下のようにかけばOKだった
import { send } from 'h3'
export default defineEventHandler(async (event) => {
const { imageId } = event.context['params']
const blob: Blob = await $fetch(`/external/api/images/${imageId}`, {
method: 'get',
responseType: 'blob'
})
await send(event, Buffer.from(Buffer.from(await blob.arrayBuffer())), blob.type)
})
勘所
$fetch は responseType によって返却する型が変わる
nuxt3 の server api にて、 $fetch は ohmyfetch のラップ関数となっている
nuxt によって型が上書きされてしまっているので、把握しづらかったが、
ohmyfetch 側の型定義を見てみると,
interface ResponseMap {
blob: Blob;
text: string;
arrayBuffer: ArrayBuffer;
}
declare type ResponseType = keyof ResponseMap | 'json';
declare type MappedType<R extends ResponseType, JsonType = any> = R extends keyof ResponseMap ? ResponseMap[R] : JsonType;
// ...
interface $Fetch {
<T = any, R extends ResponseType = 'json'>(request: FetchRequest, opts?: FetchOptions<R>): Promise<MappedType<R, T>>;
raw<T = any, R extends ResponseType = 'json'>(request: FetchRequest, opts?: FetchOptions<R>): Promise<FetchResponse<MappedType<R, T>>>;
create(defaults: FetchOptions): $Fetch;
}
となっており、
つまり、 responseType が blob, text, arrayBuffer なら、
それぞれ Blob, string, Arraybuffer が返却するデータの型になるのがわかる。
return せず send する
defineEventHandler の引数に指定した関数の返り値は、 nitro サーバ側で h3 モジュールの send を呼んでいる。
また、既に send 済みであれば、それをレスポンスデータとして扱ってくれる。
そのため、 レスポンスデータを return せずに、 直接 send すればよかった。
ちなみに、 nitro サーバのロジックを見た感じ、 text と json 以外のレスポンスデータを return するケースが想定されていなかった