Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ファイルアップロードAPIにmultipartFileValidatorを指定するとbody取得時エラー #300

Open
1 of 3 tasks
deton opened this issue Nov 11, 2023 · 0 comments

Comments

@deton
Copy link

deton commented Nov 11, 2023

Description

現象

multipart/form-dataのPOSTリクエスト内のファイルに対するvalidatorとして、
$relay.tsに生成されるmultipartFileValidator()を指定すると、
ファイル内容取得時(toBuffer())にエラーが発生します。
(validators指定無しの時はエラーなし)。

Fastifyのログ出力を有効にしてInternal Server Errorの内容を確認すると、
body.XXXfile.toBuffer()実行時にエラーが発生しています。

TypeError: this.file is not async iterable
    at Object.toBuffer (/work/test-frourio-app/server/node_modules/@fastify/multipart/index.js:463:42)
    at Object.toBuffer (/work/test-frourio-app/server/node_modules/zod/lib/types.js:2703:46)
    at async changeIcon (/work/test-frourio-app/server/index.js:280:5)
    at async handler (/work/test-frourio-app/server/index.js:311:13)
    at async Object.<anonymous> (/work/test-frourio-app/server/index.js:394:16)

原因

おそらくmultipartFileValidator()に無い_bufプロパティが、zodにより削除(strip)されるため。

_bufがあれば、それがtoBuffer()で返されます。
https://github.com/fastify/fastify-multipart/blob/v7.7.3/index.js#L463

(console.log(body)をformatMultipartData()とhandlerに入れて違いをみると、
_bufが無くなっています)

回避方法

使い方の問題かもしれないと思いつつ、とりあえず、2番目の方法で回避しています。

  • 削除されないようにpassthrough()を追加。
    ただし、npm run typecheckによるtsc --noEmit実行でエラーが5個出るようになる。
    multipartFileValidator().passthrough()

    typecheckエラー内容
    server/$server.ts(286,21): error TS2345: Argument of type 'ServerMethodHandler<{ reqHeaders: AuthHeader; resBody: UserInfo; }, AdditionalRequest>' is not assignable to parameter of type 'ServerHandler<any, any>'.
      Type 'ServerHandlerPromise<{ reqHeaders: AuthHeader; resBody: UserInfo; }, AdditionalRequest>' is not assignable to type 'ServerHandler<any, any>'.
        Type 'Promise<ServerResponse<{ reqHeaders: AuthHeader; resBody: UserInfo; }>>' is not assignable to type 'ServerResponse<any>'.
    server/$server.ts(292,58): error TS2339: Property 'validators' does not exist on type 'ServerMethodHandler<{ reqHeaders: AuthHeader; reqFormat: FormData; reqBody: { icon: File | ReadStream; }; resBody: UserInfo; }, AdditionalRequest>'.
      Property 'validators' does not exist on type 'ServerHandler<{ reqHeaders: AuthHeader; reqFormat: FormData; reqBody: { icon: File | ReadStream; }; resBody: UserInfo; }, AdditionalRequest>'.
    server/$server.ts(297,50): error TS2339: Property 'handler' does not exist on type 'ServerMethodHandler<{ reqHeaders: AuthHeader; reqFormat: FormData; reqBody: { icon: File | ReadStream; }; resBody: UserInfo; }, AdditionalRequest>'.
      Property 'handler' does not exist on type 'ServerHandler<{ reqHeaders: AuthHeader; reqFormat: FormData; reqBody: { icon: File | ReadStream; }; resBody: UserInfo; }, AdditionalRequest>'.
    server/api/user/controller.ts(9,7): error TS2322: Type 'ZodObject<{ icon: any; }, "strip", ZodTypeAny, { [x: string]: any; icon?: any; }, { [x: string]: any; icon?: any; }>' is not assignable to type 'ZodType<{ icon: MultipartFile; }, ZodTypeDef, { icon: MultipartFile; }>'.
      Types of property '_type' are incompatible.
        Type '{ [x: string]: any; icon?: any; }' is not assignable to type '{ icon: MultipartFile; }'.
          Property 'icon' is optional in type '{ [x: string]: any; icon?: any; }' but required in type '{ icon: MultipartFile; }'.
    server/api/user/controller.ts(10,40): error TS2339: Property 'passthrough' does not exist on type 'ZodType<MultipartFile, ZodTypeDef, MultipartFile>'.
    
  • _bufプロパティを追加。
    ただし、同様にtypecheckでエラーが5個出るようになる。
    multipartFileValidator().extend({_buf: z.instanceof(Buffer)})

  • multipartFileValidator()を使わずに同様の定義を行う。

  • (validators指定無しにする)

再現手順

  1. create-frourio-app
npx create-frourio-app --answers '{"dir":"test-frourio-app","server":"fastify","client":"next","building":"static","aspida":"axios","reactHooks":"swr","daemon":"none","orm":"none","testing":"jest","pm":"npm","ci":"none","deployServer":"none","deployBranch":"main","staticHosting":"none"}'
  1. frourioを更新。npm i frourio@1 --prefix server
  2. validatorとしてmultipartFileValidatorを指定。
    (ここまでの手順を行った段階のもの: https://github.com/deton/test-frourio-app )
--- a/server/api/user/controller.ts
+++ b/server/api/user/controller.ts
@@ -1,10 +1,18 @@
-import { defineController } from './$relay'
+import { defineController, multipartFileValidator } from './$relay'
 import { getUserInfoById, changeIcon } from '$/service/user'
+import { z } from 'zod';
 
 export default defineController(() => ({
   get: ({ user }) => ({ status: 200, body: getUserInfoById(user.id) }),
-  post: async ({ user, body }) => ({
-    status: 201,
-    body: await changeIcon(user.id, body.icon)
-  })
+  post: {
+    validators: {
+      body: z.object({
+        icon: multipartFileValidator()
+      })
+    },
+    handler: async ({ user, body }) => ({
+      status: 201,
+      body: await changeIcon(user.id, body.icon)
+    })
+  }
 }))
  1. サーバを起動してnpm run dev、ブラウザからhttp://localhost:8000を開いて、
    右上LOGINボタンを押して、idpassと入力してログインして、
    参照ボタンを押して、アップロードするファイルを選択。
  2. HTTP 500 が返ってくる。

Environment

  • Package version:
    v1.0.0
  • OS:
    • Linux
    • Windows
    • macOS
  • Node.js version:
    v18.17.1
  • npm version:
    9.6.7

Additional context

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant