Categories
Express JavaScript Nodejs

Use body-parser Express Middleware to Parse JSON and Raw 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 JSON and raw bodies.

Adding the Body-Parser Package

body-parser is a Node package that we can add onto our Express app to parse request bodies.

It doesn’t support multipart bodies, so we have to use other middleware packages to parse those.

However, it can parse JSON bodies, raw request bodies, text, and URL-encoded bodies.

To install the package, we run:

npm install body-parser

Then we can include by adding:

const bodyParser = require('body-parser');

Parsing JSON Bodies

We can parse JSON bodies by calling the JSON method. It takes an optional object with a few properties.

The options include:

  • 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.
  • reviver — this is a function that’s passed into JSON.parse as the second argument to map values to what we want
  • strict — only accepts objects and arrays when set to true . Otherwise, it’ll accept anything that JSON.parse accepts. Defaults to true .
  • 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,  
  reviver: (key, value) => {  
    if (key === 'age') {  
      if (value < 50) {  
        return 'young'  
      }  
      else {  
        return 'old';  
      }  
    }  
    else {  
      return value;  
    }  
  }  
};  
app.use(bodyParser.json(options));
app.post('/', (req, res) => {  
  res.send(req.body);  
});
app.listen(3000);

Then when we make a POST request to / , we get back:

{  
    "name": "foo",  
    "age": "young"  
}

as the response since we check the age field in the reviver function and return 'young' or 'old' depending on the value . Otherwise, we return the value as-is.

The request body is parsed and set as the value of req.body .

Parsing Raw Bodies

We can parse raw bodies as a buffer. It supports the automatic inflation of gzip and deflate encodings.

The parsed body containing the parsed data is populated on the request object, i.e. it’ll be set as the value of req.body .

It takes an optional option object that can take the following properties:

  • 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,  
  type: 'text/plain'  
};  
app.use(bodyParser.raw(options));
app.post('/', (req, res) => {  
  res.send(req.body);  
});
app.listen(3000);

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

This is because we specified text/plain as the type to parse the raw data.

It also smart enough to parse multiple body types. We can do that by passing in an array of type strings as follows:

const express = require('express');  
const bodyParser = require('body-parser');  
const app = express();  
const options = {  
  inflate: true,  
  limit: 1000,  
  type: ['text/plain', 'text/html']  
};  
app.use(bodyParser.raw(options));
app.post('/', (req, res) => {  
  res.send(req.body);  
});
app.listen(3000);

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

Conclusion

We can use the body-parser middleware to parse JSON and raw text bodies.

It also takes a variety of options to let us control whether to inflate compressed request bodies, map JSON values to something else, limit the size of a request body, and so on.

For raw request bodies, we can use body-parser to specify the type that the data is so we can parse it to that type of object and set it to req.body .

Categories
Express JavaScript

Guide to the Express Application Object — Routing

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

In this piece, we’ll look at the methods of the app object and what we can do with it.


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

This method routes an HTTP request. METHOD is a placeholder for various routing methods that Express supports.

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.

The following routing methods are supported by Express:

  • checkout
  • copy
  • delete
  • get
  • head
  • lock
  • merge
  • mkactivity
  • mkcol
  • move
  • m-search
  • notify
  • options
  • patch
  • post
  • purge
  • put
  • report
  • search
  • subscribe
  • trace
  • unlock
  • unsubscribe

All methods take the same arguments and work exactly the same way. So app.get and app.unlock are the same.


app.param([name], callback)

app.param adds callback triggers for route parameters. name is the parameter or an array of them. callback is a callback function.

The parameters of the callback are the request object, response object, next middleware function, the value of the parameter, and the name of the parameter in the given order.

For example, we can use it as follows:

The code above will get the id URL parameter when it exists with the app.param callback.

Then in the callback, we get id to req.id and call next to call our route handler in app.get.

Then we call res.send(req.id); to send the response with req.id, which we set earlier.

Note that id in app.param has to match :id with the route handlers.

We can pass in an array of parameters that we want to watch for:

Then if we make a request for /1/foo, we’ll get 1 and foo one at a time as the value of the value parameter.


app.path()

app.path returns the path of mounted apps as a string.

For example, we can use it as follows:

Then we get '' for app.path(), '/foo' for foo.path(), and '/foo/bar' for bar.path() since we mounted foo to app and bar to foo.

<img class="s t u hh ai" src="https://miro.medium.com/max/6438/0*hC4qa3eKTWD_g_hs" width="3219" height="4836" srcSet="https://miro.medium.com/max/552/0*hC4qa3eKTWD_g_hs 276w, https://miro.medium.com/max/1104/0*hC4qa3eKTWD_g_hs 552w, https://miro.medium.com/max/1280/0*hC4qa3eKTWD_g_hs 640w, https://miro.medium.com/max/1400/0*hC4qa3eKTWD_g_hs 700w" sizes="700px" role="presentation"/>

