marc
marc

Reputation: 126

node express with multer how to select MemoryStorage or DiskStorage at runtime

Hello I am trying to select the storage at runtime , because I also added a middleware for getting the content-size just before .

I have an exported enum elsewhere :

export enum Storage {
    DISK,
    MEMORY
}

Middleware checkHeader :

const checkHeader = (req :any , res: any , next:any ) => {
    console.log('content-length :',req.headers['content-length']);
    const sizeContent =  req.headers['content-length'];
    if (!sizeContent || Number(sizeContent) ==0 ) {
        res.send(400).end();
        return;
    }
    const sizeKo = Number(sizeContent)/1024 >5000 ;
    console.log('size : (KO) ',sizeKo);
    res.locals.storage = Number(sizeContent)/1024 >5000 ? Storage.DISK:Storage.MEMORY;
    next();
};

make multer middleware

const createUpload = (_req: Request, res: Response, _next:any) :any   =>{
    let storage;
    if (res.locals) {console.log('in createupload : ' , res.locals.storage);}
    else return _next;
    if (res.locals.storage === Storage.DISK){
        storage = multer.diskStorage({
            destination: function (_req, _file, cb) {
              cb(null, './uploads/');
            },
          
            filename: function (_req: any, file: any, cb: any) {
              cb(null, file.originalname);
            },
          });
    }
    else {
        storage = multer.memoryStorage();
    }
    return multer({ storage: storage, fileFilter: fileFilter }).any();
  };

create route

const router = express
  .Router()
  .get('/', controller.all)
  .post('/', controller.create)
  .get('/:id', controller.byId)
  .get('/:id/contractors', controller.getContractors)
  .post('/:id/contractors', controller.addContractors)
  .post('/:id/documents', checkHeader ,createUpload, controller.addDocument);

It doesn't work , I suppose it is because createUpload doesn't return , i.e, an example ,

multer({storage : multer.memoryStorage()}).any() 

but it returns the function that return it !! But I am forced to write it as a middleware function, i.e (req,res,next)=>return a middleware, in order to get it pass through the middleware chain ....

I don't know how to write the code for this use case , ...

Thank in advance

Upvotes: 0

Views: 599

Answers (1)

marc
marc

Reputation: 126

Finally , I got a workaround :

const fileFilter = (_req: any, file: any, cb: any) => {
  if (
    file.mimetype === 'image/jpg' ||
    file.mimetype === 'image/jpeg' ||
    file.mimetype === 'image/png' ||
    file.mimetype === 'application/pdf'
  ) {
    cb(null, true);
  } else {
    cb(new Error('not type pdf or jpg/jpeg or png'), false);
  }
};

const setUploadDest = (req :any , res: any , next:any ) => {
    console.log('content-length :',req.headers['content-length']);
    const sizeContent =  req.headers['content-length'];
    res.locals.storage = Number(sizeContent)/1024 >5000 ? Storage.DISK:Storage.MEMORY;
    next();
};


const skipMemory = (_req :any , res: any , next:any ) => {
    if (res.locals.storage !== Storage.MEMORY){
        next('route');
    }
    else next();
};

const skipDisk = (_req :any , res: any , next:any ) => {
    if (res.locals.storage !== Storage.DISK){
        next('route');
    }
    else next();
};


const diskStorage = multer.diskStorage({
        destination: function (_req, _file, cb) {
            cb(null, './uploads/');
        },
        filename: function (_req: any, file: any, cb: any) {
            cb(null, file.originalname);
        }
});



const router = express
  .Router()
  .get('/', controller.all)
  .post('/', controller.create)
  .get('/:id', controller.byId)
  .get('/:id/contractors', controller.getContractors)
  .post('/:id/contractors', controller.addContractors)
  .use('/:id/documents',setUploadDest)
  .post('/:id/documents', skipMemory , multer({storage : multer.memoryStorage(), fileFilter:fileFilter}).any() , controller.addDocument)
  .post('/:id/documents', skipDisk, multer({storage : diskStorage, fileFilter :fileFilter}).any() , controller.addDocument);

means I duplicated the post Router , one each is attached to a multer storage constructor . I control the routes by adding a "skip" middleware which gonna send to an other route if storage condtion not met ...

Upvotes: 1

Related Questions