Categories
Express JavaScript

Guide to the Express Application Object — Middleware

The core part of an Express app is the Application object. It’s the application itself.

In this article, we’ll look at the methods of the app object and what we can do with it, including using app.use to set middleware.

app.use([path,] callback [, callback…])

We can use the app.use method to mount middleware that’s run app-wide.

They can be run when requests for specific paths are made or for all paths.

It takes the following arguments:

  • path — it can be a string or regex representing paths or patterns of paths. The default is / .
  • callback — a function to handle requests. It can be a middleware function, a series of them, array of them, or a combination of all of the above

We can provide multiple callbacks that behave just like middleware, but they call next('route') to skip the remaining middleware functions.

We can use these to impose preconditions on some routes and pass control to the route if we don’t need to call the remaining middleware.

Since router and app implement the middleware interface, we can use them like any other middleware function.

For example, we can use it as follows:

const express = require('express');  
const bodyParser = require('body-parser');  
const app = express();
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));  
app.use((req, res, next) => {  
  console.log(`Request made at ${Date.now()}`)  
  next();  
})

app.get('/', (req, res) => {  
  res.send('hi');  
})

app.listen(3000);

Then we get the request time logged with every request.

We call next to call the route handler.

Middlewares are run sequentially, so the order they’re included in the code is important.

For example, if we have:

const express = require('express');  
const bodyParser = require('body-parser');  
const app = express();
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));  
app.use((req, res, next) => {  
  res.send('End with middleware');  
})

app.get('/', (req, res) => {  
  res.send('hi');  
})

app.listen(3000);

Then we get End with middleware instead of hi since we sent our response with the middleware, which we included first.

Error-Handling Middleware

We can create our own middleware for handling errors instead of using Express’s default error handler.

The error handler takes 4 arguments, which are the error object, request object, response object, and next function.

For instance, we can define one as follows:

const express = require('express');  
const bodyParser = require('body-parser');  
const app = express();
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
app.get('/', (req, res, next) => {  
  try {  
    throw new Error('foo');  
  }  
  catch (ex) {  
    next(ex);  
  }  
})

app.use((err, req, res, next) => {  
  res.status(500).send('error');  
})

app.listen(3000);

The error should be displayed since we included the error handler after our GET request handler.

Paths

We can path in a string or regex path or path pattern as the first argument of the use method. This way, the middleware will only be called when the route matches the one specified in string or regex.

To match a constant path, we can write the following:

app.use('/abc', (err, req, res, next) => {  
  res.status(500).send('error');  
})

We can match patterns as follows. A ? will make the character preceding it optional:

app.use('/abc?d', (err, req, res, next) => {  
  res.status(500).send('error');  
})

The when requests made to /abcd or /abd has an error, the middleware above will be called.

The + sign means that one or more characters preceding it will be matched. For example, if we have:

app.use('/abc+d', (err, req, res, next) => {  
  res.status(500).send('error');  
})

The when requests made to /abccd,/abcccd, etc. has an error, the middleware above will be called.

* is a wildcard character. We can use it as follows:

app.use('/ab*cd', (err, req, res, next) => {  
  res.status(500).send('error');  
})

Then we get error when we make a request to /abcccd , /abFoocd , and so on if that has an error.

To match a group of optional characters, we can use parentheses and a question mark after it.

For instance, if we have:

app.use('/a(bcd)?e', (err, req, res, next) => {  
  res.status(500).send('error');  
})

Then we get error when we make a request to /abcde or/ae that has an error.

Passing in Middleware

We can pass in various combinations of middleware in addition to just one middleware.

We can pass in a router object as a middleware as follows:

const express = require('express');  
const bodyParser = require('body-parser');  
const app = express();app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));const router = express.Router();  
router.get('/', (req, res, next) => {  
  res.send();  
});

app.use(router);app.listen(3000);

An Express app is also valid middleware:

const express = require('express');  
const bodyParser = require('body-parser');  
const app = express();
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
const subApp = express();
subApp.get('/', (req, res, next) => {  
  res.send();  
});

app.use(subApp);app.listen(3000);

We can also pass in a series of middleware as arguments:

