Routing-controllers: How to implement upload ?

Created on 22 Aug 2017  路  10Comments  路  Source: typestack/routing-controllers

Hi there,
I can't upload a file.

PhotoController.ts
````
@Service()
@JsonController("/photo/photo")
export class Photo_PhotoController
{
dest = __dirname + '/../../../../public/photos/tmp';
fileUploadOptions = {
storage: multer.diskStorage({
destination: (req: any, file: any, cb: any) => {
cb(null, this.dest);
},
filename: (req: any, file: any, cb: any) => {
cb(null, 'toto.jpeg');
}
}),
fileFilter: (req: any, file: any, cb: any) => {
cb(null, true);
},
limits: {
fieldNameSize: 255,
fileSize: 1024 * 1024 * 2
}
};

//https://github.com/pleerock/routing-controllers#inject-uploaded-files
@Post("/upload/acces/:acces")
upload(@UploadedFile("file", { options: this.fileUploadOptions }) file: any, @Param("acces") acces: number, @Req() request: Request, @Res() response: Response) {
console.log(file);

    let id_annonce = parseInt(request.session.candidat.id);
    const photoService = Container.get(PhotoService);        `

    // to keep code clean better to extract this function into separate file

    let dest = __dirname + '/../../../../public/photos/tmp';
    const fileUploadOptions = {
        storage: multer.diskStorage({
            destination: (req: any, file: any, cb: any) => {
               cb(null,  dest);
            },
            filename: (req: any, file: any, cb: any) => {
                cb(null, req.body.username + '.jpeg');
            }
        }),
        fileFilter: (req: any, file: any, cb: any) => {

        },
        limits: {
            fieldNameSize: 255,
            fileSize: 1024 * 1024 * 2
        }
    };

    const upload = multer(fileUploadOptions);

    try {
        let result = upload.single('file');
    } catch(error: Error) {
        console.log(error);
    }
    return 'ok';
}

````

console.log(file) =>
{ fieldname: 'file', originalname: 'fallback.jpeg', encoding: '7bit', mimetype: 'image/jpeg', buffer: <Buffer ff d8 ff e0 00 10 4a 46 49 46 00 01 01 01 00 48 00 48 00 00 ff e2 0b f8 49 43 43 5f 50 52 4f 46 49 4c 45 00 01 01 00 00 0b e8 00 00 00 00 02 0 0 00 00 ... >, size: 161077 }

No error but no file copied into my directory.

Example in the doc is:
// use options this way:
@Post("/files")
saveFile(@UploadedFile("fileName", { options: fileUploadOptions }) file: any) {
}
But it doesn't work.
I don't understand how to use it, .

invalid question

Most helpful comment

Still trying...
I found this: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18569
But it results in:

TS2702: 'Express' only refers to a type, but is being used as a namespace here.

import { Express } from 'express';
/* = = = = = = = */ 
@Post('/upload')
  upload(@UploadedFile('file') file: Express.Multer.File) {
    console.log(file);
    return 'ok';
  }

When adding @types/express:
TS2694: Namespace 'global.Express' has no exported member 'Multer'.

Aside from that, I got it to work. One must be sure to add name to match @UploadedFile('name') and field that is equal to file's name;

All 10 comments

Why do you do:

        const upload = multer(fileUploadOptions);

        try {
            let result = upload.single('file');
        } catch(error: Error) {
            console.log(error);
        }
        return 'ok';

You have defined your action parameter as @UploadedFile("file", { options: this.fileUploadOptions }) file: any so just use the file parameter - it's and object like you described with filename, mimetype and a Buffer with binary file data.

Yes i understand what you mean but i've no idea how to upload this file.

````
@Post("/upload/acces/:acces")
upload(@UploadedFile("file", { options: this.fileUploadOptions }) file: any, @Param("acces") acces: number, @Req() request: Request, @Res() response: Response) {
console.log(file);
// DO NOTHING, MAGICAL UPLOAD ?

    let upload = multer();
    let result = upload.single(file); // => no error but doesn't work

    return 'ok';
}

````
I've got no errors , i don't know what to do.
Can you give me an example please @19majkel94 ?

@Post("/upload")
async handleFileUpload(@UploadedFile("file") file: Express.Multer.File) {
    if (!allowedMimeTypes.includes(file.mimetype)) {
        throw new BadRequestError(`${file.mimetype} is not a supported file type!`);
    }

    await filesystem.writeFile(writePath, file.originalname);

    return {
        status: "OK"
    };
}

Please read this:
https://github.com/expressjs/multer

So no need of upload.single('file') !
I don't understand what is utility of multer in this example.
It works so that is not important.
Thank you @19majkel94 !

Hi @19majkel94 !

I have got the same issue.

Upload.ts
import * as multer from 'multer';
// import * as path from 'path';
import logger from '../logger';

export const fileUploadOptions = () => {
logger.info('fileUploadOptions req:');
storage: multer.diskStorage({
destination: (req: any, file: any, cb: any) => {
logger.info('fileFilter req:', req);
logger.info('fileFilter file:', file);
cb(null, 'src/public/images');
},
filename: (req: any, file: any, cb: any) => {
logger.info('fileFilter req:', req);
logger.info('fileFilter file:', file);
cb(null, file.fieldname + '-' + Date.now());
}
});
};

UserController.ts

import { fileUploadOptions } from '../modules/upload';

@HttpPost('/files')
uploadPhoto(@UploadedFile('fileName', { options: fileUploadOptions }) file: any) {
logger.info('UserController.ts::: uploadPhoyto() fileName:::', file.originalname);
return {
filename: file.originalname,
buffer: file.buffer.length,
size: file.size,
fieldname: file.fieldname
};
}

It does not work as the document said. Is there any missing in my snippet code ?

Ok, this is how I did it:

<form role="form" method='post' action='my-url-here' enctype=multipart/form-data>
<input type="file" id="file" name="file">
</form>

```@Post("/upload")
async handleFileUpload(@Req() req: any, @Res() response: any, @Body() form: any, @UploadedFile("file") file: any) {
// and now you can read the file.buffer as a file.
}

Thanks @franciscocorrales. It is working. It seems there are something missing using fileUploadOptions

@HttpPost('/files')
    uploadPhoto( @UploadedFile('file') file: any) {

        fs.writeFile('upload.png', file.buffer, (err) => {
            logger.error('uploadPhoto errerrerr:::', err);
        });

        // https://github.com/typestack/routing-controllers/issues/260

        return {
            filename: file.originalname,
            size: file.size,
            fieldname: file.fieldname
        };
    }

@19majkel94
In your example you used Express.Multer.File. It is also in the readme. However I'm getting compilation errors. I installed multer and @types/multer and also @types/express and got this:
Namespace 'global.Express' has no exported member 'Multer'.
And no matter how I send that file from FE, be it from swagger, postman or angular, file variable is undefined.

Still trying...
I found this: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18569
But it results in:

TS2702: 'Express' only refers to a type, but is being used as a namespace here.

import { Express } from 'express';
/* = = = = = = = */ 
@Post('/upload')
  upload(@UploadedFile('file') file: Express.Multer.File) {
    console.log(file);
    return 'ok';
  }

When adding @types/express:
TS2694: Namespace 'global.Express' has no exported member 'Multer'.

Aside from that, I got it to work. One must be sure to add name to match @UploadedFile('name') and field that is equal to file's name;

@MikeDabrowski try import * as Express from 'express'

Was this page helpful?
0 / 5 - 0 ratings

Related issues

azaslonov picture azaslonov  路  5Comments

davidquintard picture davidquintard  路  4Comments

circy picture circy  路  3Comments

posabsolute picture posabsolute  路  4Comments

humbertowoody picture humbertowoody  路  4Comments