Categories
JavaScript Rxjs

Rxjs Filtering Operators — Getting Specific Values

Rxjs is a library for doing reactive programming. Creation operators are useful for generating data from various data sources to be subscribed to by Observers.

In this article, we’ll look at some filter operators, including elementsAt , filter , first , ignoreElements , and last .

elementAt

The elementAt operator lets us get a single value by at the specified index in a sequence of emissions from the source Observable.

It takes up to 2 arguments. The first is the index , which is the number starting from 0 which the source Observable has emitted since subscription.

The second is the defaultValue which is an optional argument for the default value returned if the value is with the given index is not found.

It returns an Observable that emits a single item if it’s found. Otherwise, the default value provided by the optional second argument will be emitted.

A ArgumentOutOfRangeError will be thrown if the index provided is less than 0 or the Observable has completed before emitting the emission with the givenindex .

For example, we can use it as follows:

import { of } from "rxjs";  
import { elementAt } from "rxjs/operators";

const of$ = of(1, 2, 3);  
const result = of$.pipe(elementAt(2));  
result.subscribe(x => console.log(x));

Then we get 3 from console.log .

filter

The filter operator lets us filter out the emitted values from the source Observable by emitting the values from the source Observable that satisfies the conditions that are returned by a predicate function.

It takes up to 2 arguments. The first is the predicate function that’s evaluated each time the source Observable emits a value. The value is checked against this and it’s emitted by the returned Observe if it meets the criteria.

The predicate function takes 2 parameters, which are the object emitted from the source Observable and the index respectively. index starts from 0 and it’s the index -th object emitted since subscription.

For example, we can use it as follows:

import { of } from "rxjs";  
import { filter } from "rxjs/operators";

const of$ = of(1, 2, 3, 4, 5, 6);  
const result = of$.pipe(filter(x => x % 2 === 0));  
result.subscribe(x => console.log(x));

Then we get:

2  
4  
6

first

The first operator emits only the first value emitted by the source Observable.

It takes 2 optional arguments. The first is the predicate function which is called with each item to test for conditional matching.

The second is the default value, which is optional. It’s the default value that’s emitted in case no valid value was found from the source.

For example, we can use it as follows:

import { of } from "rxjs";  
import { first } from "rxjs/operators";

const of$ = of(1, 2, 3, 4, 5, 6);  
const result = of$.pipe(first());  
result.subscribe(x => console.log(x));

The code above takes the values from the of$ Observable and emits the first one, so we get 1 from the console.log .

We can also pass in a function to check for a match from the source Observable. For example, we can write:

import { of } from "rxjs";  
import { first } from "rxjs/operators";

const of$ = of(1, 2, 3, 4, 5, 6);  
const result = of$.pipe(first(x => x % 3 === 0));  
result.subscribe(x => console.log(x));

Since we passed in x => x % 3 === 0 to thefirst operator, first will check for the first one that matches our condition, which is a number that’s evenly divisible by 3.

Then we get the value 3 from console.log since that’s the first number of of$ that matches the condition.

We can pass in a default value as the second argument of first :

import { of } from "rxjs";  
import { first } from "rxjs/operators";  
const of$ = of(1, 2, 3, 4, 5, 6);  
const result = of$.pipe(first(x => x % 3 === 10, "none"));  
result.subscribe(x => console.log(x));

Since there’s no number in of$ that has the remainder 10 when divided by 3, the 'none' string will be emitted by the returned Observable.

ignoreElements

ignoreElements ignores all items emitted by the source Observable and only passes calls of complete or error .

It takes no arguments.

For example, we can use it as follows:

import { of } from "rxjs";  
import { ignoreElements } from "rxjs/operators";  
const of$ = of(1, 2, 3, 4, 5, 6);  
const result = of$.pipe(ignoreElements());  
result.subscribe(  
  val => console.log(val),  
  err => console.log(err),  
  () => console.log("end")  
);

Since nothing from the of$ Observable is emitted before completion, we just get 'end' logged.

last

The last operator returns an Observable that emits only the last item that’s emitted by the source Observable. If a predicate function is passed into last , then the last value that matches the condition returned by the predicate will be emitted.

It takes 2 optional arguments. The first is the predicate, which is optional. The predicate returns the condition that the emitted value from the source has to satisfy.

The second is an optional argument for the defaultValue , which the value that’ll be emitted if nothing emitted from the source Observable meets the condition returned by the predicate function.

For example, we can use it as follows:

import { of } from "rxjs";  
import { last } from "rxjs/operators";  
const of$ = of(1, 2, 3, 4, 5, 6);  
const result = of$.pipe(last());  
result.subscribe(val => console.log(val));

Then we get 6 logged since it’s the last value emitted by the of$ Observable.

We can also specify a condition as follows:

import { of } from "rxjs";  
import { last } from "rxjs/operators";  
const of$ = of(1, 2, 3, 4, 5, 6);  
const result = of$.pipe(last(x => x % 2 === 1));  
result.subscribe(val => console.log(val));

Then we get 5 logged since it’s the last value from the of$ Observable that’s odd.

elementAt operator lets us get a single value by at the specified index in a sequence of emissions from the source Observable.

The filter operator only emits the values from the source Observable that satisfies the conditions that are returned by a predicate function.

first operator emits only the first value emitted by the source Observable.

ignoreElements and only passes calls of complete or error and ignores everything else.

last returns an Observable that emits only the last item that’s emitted by the source Observable or the last one that meets the condition in the predicate function if it’s specified.

Categories
JavaScript Rxjs

Rxjs Filtering Operators — Distinctness

Rxjs is a library for doing reactive programming. Creation operators are useful for generating data from various data sources to be subscribed to by Observers.

In this article, we’ll look at some filtering operators, including the distinct , distinctUntilChanged , and distinctUntilKeyChanged operators.

distinct

The distinct operator emits the items from the source Observable that are distinct in comparison to previous items from the source.

It takes 2 optional arguments. The first is the keySelector function, which lets us select which value we want to check as distinct.

The second is an optional flushes Observable for flushing the internal HashSet from the operator.

It returns a new Observable that emits values that are distinct.

A simple example would be the following:

import { of } from "rxjs";  
import { distinct } from "rxjs/operators";
of(3, 3, 3, 3, 3, 3, 35, 5, 7, 8, 4, 6, 3, 5, 2, 4, 2)  
  .pipe(distinct())  
  .subscribe(x => console.log(x));

We have the following Observable with duplicate values:

of(3, 3, 3, 3, 3, 3, 35, 5, 7, 8, 4, 6, 3, 5, 2, 4, 2)

The values from it is pipe d to the distinct() operator to filter out duplicate values.

Then we get:

3  
35  
5  
7  
8  
4  
6  
2

from the console.log .

We can also check if some key of an entry is distinct as follows:

import { of } from "rxjs";  
import { distinct } from "rxjs/operators";

const people = [  
  { age: 4, name: "Joe" },  
  { age: 7, name: "Jane" },  
  { age: 5, name: "Jane" }  
];

of(...people)  
  .pipe(distinct(p => p.name))  
  .subscribe(x => console.log(x));

The code above spreads the people array as the arguments of the of operator, which emits the objects in the people array. Then the emitted values are pipe d into the distinct operator, which selects the name property to check for distinctness.

Then only the objects with a different name value is emitted.

In the end, we get:

{age: 4, name: "Joe"}  
{age: 7, name: "Jane"}

As the Observable.

distinctUntilChanged

distinctUntilChanged emits all items emitted from the source Observable that are distinct by comparison from the previous item from the source.

It takes 2 optional arguments, which is a compare function to test if an item is distinct from the previous item. The second argument is the keySelector function to return the value of the key that we want to check.

A simple example would be as follows:

import { of } from "rxjs";  
import { distinctUntilChanged } from "rxjs/operators";
of(1, 1, 5, 5, 6, 7, 8, 8, 8, 8, 9)  
  .pipe(distinctUntilChanged())  
  .subscribe(x => console.log(x));

The values from the of(1, 1, 5, 5, 6, 7, 8, 8, 8, 8, 9) is pipe d to the distinctUntilChanged operator and the previously emitted value is checked against the currently emitted value to see if they’re the same.

Then we get:

1  
5  
6  
7  
8  
9

since the value that’s different from the previously emitted one is emitted.

For Observables that emit objects, we can check if the property’s value is considered the same by passing in a function to the distinctUntilChanged operator as follows:

import { of } from "rxjs";  
import { distinctUntilChanged } from "rxjs/operators";  
const people = [  
  { age: 4, name: "Joe" },  
  { age: 7, name: "Jane" },  
  { age: 5, name: "Jane" }  
];  
of(...people)  
  .pipe(distinctUntilChanged((p, q) => p.name === q.name))  
  .subscribe(x => console.log(x));

The first and last parts work like the previous example. The difference is that now we have the (p, q) => p.name === q.name function to check if the previously emitted name value of the emitted object is the same as the currently emitted one.

Then we get:

{age: 4, name: "Joe"}  
{age: 7, name: "Jane"}

as the output from console.log .

distinctUntilKeyChanged

distinctUntilKeyChanged returns an Observable that emits the value of a source Observable that’s distinct by the comparison with a key of the object emitted previously from the source.

This means that an item will be emitted if the value with the given key is different from the previously emitted object key’s value.

It takes up to 2 arguments. The first is the key , which is a string with the object property to look up for each item.

The second is an optional compare function, which is called to test if an item is distinct from the previously emitted item from the source Observable.

It returns an Observable that emits item from the source Observable with distinct property value from the previously emitted one from the source.

For example, we can rewrite the previous example:

import { of } from "rxjs";  
import { distinctUntilChanged } from "rxjs/operators";  
const people = [  
  { age: 4, name: "Joe" },  
  { age: 7, name: "Jane" },  
  { age: 5, name: "Jane" }  
];  
of(...people)  
  .pipe(distinctUntilChanged((p, q) => p.name === q.name))  
  .subscribe(x => console.log(x));

into:

import { of } from "rxjs";  
import { distinctUntilKeyChanged } from "rxjs/operators";  
const people = [  
  { age: 4, name: "Joe" },  
  { age: 7, name: "Jane" },  
  { age: 5, name: "Jane" }  
];  
of(...people)  
  .pipe(distinctUntilKeyChanged("name"))  
  .subscribe(x => console.log(x));

Then we should get the same result as before. All we did was changing:

distinctUntilChanged((p, q) => p.name === q.name)

to:

distinctUntilKeyChanged("name")

We can use the distinct operator to get the distinct values emitted from a source Observable either by comparing primitive values or values of the properties of an object.

distinctUntilChanged , and distinctUntilKeyChanged let us emit the items from a source Observable that are different from the ones previously emitted by the source Observable. Again, it can compare by the primitive values or the values of the properties of an object.

Categories
JavaScript JavaScript Basics

Why it’s time to use the async-await in JavaScript?

Asynchronous code is a regular part of JavaScript. As web apps get more complex, there’ll be more need for asynchronous code since JavaScript is single-threaded, and asynchronous code prevents the blocking of the main thread.

In this article, we’ll look at why async and await is the way to go for writing asynchronous code.

The Old Way to Write Promise Code

Before we look at async and await, we have to look at what it’s like in the old days.

In the olden days, we chain promises by writing something like the following:

Promise.resolve(1)  
  .then(val => Promise.resolve(2))  
  .then(val => Promise.resolve(3))  
  .then(val => Promise.resolve(4))  
  .then(val => Promise.resolve(5))  
  .then(val => Promise.resolve(6))

As we can see, we have to call then a lot and in each then call, we have to pass in a callback function to return the next promise. This is a pain because it’s very long-winded. If we want to do something like gathering the resolved values from each promise, then the code gets even longer.

For example, to gather the resolved values into an array, we have to write something like:

let vals = [];  
Promise.resolve(1)  
  .then(val => {  
    vals.push(val);  
    return Promise.resolve(2)  
  })  
  .then(val => {  
    vals.push(val);  
    return Promise.resolve(3)  
  })  
  .then(val => {  
    vals.push(val);  
    return Promise.resolve(4)  
  })  
  .then(val => {  
    vals.push(val);  
    return Promise.resolve(5)  
  })  
  .then(val => {  
    vals.push(val);  
    return Promise.resolve(6)  
  })  
  .then(val => {  
    vals.push(val);  
    console.log(vals)  
  });

Then we get [1, 2, 3, 4, 5, 6] as the value of vals.