const express = require('express');  
const bodyParser = require('body-parser');  
const app = express();
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));  
const r1 = express.Router();  
r1.get('/', (req, res, next) => {  
  console.log('r1 called');  
  next();  
});

const r2 = express.Router();  
r2.get('/', (req, res, next) => {  
  console.log('r2 called');  
  next();  
});  
app.use(r1, r2);
app.listen(3000);

Then they’ll be called in order, so we get:

r1 called  
r2 called

in the console.

Likewise, we can pass in an array of middlewares as follows:

const express = require('express');  
const bodyParser = require('body-parser');  
const app = express();
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));  
const r1 = express.Router();  
r1.get('/', (req, res, next) => {  
  console.log('r1 called');  
  next();  
});

const r2 = express.Router();  
r2.get('/', (req, res, next) => {  
  console.log('r2 called');  
  next();  
});  
app.use([r1, r2]);
app.listen(3000);

Then we get the same output since they’re called in the same order that they’re listed.

A combination of them also works:

const express = require('express');  
const bodyParser = require('body-parser');  
const app = express();
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));  
const foo = (req, res, next) => {  
  console.log('foo called');  
  next();  
}

const r1 = express.Router();  
r1.get('/', (req, res, next) => {  
  console.log('r1 called');  
  next();  
});

const r2 = express.Router();  
r2.get('/', (req, res, next) => {  
  console.log('r2 called');  
  next();  
});

const subApp = express();  
subApp.get('/', (req, res, next) => {  
  console.log('subApp called');  
  next();  
})

app.use(foo, [r1, r2], subApp);app.listen(3000);

Then we get:

foo called  
r1 called  
r2 called  
subApp called

from the console. They’re still called in the order they’re listed.

Static Files

We can expose static folders with the express.static middleware. For example, if we want to expose the public folder in the project folder, we can write:

app.use(express.static(path.join(__dirname, 'public')));

Conclusion

app.use can be used to one more middleware in various combinations, including a single middleware, an array of middlewares, a comma-separated list of middlewares or a combination of them.

They’re called in the order that they’re included, and the next one can be called by calling next .

Error handlers are also middleware functions. The only difference is that they have an error parameter before the request and response parameters.

Finally, we can expose static folders with the express.static middleware.

Categories
Express JavaScript Nodejs

Guide to the Express Router Object — Request and Parameter Handling

The Expressrouter object is a collection of middlewares and routes. It a mini-app within the main app.

It can only perform middleware and routing functions and can’t stand on its own.

It also behaves like middleware itself, so we can use it with app.use or as an argument to another route’s use method.

In this article, we’ll look at the router object’s methods, including all , param , and methods for listening to specific kinds of requests.

Methods

router.all(path, [callback, …] callback)

The router.all method takes a callback for handling all kinds of requests.

We can pass in a constant path, or a string with the path pattern or a regex.

For example, we can pass in middleware that’s run for all routes attached to the router as follows:

const express = require('express');  
const bodyParser = require('body-parser');
const app = express();  
const fooRouter = express.Router();
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
const mw1 = (req, res, next) => {  
  console.log('middleware 1 called');  
  next();  
}
const mw2 = (req, res, next) => {  
  console.log('middleware 2 called');  
  next();  
}
fooRouter.all('*', mw1, mw2);
fooRouter.get('/', (req, res) => {  
  res.send('foo');  
})
app.use('/foo', fooRouter);app.listen(3000, () => console.log('server started'));

Then we get:

middleware 1 called  
middleware 2 called

if we make a request to /foo since anything that starts with /foo routes through the fooRouter , and we have the fooRouter.all method call with the middlewares passed in.

Equivalently, we can write:

const express = require('express');  
const bodyParser = require('body-parser');
const app = express();  
const fooRouter = express.Router();
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
const mw1 = (req, res, next) => {  
  console.log('middleware 1 called');  
  next();  
}
const mw2 = (req, res, next) => {  
  console.log('middleware 2 called');  
  next();  
}
fooRouter.all('*', mw1);  
fooRouter.all('*', mw2);
fooRouter.get('/', (req, res) => {  
  res.send('foo');  
})
app.use('/foo', fooRouter);
app.listen(3000, () => console.log('server started'));