Photo by Bundo Kim on Unsplash.


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

We can use the app.post method to handle POST requests with the given path by passing in a callback route handler.

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.

For example, we can use it as follows:

Then when we make a POST request with a client like Postman, we should see “POST request made.”


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

We can use the app.put method to handle PUT requests with the given path by passing in a callback route handler.

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.

For example, we can use it as follows:

Then when we make a PUT request with a client like Postman, we should see “PUT request made.”


Conclusion

We can intercept the parameters sent from requests with the app.params method.

To listen to POST requests, we can use the app.post method. To listen to PUT requests, we can use the app.put method.

app.path lets us get the path of mounted apps.

app also has a long list of methods for listening to all kinds of requests.

Categories
Express JavaScript Nodejs

To store sessions in our Express apps, we can use the cookie-session middleware.

It’s a cookie-based session middleware that stores user sessions on the client within a cookie.

In this article, we’ll look at how to store sessions within an Express app with the cookie-session middleware.

How Cookie-Session Stores Sessions?

cookie-session doesn’t require any database or other server-side resources to store sessions. The session data can’t exceed the browser’s max cookie side.

It can also simplify certain load-balanced scenarios. It can also store a light session and include an identifier to look up a database-backed secondary store to reduce database lookups.

Adding the Library

We can install cookie-session by running:

npm i cookie-session

Then we can use it as follows:

const cookieSession = require('cookie-session')  
const express = require('express')  
  
const app = express()  
  
app.use(cookieSession({  
  name: 'session',  
  keys: 'secret',  
  maxAge: 24 * 60 * 60 * 1000  
}))

Options

The cookie-session middleware lets us pass in an options object with various properties to set the value.

This middleware will automatically add a Set-Cookie header to the response if the contents of the req.session were altered.

The Set-Cookie header won’t be in the response unless there are contents in the session, so we should add something to req.session as soon as we have identifying information to store the session.

The following options are available:

name

Name of the cookie to be set and defaults to session .

keys

The list of keys to sign and verify cookie values, or a Keygrip instance. Set cookies are always signed with keys[0] , and other keys are valid for verification.

This allows for key rotation. It can be used to change signature parameters like the algorithm of the signature.

secret

The string will be used as a single key if keys isn’t provided.

Cookie Options

The cookie object within the options have the following properties:

  • maxAge — a number of milliseconds from Date.now() for expiry
  • expires — a Date object indicating the cookie’s expiration date
  • path — a string indicating the path of the cookie, which defaults to /
  • domain — a sting indication the domain of the cookie
  • sameSite — boolean or string indicating whether the cookie is a ‘same site’ cookie. The default value is false , 'strict' , 'lax' or true are other possible values
  • secure — boolean indicating whether the cookie is only sent over HTTPS. If this is true and communication isn’t through TLS, then the cookie may not be set correctly
  • httpOnly — boolean indicating whether the cookie is sent over HTTP(S) and not available to client JavaScript
  • signed — boolean indicating whether the cookie is signed. Default value is true . If it’s true , then the cookie is appended with a .sig suffix.
  • overwrite — boolean indicating whether to overwrite previously set cookies of the same name

req.session

req.session holds the session for the given request.

.isChanged

A method that returns trie is the session has been changed during the request.

.isNew

A method that returns true if the session is new.

.isPopulated

A method that returns true is the session has been populated with data.

req.sessionOptions

We can set the sessionOptions object to change cookie settings.

Destroying a Session

We can set req.session to null to destroy a session.

Example

We can track the number of views a user made as follows:

const express = require('express');  
const bodyParser = require('body-parser');  
const cookieSession = require('cookie-session');  
const app = express();  
app.set('trust proxy', 1);  
app.use(cookieSession({  
  name: 'session',  
  keys: ['key1', 'key2']  
}))
app.get('/', (req, res, next) => {  
  req.session.numViews = (req.session.numViews || 0) + 1  
  res.end(`${req.session.numViews} views`);  
})
app.listen(3000);

In the code above, we just set req.session with the properties that we want to add and set the values the way we want.

The numViews property is added to track the number of views and increments as more request to the / is made.

Setting Max Age

We can set the maxAge as follows:

const express = require('express');  
const bodyParser = require('body-parser');  
const cookieSession = require('cookie-session');  
const app = express();  
app.set('trust proxy', 1);  
app.use(cookieSession({  
  name: 'session',  
  keys: ['key1', 'key2'],  
  maxAge: 1000,  
}))
app.use((req, res, next) => {  
  req.sessionOptions.maxAge = req.session.maxAge || req.sessionOptions.maxAge  
  next()  
})
app.get('/', (req, res, next) => {  
  req.session.numViews = (req.session.numViews || 0) + 1  
  res.end(`${req.session.numViews} views`);  
})
app.listen(3000);