As we can see, the number of lines of code exploded compared to the first example.

There’s lots of repetition and takes up lots of space in a file.

To deal with this, it’s time to move to the present with the async-await syntax for chaining promises.

Async and Await

To clean up the code in the example above, we can use async and await to do this.

We start a function declaration with async and we use the await keyword inside. await does the same thing as the then callbacks. It takes the resolved value of the promise and lets us do stuff with it.

With async and await, we can turn:

let vals = [];  
Promise.resolve(1)  
  .then(val => {  
    vals.push(val);  
    return Promise.resolve(2)  
  })  
  .then(val => {  
    vals.push(val);  
    return Promise.resolve(3)  
  })  
  .then(val => {  
    vals.push(val);  
    return Promise.resolve(4)  
  })  
  .then(val => {  
    vals.push(val);  
    return Promise.resolve(5)  
  })  
  .then(val => {  
    vals.push(val);  
    return Promise.resolve(6)  
  })  
  .then(val => {  
    vals.push(val);  
    console.log(vals)  
  });

into:

(async () => {  
  const val = await Promise.resolve(1);  
  const val2 = await Promise.resolve(2);  
  const val3 = await Promise.resolve(3);  
  const val4 = await Promise.resolve(4);  
  const val5 = await Promise.resolve(5);  
  const val6 = await Promise.resolve(6);  
  const vals = [val, val2, val3, val4, val5, val6];  
  console.log(vals);  
})();

The await in the code above indicates that the code to the right of it returns a promise, and it’ll wait for the promise to be fulfilled until it moves on to the next one. Also, the resolved value can be assigned with the = and the variable or constant to the left of it.

The values can be gathered into an array at the end of the function and we can log it.

Even though this looks like synchronous code, async function can only return promises, so if we return vals, we’ll get a promise that resolves to the value of vals.

This means that:

const getVals = () => {  
  let vals = [];  
  Promise.resolve(1)  
    .then(val => {  
      vals.push(val);  
      return Promise.resolve(2)  
    })  
    .then(val => {  
      vals.push(val);  
      return Promise.resolve(3)  
    })  
    .then(val => {  
      vals.push(val);  
      return Promise.resolve(4)  
    })  
    .then(val => {  
      vals.push(val);  
      return Promise.resolve(5)  
    })  
    .then(val => {  
      vals.push(val);  
      return Promise.resolve(6)  
    })  
    .then(val => {  
      vals.push(val);  
      return Promise.resolve(vals);  
    });  
}

is the same as:

const getValsAsyncAwait = async () => {  
  const val = await Promise.resolve(1);  
  const val2 = await Promise.resolve(2);  
  const val3 = await Promise.resolve(3);  
  const val4 = await Promise.resolve(4);  
  const val5 = await Promise.resolve(5);  
  const val6 = await Promise.resolve(6);  
  const vals = [val, val2, val3, val4, val5, val6];  
  return vals;  
};

We can use await on both and see what we get.

This block:

const getVals = () => {  
  let vals = [];  
  return Promise.resolve(1)  
    .then(val => {  
      vals.push(val);  
      return Promise.resolve(2)  
    })  
    .then(val => {  
      vals.push(val);  
      return Promise.resolve(3)  
    })  
    .then(val => {  
      vals.push(val);  
      return Promise.resolve(4)  
    })  
    .then(val => {  
      vals.push(val);  
      return Promise.resolve(5)  
    })  
    .then(val => {  
      vals.push(val);  
      return Promise.resolve(6)  
    })  
    .then(val => {  
      vals.push(val);  
      return Promise.resolve(vals);  
    });  
}

(async () => {  
  const values = await getVals();  
  console.log(values);  
})()

gets us [1, 2, 3, 4, 5, 6] from the console.log.

And:

const getValsAsyncAwait = async () => {  
  const val = await Promise.resolve(1);  
  const val2 = await Promise.resolve(2);  
  const val3 = await Promise.resolve(3);  
  const val4 = await Promise.resolve(4);  
  const val5 = await Promise.resolve(5);  
  const val6 = await Promise.resolve(6);  
  const vals = [val, val2, val3, val4, val5, val6];  
  return vals;  
};

(async () => {  
  const values = await getValsAsyncAwait();  
  console.log(values);  
})()