They’re the same as long as the order of fooRouter.all is called in the same as the order the callbacks are passed in.

router.METHOD(path, [callback, …] callback)

router.METHOD is for handling requests with the given method. For example, router.get for handling GET requests, router.post for handling POST requests, etc.

router.get also automatically calls for the HTTP HEAD in addition to the GET method if router.head wasn’t called.

We can provide multiple callbacks and they’re all treated equally. These callbacks may invoke the next('route') call to bypass the remaining route callbacks.

For example, we can use it as follows:

const express = require('express');  
const bodyParser = require('body-parser');
const app = express();  
const fooRouter = express.Router();
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
fooRouter.get('/', (req, res) => {  
  res.send('foo');  
})
app.use('/foo', fooRouter);
app.listen(3000, () => console.log('server started'));

Then when we make a request to /foo , we get back foo .

We can also pass in a regex for the route path . For example, we can write:

const express = require('express');  
const bodyParser = require('body-parser');
const app = express();  
const fooRouter = express.Router();
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
fooRouter.get('/ab+c/', (req, res) => {  
  res.send('foo');  
})
app.use('/foo', fooRouter);
app.listen(3000, () => console.log('server started'));

to listen to requests for paths /foo/abc , /foo/abbc , /foo/abbbc , etc., since we specified in the regex that we look for any number of the character b in the path.

router.param(name, callback)

router.param lets us trigger a callback function call when a specific parameter is passed in when the request is made from the client.

name is the parameter placeholder name that we look for.

The parameters of the callback function are:

  • req, the request object.
  • res, the response object.
  • next, indicating the next middleware function.
  • The value of the name parameter.
  • The name of the parameter.

For example, we can use it as follows:

const express = require('express');  
const bodyParser = require('body-parser');
const app = express();  
const fooRouter = express.Router();
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
fooRouter.param('name', (req, res, next, name) => {  
  req.name = name;  
  next();  
})
fooRouter.get('/:name', (req, res) => {  
  res.send(req.name);  
})
app.use('/foo', fooRouter);
app.listen(3000, () => console.log('server started'));

Then we make a request to /foo/abc then we get abc since the fooRouter.param found the name parameter was passed in with the URL.

The name parameter has the value 'abc' because it grabbed the part after /foo/ and then we assigned name to req.name and called next .

After that, the route handler we passed into foorRouter.get is called, then we passed req.name into res.send and sent it as the response.

Conclusion

The Express router lets us create sub-apps of an Express app so we don’t have to add all the route handlers and middlewares to the main app.

With the all method, we can listen to all kinds requests. We can also listen to specific kinds of requests like GET or POST requests with the respective methods. They all take a string or regex path and a route handler callback.

Finally, we have the param method to get route parameters and do what we want with it.

Categories
JavaScript Rxjs

Rxjs Operators — More Utility Operators

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 utility operators that help us do various things, including the materialize , observeOn , subscribeOn , timeInterval and timeStamp operators.

materialize

The materialize operator maps all the emitted values from the source Observable into Notification objects.

It takes no arguments and returns an Observable that emits Notification objects with the values from the source Observable as values of the value property of the Notification object.

For example, we can use it as follows:

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

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

The code above takes the values of the of$ Observable, wrap each in a Notification object and emit it.

Then we’ll get the following objects:

{  
  "kind": "N",  
  "value": 1,  
  "hasValue": true  
}  
{  
  "kind": "N",  
  "value": 2,  
  "hasValue": true  
}  
{  
  "kind": "N",  
  "value": 3,  
  "hasValue": true  
}  
{  
  "kind": "C",  
  "hasValue": false  
}

It’ll emit error values when encountered:

import { of } from "rxjs";  
import { materialize, map } from "rxjs/operators";

const of$ = of(1, 2, 3);  
const upperCase = of$.pipe(map(x => x.toUpperCase()));  
const materialized = upperCase.pipe(materialize());  
materialized.subscribe(x => console.log(x));

Then we get:

{  
  "kind": "E",  
  "error": {},  
  "hasValue": false  
}

since x has no toUpperCase method as they’re numbers emitted by the source Observable.

observeOn

The observeOn operator returns an Observable that re-emits all notifications from the source Observable with the specified scheduler.

