めちゃくちゃハマってしまった。解決したので残しておく
前提条件
- Nuxt .. v3.0.0-rc.6
- nitropack .. v0.4.12
- h3 .. v0.7.13
- ohmyfetch .. v0.4.18
# 結論
以下のようにかけばOKだった
server/api/image/[imageId].get.ts
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 側の型定義を見てみると,
ohmyfetch:v0.4.18
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 するケースが想定されていなかった