also gets us [1, 2, 3, 4, 5, 6] from the console.log. So they do exactly the same thing, just with much fewer lines of code.

Catching Errors

In the olden days we catch errors with the catch and the callback passed into it.

For example, we write something like:

Promise.resolve(1)  
  .then(val => console.log(val))  
  .catch(err => console.log(err));

Now we can use try...catch with async and await:

(async () => {  
  try {  
    const val = await Promise.resolve(1);  
  } catch (err) {  
    console.log(err);  
  }  
})();

This doesn’t save much space, but this may still come in handy in case of errors.

As we can see, async and await make code for chaining promises so much shorter. It’s been available since 2017, so it’s supported by most modern browsers. The time to use this to clean up our code is definitely now.

Categories
JavaScript Vue

Introduction to Vue.js Computed Properties and Watchers

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at Vue.js computed properties and watchers.

Computed Properties

To make more template expressions more concise and reusable, we can create computed properties to compute results from existing properties as their value changes.

We can define computed properties in a Vue instance by putting them in the computed property of the options object that we pass into the Vue constructor.

For example, we can write the following in src/index.js:

new Vue({  
  el: "#app",  
  data: {  
    message: "foo"  
  },  
  computed: {  
    spelledMessage() {  
      return this.message.split("").join("-");  
    }  
  }  
});

Then we can use it like any other field in our HTML template. So in index.html, we can write:

<!DOCTYPE html>  
<html>  
  <head>  
    <title>Hello</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <p>{{message}}</p>  
      <p>{{spelledMessage}}</p>  
    </div>  
    <script src="./src/index.js"></script>  
  </body>  
</html>

We should then get:

foof-o-o

on our screen.

The spelledMessage method is a getter that’s used by Vue.js. It takes the returned value of it and then put it in place of {{spelledMessage}} .

Therefore, the name of the placeholder in the template must be the same as the name of the method that returns the value that we want in the computed object.

We can also get the value from the returned Vue instance as follows:

const vm = new Vue({  
  el: "#app",  
  data: {  
    message: "foo"  
  },  
  computed: {  
    spelledMessage() {  
      return this.message.split("").join("-");  
    }  
  }  
});

console.log(vm.spelledMessage);

We should see f-o-o logged from the console.log.

We can bind to computed properties in templates like any other property. Vue knows that vm.spelledMessage depends on vm.message, so the bindings will be updated when vm.message is updated.

The computed getter method doesn’t commit side effects, which makes it easy to test and understand.

Computed Caching vs Methods

One good feature of computed properties is that the result of it is cached.

There’s no caching for results returned from methods.

So instead of using methods, we should use computed properties for cases where we’re computing something from existing properties.

A computed property is only re-evaluated once a reactive property is updated.

For example, if we have:

const vm = new Vue({  
  el: "#app",  
  data: {  
    message: "foo"  
  },  
  computed: {  
    now() {  
      return Date.now();  
    }  
  }  
});

It’ll never update after its first computed since it doesn’t depend on any reactive property from the data property.

Without caching computed properties keep getting computed as reactive properties that they depend on change, which means the app gets slow as reactive properties that the computed property depends on are changing.

Computed vs Watched Property

Watch properties are useful for watching for changes in a property as the name suggests.

However, because of the caching feature of computed properties, we should use them as much as we can.

For instance, we can simplify the following:

new Vue({  
  el: "#app",  
  data: {  
    name: "Joe",  
    age: 1,  
    person: undefined  
  },  
  watch: {  
    name: {  
      immediate: true,  
      handler(newVal) {  
        this.person = `${newVal} - ${this.age}`;  
      }  
    },  
    age: {  
      immediate: true,  
      handler(newVal) {  
        this.person = `${this.name} - ${newVal}`;  
      }  
    }  
  }  
});

to:

new Vue({  
  el: "#app",  
  data: {  
    name: "Joe",  
    age: 1  
  },  
  computed: {  
    person() {  
      return `${this.name} - ${this.age}`;  
    }  
  }  
});

As we can see, the first example was much more complex. We have to set immediate to true in each property so that it’ll watch the initial value change. Then we have to define the value change handler for each reactive property.

Then in each handler, we have to set the person property so that we can combine name and age.