It takes up to 2 arguments. The first is the scheduler that we’ll use to reschedule notifications from the source Observable.

The second argument is the optional delay argument, which defaults to 0. It’s the number of milliseconds that represents the delay for every notification that’s rescheduled.

We shouldn’t use observeOn to emit values from source Observables that emits lots of values synchronously. The delay operator is better for delaying the emission of values from the source Observable.

For example, we can use it as follows:

import { interval, animationFrameScheduler } from "rxjs";  
import { observeOn, take } from "rxjs/operators";
const intervals = interval(10).pipe(take(10));  
const animationInterval = intervals.pipe(observeOn(animationFrameScheduler));  
animationInterval.subscribe(x => console.log(x));

We piped the emitted values from the intervals Observable to the animationFrameScheduler , which helps with smoothing out changes for animations.

subscribeOn

The subscribeOn operator returns an Observable that asynchronously subscribes to Observers to the source Observable.

It takes up to 2 arguments. The first is the scheduler to perform the subscription action on, and the second is an optional delay argument, which defaults to 0.

For example, we can use it as follows:

import { of, merge, asyncScheduler } from "rxjs";  
import { subscribeOn } from "rxjs/operators";

const a = of("a", "b", "c").pipe(subscribeOn(asyncScheduler));  
const b = of(5, 6, 7, 8, 9);  
merge(a, b).subscribe(console.log);

Then we get:

5  
6  
7  
8  
9  
a  
b  
c

from the console.log since a is converted to an asynchronous Observable by the subscribeOn(asyncScheduler) , while b still emits values synchronously.

Asynchronous emissions are queued after synchronous ones. Therefore, the values are emitted later than the synchronous ones.

timeInterval

The timeInterval returns an Observable that emits an object containing the current value and the time that’s passed between emitting the current value and the previous value. The time difference is calculated with the scheduler ‘s now() method to get the current time for each emission.

The scheduler defaults to async , so by default, the time is measured in milliseconds.

It takes one optional argument, which is the scheduler , which is used to get the current time.

For example, we can use it as follows:

import { interval } from "rxjs";  
import { timeInterval, take } from "rxjs/operators";

const a = interval(1000).pipe(take(3));  
a.pipe(timeInterval()).subscribe(  
  value => console.log(value),  
  err => console.log(err)  
);

The a Observable’s emitted values are pipe d to the timeInterval operator which emits an object with the value from the source Observable along with the time interval between the current and previous emitted value.

Then we get:

{  
  "value": 0,  
  "interval": 1001  
}  
{  
  "value": 1,  
  "interval": 1000  
}  
{  
  "value": 2,  
  "interval": 999  
}

from the console.log .

timestamp

The timestamp operator returns an Observable that adds a timestamp to each item emitted by the source Observable to indicate when it was emitted.

It takes an optional scheduler argument which defaults to async .

For example, we can use it as follows:

import { interval } from "rxjs";  
import { timestamp, take } from "rxjs/operators";

const a = interval(1000).pipe(take(3));  
a.pipe(timestamp()).subscribe(  
  value => console.log(value),  
  err => console.log(err)  
);

The code above takes the items emitted by the a Observable then pipe it to the timestamp operator, which returns an object that has the value emitted by the source Observable along with the timestamp of when it’s emitted.

Then we get:

{  
  "value": 0,  
  "timestamp": 1576632836715  
}  
{  
  "value": 1,  
  "timestamp": 1576632837715  
}  
{  
  "value": 2,  
  "timestamp": 1576632838715  
}

The materialize operator maps all the emitted values from the source Observable into Notification objects.

observeOn returns an Observable that re-emits all notifications from the source Observable with the specified scheduler.

subscribeOn returns an Observable that asynchronously subscribes to Observers to the source Observable.

timeInterval returns an Observable that emits an object containing the current value and the time that’s passed between emitting the current value and the previous value.

timestamp returns an Observable that adds a timestamp to each item emitted by the source Observable of when it was emitted.

Categories
JavaScript Nodejs

Node.js FS Module — Changing Ownership and Copying Files

Manipulating files and directories are basic operations for any program. Since Node.js is a server-side platform and can interact with the computer that it’s running on directly, being able to manipulate files is a basic feature.