We set maxAge to 1000 milliseconds above, then we’ll see that the values reset to 1 as the session expires.

In both cases, the Set-Cookie response header will be set as the session is set for the client.

We have multiple keys with the first one for encryption and the second one for verification.

Keygrip Integration

We can use keygrip as follows for encrypting our sessions:

const express = require('express');  
const bodyParser = require('body-parser');  
const cookieSession = require('cookie-session');  
const Keygrip = require('keygrip');  
const app = express();  
app.set('trust proxy', 1);  
app.use(cookieSession({  
  name: 'session',  
  keys: new Keygrip(['key1', 'key2'], 'SHA384'),  
  maxAge: 60 * 60 * 1000,  
}))
app.use((req, res, next) => {  
  req.sessionOptions.maxAge = req.session.maxAge || req.sessionOptions.maxAge  
  next()  
})
app.get('/', (req, res, next) => {  
  req.session.numViews = (req.session.numViews || 0) + 1  
  res.end(`${req.session.numViews} views`);  
})
app.listen(3000);

In the code above, we set the encryption algorithm to SHA384 for secure encryption.

Conclusion

The cookie-session lets us store sessions securely. We can use it to store identifying information about a user securely by encrypting the content with keys.

Then we can get and set the data via req.session .

Various options are also available for sessions. We can set maxAge to set when the session expires.

We can use domain , path , sameSite , secure , and httpOnly to control what kind of domain and path to set in our cookies, and also set what sites the cookies will be set for.

cookie-session also works with Keygrip for encryption.

Categories
Express JavaScript

Guide to the Express Application Object — Rendering and Setting

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 rendering HTML and changing settings.

app.render(view, [locals], callback)

We can use the app.render method to render HTML of a view via its callback function. It takes an optional parameter that’s an object containing variables for the view.

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.engine('ejs', require('ejs').renderFile);  
app.set('view engine', 'ejs');
app.render('index', { people: ['geddy', 'neil', 'alex'] }, (err, html) => {  
  console.log(html);  
});
app.listen(3000);

Then if we have the following in views/index.ejs :

<%= people.join(", "); %>

Then we get:

geddy, neil, alex

outputted from console.log(html);

app.route(path)

We can use app.route to define route handlers with the given path .

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.route('/')  
  .get((req, res, next) => {  
    res.send('GET request called');  
  })  
  .post((req, res, next) => {  
    res.send('POST request called');  
  })  
  .all((req, res, next) => {  
    res.send('Other requests called');  
  })app.listen(3000);

Then when a GET request is made to / , we get GET request called . If a POST request is made to / , then we get POST request called .

Any other kind of requests to / will get us Other requests called .

The order matters since all will handle all kinds of requests. So if we want to listen to specific kinds of requests in addition to other kinds of requests, all should come last.

app.set(name, value)

We can use set to set the setting with the given name to the given value .

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.set('title', 'Foo');
app.get('/', (req, res) => {  
  res.send(app.get('title'));  
})
app.listen(3000);

Since we called app.set(‘title’, ‘Foo’); to set the title setting to Foo we should see Foo displayed when we make a GET request to / .

Some settings are special for Express. They include:

  • case sensitive routing — boolean value for enabling or disabling case sensitive routing (e.g. /Foo will be considered different from /foo if this is true )
  • env — string for the environment mode
  • etag — ETag response header
  • jsonp callback name — string for the JSONP callback name
  • json escape — boolean option to enable or disable escaping JSON response from res.json , res.jsonp or res.send . <, >, and & will be escaped if this is true
  • json replacer — replace callback for JSON.stringify
  • json spaces — spaces argument for JSON.stringify
  • query parser — disable query parsing if set to false , or set the query parse to use either 'simple' or 'extended' or a custom query string parsing function.
  • strict routing — boolean setting for enabling/disabling strict routing. If this is true , then /foo will be considered different from /foo/
  • subdomain offset — number of dot-separated parts of the host to remove to access subdomain. Defaults to 2.
  • trust proxy — indicates that the app is behind a proxy is it’s true . The X-Forwarded-* headers will determine the connection and IP address of the client.
  • views — string or array of directories to look for view templates. If it’s an array, then the views will be searched in the order they’re listed
  • view cache — boolean to enable view template compilation caching
  • view engine — string for setting view engine for rendering templates.
  • x-powered-by — enable 'X-Powered-By: Express HTTP header

Options for `trust proxy` setting