On the other hand, with computed properties, we only have one method which returns the fields combined in the way we want.

It’s much more convenient for us and the app that we create is also faster because of caching.

Computed Setter

We can also create a setter function for computed properties.

For example, we can write:

new Vue({  
  el: "#app",  
  data: {  
    name: "Joe",  
    age: 1  
  },  
  computed: {  
    person: {  
      get() {  
        return `${this.name} - ${this.age}`;  
      },  
      set(newValue) {  
        const [name, age] = newValue.split("-");  
        this.name = name.trim();  
        this.age = age.trim();  
      }  
    }  
  }  
});

The getter function returns the same thing as before, but now we also have a setter function.

The setter function splits the newValue, which has the computed value from the getter function, we split the result and set the result back to the corresponding reactive properties.

We can use a setter as follows. We can put the following in src/index.js:

new Vue({  
  el: "#app",  
  data: {  
    firstName: "Joe",  
    lastName: "Smith"  
  },  
  computed: {  
    name: {  
      get() {  
        return `${this.firstName} ${this.lastName}`;  
      },  
      set(newValue) {  
        const [firstName, lastName] = newValue.split(" ");  
        this.firstName = (firstName || "").trim();  
        this.lastName = (lastName || "").trim();  
      }  
    }  
  }  
});

And in index.html, we put:

<!DOCTYPE html>  
<html>  
  <head>  
    <title>Hello</title>  
    <meta charset="UTF-8" />  
    <script src="[https://cdn.jsdelivr.net/npm/vue/dist/vue.js](https://cdn.jsdelivr.net/npm/vue/dist/vue.js)"></script>  
  </head> <body>  
    <div id="app">  
      <p>{{name}}</p>  
      <input type="text" v-model="name" />  
    </div>  
    <script src="./src/index.js"></script>  
  </body>  
</html>

Then when we change the value in the input, we get the new values assigned back to the firstName and lastName fields with the setter.

Conclusion

We can use computed properties to compute values from existing properties.

Returned values from computed properties are cached to reduce the amount of computation required.

Computed properties can also have setters, where we can do things with the new values returned from the computed property getter.

Categories
Express JavaScript Nodejs

Configuring Express Multer Middleware and Checking File Information

Multer is a middleware that lets us process file uploads with our Express app.

In this article, we’ll look at the settings that we can change to upload files our way, and also check the file information.

Checking File Information

We can check the uploaded files’ information by looking at the req.file object for single file upload and the array entries of req.files for multiple file uploads.

These fields are available for each file:

  • fieldname — field name specified in the form
  • originalname — name of the file on the user’s computer
  • encoding — encoding type of the file
  • mimetype — MIME-type of the file
  • size — size of the file in bytes
  • destination — the folder where the file was saved on the server
  • filename — name of the file stored in the destination
  • path — the full path of the uploaded file
  • bufferBuffer object of the whole file

Options for File Upload

The multer function takes an options object that takes a variety of options.

We can do things like set the destination of the files and rename the files.

The following properties can be in the options object:

  • dest or storage — where to store the files
  • fileFilter — controls which files are accepted
  • limits — limits of the uploaded data
  • preservePath — keep the full path of the files instead of just the base name

Storage Options

DiskStorage

We can store files on disk by using the diskStorage method.

There’re 2 options available, destination and filename . They’re both functions that determine the destination where the file is saved and what to rename the file to respectively.

Each function takes the requestion object, file object and callback function. The callback function is called at the end of each function with the first argument being null .

The second argument is the destination that we want to save the file for the destination function and the filename that we want to rename the file to for the filename function.

For example, we can rename a file by keeping the original name and adding a timestamp to the end of the file as follows:

const express = require('express');  
const bodyParser = require('body-parser');  
const multer = require('multer');  
const storage = multer.diskStorage({  
  destination: (req, file, cb) => {  
    cb(null, './uploads/')  
  },  
  filename: (req, file, cb) => {  
    cb(null, `${file.originalname}-${+Date.now()}`)  
  }  
})
const upload = multer({ storage });  
const app = express();
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static('public'));
app.get('/', (req, res) => {  
  res.sendFile('public/index.html');  
});
app.post('/upload', upload.single('upload'), (req, res) => {  
  res.send('file uploaded')  
});
app.listen(3000, () => console.log('server started'));