Fortunately, Node.js has an fs module built into its library. It has many functions that can help with manipulating files and folders. File and directory operations that are supported include basic ones like manipulating and opening files in directories.

Likewise, it can do the same for files. It can do this both synchronously and asynchronously. It has an asynchronous API that has functions that support promises.

Also, it can show statistics for a file. Almost all file operations that we can think of can be done with the built-in fs module.

In this article, we will change ownership of a file with the chown function and copy files with the copyFile function.


Changing File Ownership With the fs.chown and fs.chownSync Functions

The chown function lets us change the ownership of a file asynchronously. It takes four arguments.

  1. The first argument is the path object which can be in the form of a string, a Buffer object, or a URL object.
  2. The second argument is the UID, which is the user ID of the user.
  3. The third argument is the GID, which is the group ID.
  4. The fourth argument is a callback function that has an err parameter which is null if the chown operation is successful, otherwise err will be an error object. The callback function is called when the chown operation is finished, whether it’s successful or not.

To use the chown function, we can write something like the following code:

In the example above, we change the ownership of the file file.txt to the user with UID 1000 and group with GID 1000. To find out the UID and GID of the user and group of the current user in Linux systems, we can use the id command.

The chown function has a synchronous version called chownSync. It takes three arguments.

  1. The first argument is the path object which can be in the form of a string, a Buffer object, or a URL object.
  2. The second argument is the UID, which is the user ID of the user.
  3. The third argument is the GID, which is the group ID. It returns undefined.

We can use it as in the following code:

const fs = require("fs");  
const file = "./files/file.txt";
fs.chownSync(file, 1000, 1000);  
console.log("File ownership changed");

It does the same thing as chown, but does it synchronously. If we just want to do the chown operation sequentially, we don’t have to use chown, a better alternative is to use the promise version of the chown function.

The promise version of the chown function takes three arguments.

  1. The first argument is the path object which can be in the form of a string, a Buffer object, or a URL object.
  2. The second argument is the UID, which is the user ID of the user.
  3. The third argument is the GID, which is the group ID. It returns a promise that resolves with no arguments when the chown operation is successfully done.

We can use it as in the following code:

To confirm that the chown worked as we expected, we can run the following commands in Linux systems. One way is to run ls -l , as in the command below:

ls -l ./files/file.txt

We can also use the stat command.

For example, we can run stat ./files/file.txt to get the ownership information of ./files/file.txt from the Uid and Gid output. With the stat command, we should get output that looks something like this:

File: './files/file.txt'  
  Size: 16              Blocks: 0          IO Block: 512    regular file  
Device: eh/14d  Inode: 22799473115106242  Links: 1  
Access: (0555/-r-xr-xr-x)  Uid: ( 1000/hauyeung)   Gid: ( 1000/hauyeung)  
Access: 2019-11-02 12:26:47.996290200 -0700  
Modify: 2019-11-02 12:26:47.996290200 -0700  
Change: 2019-11-02 12:44:45.037581600 -0700  
 Birth: -

Also, we can filter out the information we don’t need and just get the UID and GID with the "%U %G" format sequence. For example, we can run stat -c “%U %G” ./files/file.txt to get the UID and GID only for file.txt.


Copy Files With fs.copyFile and fs.copyFileSync

To copy files in a Node.js program, we can use the copyFile function. The copyfile function takes four arguments.

  1. The first argument is the path of the source file, which can be a string, a Buffer object, or a URL object.
  2. The second argument is the path of the destination file, which can also be a string, a Buffer object, or a URL object.
  3. The third argument is a numeric flag argument that specifies the behavior of the copy operation. The default value of the flag is 0.

The flag can be one of the following values or a bitwise combination of them:

  • fs.constants.COPYFILE_EXCL — The copy operation will fail if the destination file already exists.
  • fs.constants.COPYFILE_FICLONE — The copy operation will attempt to create a copy-on-write reflink. Copy-on-write means that if a file is copied but not modified then it will just reference the original file. The only time that it will do the actual copy is when we first write to a file. If the platform does not support copy-on-write, then a fallback copy mechanism is used.
  • fs.constants.COPYFILE_FICLONE_FORCE — The copy operation will attempt to create a copy-on-write reflink. If the platform does not support copy-on-write, then the operation will fail.

