react-dropzone、Express、Firebaseを使った画像のアップロード

```typescript:components/FileUpload.ts
const onDrop = (acceptedFiles: File[]) => {
     console.log(formData)
 }

return (
     <div>
         <DropZone  onDrop={onDrop}>
             {({getRootProps, isDragActive}) => (
                 <div {...getRootProps()}>
                     {isDragActive ? "Drop it like it's hot!" : 'Drag a file to upload!'}
                 </div>
             )}
         </DropZone>
     </div>
 )
```


react-dropzoneを使ってこんな感じに書いて、描画された部分に画像をドロップしてみると

```
lastModified: 1571463132902
lastModifiedDate: Sat Oct 19 2019 14:32:12 GMT+0900 (日本標準時) {}
name: "hoge.PNG"
path: "hoge.PNG"
size: 353348
type: "image/png"
webkitRelativePath: ""
```

こんな感じのFileっていう型の配列がもらえる。
んじゃあこのデータ配列そのままサーバ側にぶん投げて、サーバ側でfirebase storageにpath指定してあげりゃあ画像のアップロード実装できんじゃん！
って思ってたんだけど、見てわかる通りpathがfullpath(?)になってない。どうしよう...

最終的に、サーバ側に一時的に画像を保存して、そこで生成されたpathをfirebase側に指定してあげたらうまく行った。

そのために、まずはreact-dropzoneから受け取ったFile配列をFormDataとやらに変換して、それをPOSTデータとしてぶん投げた。

```typescript:components/FileUpload.ts
 const onDrop = (acceptedFiles: File[]) => {
     const formData = new FormData();
     acceptedFiles.forEach(file => {
         formData.append('Files', file)
     })
     dispatch(postFiles.request(formData))
 }
```

参考にさせていただいたサイト様様 → https://qiita.com/uryyyyyyy/items/9954205a620b6f3c1f24

んで、これをExpress側で受け取るんだけど、このデータはmultipart/form-dataというものらしく、普通にやったらうまく受け取れなかった。なんやそれ。知らんがな。

```typescript:app.ts

import multer from 'multer';

const upload = multer({ dest: './uploads/' });

app.post('/files', upload.fields([ { name: 'Files' } ]), postStorageController);
```
```typescript:controller/postStorageController.ts

export function postStorageController(req: Request, res: Response, next: NextFunction) {
    const files: Express.Multer.File[] = req.files['Files'];
```
こういう風に書いてあげると、filesの部分で以下のような感じで値がもらえる

```
[Object: null prototype] {
  Files:
   [ { fieldname: 'Files',
       originalname: 'hoge.PNG',
       encoding: '7bit',
       mimetype: 'image/png',
       destination: 'uploads/',
       filename: 'd18eb9674f13a81898e7c25bb0c3bda6',
       path: 'uploads/d18eb9674f13a81898e7c25bb0c3bda6',
       size: 353348 } ] }
```
参考にさせていただいたサイト様様 → https://qiita.com/uryyyyyyy/items/9954205a620b6f3c1f24
(さっきと同じ記事。圧倒的感謝)

あとは、Google先生の解説を見ながらfirebase storageにあげれば終わり！

```typescript:controller/postStorageController.ts
export function postStorageController(req: Request, res: Response, next: NextFunction) {
    const files: Express.Multer.File[] = req.files['Files'];

    files.forEach(fileInfo => {
        const uploadFilePath = `files/${fileInfo.originalname}`
        bucket.upload(fileInfo.path, { destination: uploadFilePath, contentType: fileInfo.mimetype }, error => {
            if (error) {
                console.log(`failed storage post ${fileInfo.originalname}`);
                console.log(error.message);
                return res.sendStatus(404);
            } else {
                console.log(`success storage post ${fileInfo.originalname}`);
                return res.sendStatus(200);
            }
    }
}
```

↓↓↓今回書いたソースコード

(フロント)
https://github.com/ShotaroOkada/fileupload_react_client

(サーバ)
https://github.com/ShotaroOkada/fileupload_express_api