MemoryStorage

memoryStorage stores files in memory as a Buffer object and doesn’t take any option.

For example, we can use it as follows:

const express = require('express');  
const bodyParser = require('body-parser');  
const multer = require('multer');  
const storage = multer.memoryStorage();  
const upload = multer({ storage })  
const app = express();app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static('public'));
app.get('/', (req, res) => {  
  res.sendFile('public/index.html');  
});
app.post('/upload', upload.single('upload'), (req, res) => {  
  console.log(req.file);  
  res.send('uploaded');  
});
app.listen(3000, () => console.log('server started'));

Then we get the buffer property in req.file with the content of the upload file as the value of it.

Upload Limits

The limits object specifies the size limits of the following optional properties:

  • fieldNameSize — maximum field name size. Defaults to 100 bytes
  • fieldSize — maximum field value size. Defaults to 1MB
  • fields — the maximum number of non-file fields. Defaults to Infinity
  • fileSize — maximum file size in bytes. Defaults to Infinity
  • files — maximum of file fields. Defaults to Infinity
  • parts — the maximum number of parts (fields and files). Defaults to Infinity
  • headerPairs — the maximum number of header key-value pairs to parse. Defaults to 2000.

This is useful for preventing denial of service attacks.

We can set the limits as follows:

const express = require('express');  
const bodyParser = require('body-parser');  
const multer = require('multer');  
const upload = multer({  
  limits: {  
    fieldSize: 1024 * 512,  
    fieldNameSize: 200  
  },  
  dest: './uploads/'  
});  
const app = express();app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static('public'));
app.get('/', (req, res) => {  
  res.sendFile('public/index.html');  
});
app.post('/upload', upload.single('upload'), (req, res) => {  
  res.send('file uploaded')  
});
app.listen(3000, () => console.log('server started'));

We set the field size limit to 512 KB and field name size to 200 bytes in the code above.

Controlling the Files to Process

The fileFilter field is a function that lets us control which files should be uploaded and which should be skipped.

For example, we can throw an error if the file uploaded doesn’t have the MIME-type image/png and then handle the error in our route as follows:

const express = require('express');  
const bodyParser = require('body-parser');  
const multer = require('multer');  
const upload = multer({  
  fileFilter: (req, file, cb) => {  
    if (file.mimetype === 'image/png') {  
      cb(null, true);  
    }  
    else {  
      cb(new multer.MulterError('not a PNG'));  
    }  
  },  
  dest: './uploads/'  
})  
  .single('upload')  
const app = express();
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static('public'));
app.get('/', (req, res) => {  
  res.sendFile('public/index.html');  
});
app.post('/upload', (req, res) => {  
  upload(req, res, (err) => {  
    if (err instanceof multer.MulterError) {  
      res.send('file not uploaded since it\'s not a PNG');  
    }  
    else {  
      res.send('file uploaded');  
    }  
  })  
});
app.listen(3000, () => console.log('server started'));

First, we have the file type check by setting a function with the fileFilter function:

const upload = multer({  
  fileFilter: (req, file, cb) => {  
    if (file.mimetype === 'image/png') {  
      cb(null, true);  
    }  
    else {  
      cb(new multer.MulterError('not a PNG'));  
    }  
  },  
  dest: './uploads/'  
})  
  .single('upload')

Then in our /upload route, we have:

app.post('/upload', (req, res) => {  
  upload(req, res, (err) => {  
    if (err instanceof multer.MulterError) {  
      res.send('file not uploaded since it\'s not a PNG');  
    }  
    else {  
      res.send('file uploaded');  
    }  
  })  
});

to catch the MulterError and respond accordingly. If the file is a PNG, then it’s uploaded. Otherwise, an error is thrown and the error won’t be uploaded.

In either case, we send a response indicating if the file was uploaded.

Conclusion

Multer has lots of options for us to control how file upload is done. We can check the file type, set the destination, control how much we can upload, etc.

Also, we can catch errors in our routes by using the upload function inside our route handler instead of using it as a middleware.

We can also check for file information with req.file for single file upload and the req.files array for multiple file upload.

Finally, we can change where files are stored by changing the destination and storage type.