We can combine the constants above with the bitwise OR operator, for example like fs.constants.COPYFILE_EXCL | fs.constants.COPYFILE_FICLONE.

4. The fourth argument is a callback function that is called when the file copy operation is complete. It has an err parameter which is null when the copy file operation succeeded and an object with the error information otherwise.

There’s no guarantee of the atomicity of the copy operation. If an error occurs after the destination file is opened for writing, then Node.js will attempt to remove the destination.

By default, if no flags are set, the destination file will overwrite the existing file with the same name in the same location if it exists.

To use the copyFile function, we can write something like the following code:

In the code above, we set the source of the source file to be file.txt, the destination file to be fileCopy.txt.

Also, we specified that the copy operation will fail if the file exists with the fs.constants.COPYFILE_EXCL constant and we specify that the copy file operation will be done via the copy-on-write method with the fs.constants.COPYFILE_FICLONE flag.

The synchronous version of the copyFile function is the copyFileSync function. It takes the same arguments as the copyFile function except the callback.

  1. The first argument is the path of the source file, which can be a string, a Buffer object, or a URL object.
  2. The second argument is the path of the destination file, which can also be a string, a Buffer object, or a URL object.
  3. The third argument is a numeric flag argument that specifies the behavior of the copy operation. The default value of the flag is 0. The flags are the same ones as the copyFile function, and we can also combine them the same way.

There’s no guarantee of the atomicity of the copy operation. If an error occurs after the destination file is opened for writing, then Node.js will attempt to remove the destination.

By default, if no flags are set, the destination file will overwrite the existing file with the same name in the same location if it exists.

To use the copyFileSync function, we can write some code like the following example:

In the code above, we set the source of the source file to be file.txt, the destination file to be fileCopy.txt.

Also, we specified that the copy operation will fail if the file exists with the fs.constants.COPYFILE_EXCL constant and we specify that the copy file operation will be done via the copy-on-write method with the fs.constants.COPYFILE_FICLONE flag.

We catch any exceptions that are thrown by surrounding the code with the try...catch block.

There’s also a promise version of the copyFile function. It asynchronously copies the file from the source to the destination.

  1. The first argument is the path of the source file, which can be a string, a Buffer object, or a URL object.
  2. The second argument is the path of the destination file, which can also be a string, a Buffer object, or a URL object.
  3. The third argument is a numeric flag argument that specifies the behavior of the copy operation. The default value of the flag is 0. The flags are the same ones as the copyFile function, and we can combine them the same way.

There’s no guarantee of the atomicity of the copy operation. If an error occurs after the destination file is opened for writing, then Node.js will attempt to remove the destination.

By default, if no flags are set, the destination file will overwrite the existing file with the same name in the same location if it exists.

The promise version of copyFile resolves with no argument if the copy operation is successful.

We can use the promise of copyFile as in the following code:

In the code above, we set the source of the source file to be file.txt, the destination file to be fileCopy.txt.

Also, we specified that the copy operation will fail if the file exists with the fs.constants.COPYFILE_EXCL constant and we specify that the copy file operation will be done via the copy-on-write method with the fs.constants.COPYFILE_FICLONE flag.

We catch any exceptions that are thrown by using surround the code with the try...catch block.


Conclusion

With the chown function, we can change the ownership of a file. There are two asynchronous versions of the function, one is the regular asynchronous version and one is the promise version.

There’s also one synchronous version of the chown function, which is the chownSync function. They both change the owner by passing in the UID and GID of the user of your choice. UID is the user ID and GID is the group ID. We can copy files with the copyFile function.

There are two asynchronous versions of the copyFile function, one is the regular asynchronous version and one is the promise version.

There’s also a synchronous version of the copyFile function called the copyFileSync function. We can change how files are copied with flags that are available as constants in the fs module.

Categories
Express JavaScript Nodejs

Use body-parser Express Middleware to Parse Text and URL-Encoded Requests

By default, Express 4.x or later doesn’t come with anything to parse request bodies. Therefore, we need to add something to do this.