It can take on the following options:

  • true — client’s IP address is understood to be the leftmost entry of the X-Forwarded-* header
  • false — the app is assumed to be directly facing the Internet
  • String, comma-separated strings, or array of strings — one or more subnets or IP address to trust
  • Number — trust the nth hop from the front-facing proxy server as the client.
  • Function — custom trust implementation

Options for etag setting

It can take on the following options:

  • Boolean — true enables weak ETag, false disables ETag
  • String — 'strong' enables strong ETag, ‘weak’ enables weak ETag
  • Function — custom implementation.

Conclusion

We can render an HTML string with the app.render method. It takes a view file name, an object for variables and a callback with the html parameter to get the HTML rendered.

app.route lets us define route handlers.

app.set lets us set the options we want for our app. Some settings are special for Express and will be processed by it if they’re set.

Categories
Express JavaScript Nodejs

Guide to the Express Router Object — Multiple Requests and Middleware

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 route and use.

Methods

router.route(path)

We can use router.route to handle multiple kinds of requests with one chain of function calls.

For example, we can use it as follows:

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

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

We can also write something like:

const express = require('express');  
const bodyParser = require('body-parser');
const app = express();  
const router = express.Router();
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
router.route('/')  
  .all((req, res, next) => {  
    console.log('all requests');  
    next();  
  })  
  .get((req, res, next) => {  
    console.log('get request');  
    res.send('foo');  
    next();  
  })  
  .put((req, res, next) => {  
    console.log('put request');  
    res.send('put');  
    next();  
  })  
  .post((req, res, next) => {  
    console.log('post request');  
    res.send('post');  
    next();  
  })  
  .delete((req, res, next) => {  
    console.log('delete request');  
    res.send('delete');  
    next();  
  })
app.use('/foo', router);  
app.listen(3000);

Then when a GET, POST, PUT or DELETE requests are made to /foo, then we get the corresponding response.

The middleware ordering is based on when the route is created and not when the handlers are added to the route.

router.use([path], [function, …] function)

The router.use method lets us add one or more middleware functions with an optional mount path, which defaults to /.

It’s similar to app.use, except it’s applied to the router object instead of the whole app.

For example, if we have:

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

Then we get router middleware called when we make a GET request to the /foo path since we’re going through the router middleware to do that.

On the other hand, if we make a GET request to /, we don’t get that message logged since we aren’t using the router object to handle that request.

This means that attaching a middleware to the router object let us do something before a route that’s handled router object is handled.

We can also chain multiple middlewares as comma-separated list of middlewares, an array of middlewares or both together.

For example, we can write:

const express = require('express');  
const bodyParser = require('body-parser');
const app = express();  
const router = express.Router();
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
const mw1 = (req, res, next) => {  
  console.log('mw1 called');  
  next();  
}
const mw2 = (req, res, next) => {  
  console.log('mw2 called');  
  next();  
}
const mw3 = (req, res, next) => {  
  console.log('mw3 called');  
  next();  
}
router.use([mw1, mw2], mw3);
router.get('/', (req, res) => {  
  res.send('foo');  
})
app.use('/foo', router);  
app.listen(3000);

Then all 3 middlewares, mw1 , mw2 , and mw3 all get run, so we get:

mw1 called  
mw2 called  
mw3 called

logged if we make a GET request to /foo .

We can also specify a path for the middleware. If it’s specified, then only request made to the specified path is handled.

For example, if we have:

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

Then when a GET request is made to /foo/bar , then our middleware is called, so we get middleware called in this case.

If we make a GET request to /foo , then our middleware doesn’t get called.

We can also pass in a pattern or regex for the path that we pass into use .

For example, we can write:

const express = require('express');  
const bodyParser = require('body-parser');
const app = express();  
const router = express.Router();
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
router.use('/ab?c', (req, res, next) => {  
  console.log('middlware called');  
  next();  
});
router.get('/ab?c', (req, res) => {  
  res.send('bar');  
})
app.use('/foo', router);  
app.listen(3000);

Then when we make a GET request to /foo/abc , we get middleware called logged. We get the same result with /foo/ac .

We can pass in a regex as the path as follows:

const express = require('express');  
const bodyParser = require('body-parser');
const app = express();  
const router = express.Router();
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
router.use('/a(bc)?$', (req, res, next) => {  
  console.log('middlware called');  
  next();  
});
router.get('/a(bc)?$', (req, res) => {  
  res.send('bar');  
})
app.use('/foo', router);  
app.listen(3000);

Then when we make a GET request to /foo/abc or /foo/a , we get middleware called logged.

Conclusion

We can handle multiple kinds of requests in a router object with the route method. It lets us chain a series of method calls and pass in route handlers for each kind of request.

With the use method, we can pass in middleware that only applies to routes handled by the router object. Any other route won’t invoke the middleware.

We can pass in a string or regex path to the use method to only handle requests that are made to certain paths.