In this article, we’ll look at how to use the body-parser middleware to do this with text and URL-encoded request bodies.

Parsing Text Bodies

We can parse text request bodies with the text method. It supports automatic inflation of gzip and deflate encodings.

The parsed string will be set as the value of req.body.

It takes an optional option object with the following properties:

  • defaultCharset — specifies the default character set for the text content if it’s not specified in the Content-Type header. Defaults to utf-8.
  • inflate — compressed request bodies will be inflated when this is set to true . Otherwise, they’ll be rejected.
  • limit — controls the maximum request body size. If it’s number, then it’s measured in bytes. If it’s a string then it can be parsed into a number of bytes.
  • type — this is used to determine what media type it’ll parse. It can be a string, array of strings or a function. If it’s not a function, then it’s directly passed into the type-is library. Otherwise, the request is parsed if the data type the function is called with returns a truthy value
  • verify — this is a function with signature (req, res, buf, encoding), where buf is a Buffer object of the raw request body. The parsing can be aborted by throwing an error in the function.

For example, we can use it as follows:

const express = require('express');  
const bodyParser = require('body-parser');  
const app = express();  
const options = {  
  inflate: true,  
  limit: 1000,  
  defaultCharset: 'utf-8'  
};  
app.use(bodyParser.text(options));
app.post('/', (req, res) => {  
  res.send(req.body);  
});
app.listen(3000);

Then when we make a POST request to / with the body foo, we get foo back.

Parsing URL Encoded Request Bodies

We can use the urlencoded method to pares URL encoded bodies. It supports automatic inflation of gzip and deflate encodings.

The parsed request body will be set as the value of req.body. The object will contain key-value pairs, where the value can be a string or an array when extended is set to false or anything otherwise.

It takes an optional option object with the following properties:

  • extended — the extended option allows us to choose between parsing the URL-encoded data with the querystring library when false or the qs library when this is set to true . The extended syntax lets us encode rich objects and arrays, allowing for a JSON-like experience with URL-encoded. The default value is true, but using the default value has been deprecated.
  • inflate — compressed request bodies will be inflated when this is set to true. Otherwise, they’ll be rejected.
  • limit — controls the maximum request body size. If it’s number, then it’s measured in bytes. If it’s a string then it can be parsed into a number of bytes.
  • parameterLimit — lets us control the maximum number that are allowed in the URL encoded data. If it’s more than the given value then a 413 response code will be returned. The default is 1000.
  • type — this is used to determine what media type it’ll parse. It can be a string, array of strings or a function. If it’s not a function, then it’s directly passed into the type-is library. Otherwise, the request is parsed if the data type the function is called with returns a truthy value
  • verify — this is a function with signature (req, res, buf, encoding), where buf is a Buffer object of the raw request body. The parsing can be aborted by throwing an error in the function.

For example, we can use it as follows:

const express = require('express');  
const bodyParser = require('body-parser');  
const app = express();  
const options = {  
  inflate: true,  
  limit: 1000,  
  extended: true  
};  
app.use(bodyParser.urlencoded(options));
app.post('/', (req, res) => {  
  res.send(req.body);  
});
app.listen(3000);

Then when we send a URL encoded POST body to the / route with the body name=Mary&age=10, then we get:

{"name":"Mary","age":"10"}

We can send an array by sending:

name=Mary&age=10&favoriteFood=apple&favoriteFood=orange

Then we get back:

{"name":"Mary","age":"10","favoriteFood":["apple","orange"]}

as the response. This assumes that extends is true.

If we set the parameterLimit to 1 as follows:

const express = require('express');  
const bodyParser = require('body-parser');  
const app = express();  
const options = {  
  inflate: true,  
  limit: 1000,  
  extended: true,  
  parameterLimit: 1,  
};  
app.use(bodyParser.urlencoded(options));
app.post('/', (req, res) => {  
  res.send(req.body);  
});
app.listen(3000);

then we get a 413 error back.

Conclusion

With the text method, body-parser can parse text request bodies. We’ll get a string with the parsed body with req.body.

To parse URL-encoded request bodies, we can use the urlencoded method. It can parse arrays and objects. URL-encoded bodies are sent as query strings, and we can send a query with the same key multiple times to make it parsed as an array.