Express: passing dates in an URL using route parameters including regex validation

Showing an elegant way on passing dates to your REST API’s and webservices using Express route parameters and regex validation standard features.

When implementing RESTful API’s or other webservices in NodeJS with Express you will sooner or later come to the point where you need to pass dates as parameters. Something like YYYY-MM-DD. This article provides a way how to do that getting the most out of Express standard features.

Query strings and route parameters quick intro

For this showcase let’s assume you want to write an API with a GET route /valueofday on localhost:3000. This route needs to receive a specific day as an input parameter to serve the values for this day.

To pass a date value to your Express application you have two possibilities in general:

  • Passing as an query string parameter:
    http://localhost:3000/valueofday?day=20220210
  • Passing as an URL route parameter:
    http://localhost:3000/valueofday/20220210

If you pass the required date as an query string like that, it would be available through a variable req.query.day in the request handler.

Although this is an easy way of grabbing the value ‘20220210’ you should keep in mind that it is a completely unchecked string value that is returned. So every post-processing that is needed to create a date like splitting the string, validating if numbers were passed, casting to numbers etc. is completely up to you.

This would bloat your API’s with a lot of boilerplate code having no business value. In this article you will see how to use out-of-the-box Express features to…

  • Separate the passed values for year, month and day
  • Ensure that only valid numbers are passed

…without the need of any own-written code. This helps keeping your REST API’s and webservices clean and robust. So let’s go for it.

Exploring Express route parameters features

Recognizing that query strings would be a sub-optimal solution let’s go ahead with route parameters in Express. To pass a day value to our route, we would naively specifiy it like so:

app.get("/valueofday/:day", (req, res) => {
    // logic goes here...
});

With that, Express will make the last URL portion available as req.params.day. Anyways, this is not any better then using a query string as it still returns an unchecked arbitrary string we expect to be in the form of YYYY-MM-DD.

Fortunately, Express has some nice out-of-the box features for route parameters we can use to optimize that.

Route parameter separators

First, we’ll use the Express parameters separation feature. To construct a JavaScript date object, we’ll need the values for YYYY, MM and DD separately. Here, Express can do the work for us by using the allowed '-' or '.' route parameter separators, like so:

app.get("/valueofday/:year-:month-:day", (req, res) => {
  // logic goes here...
});

This will give us three variables req.params.year, req.params.month and req.params.day instead of one. E.g. when calling http://localhost:3000/valueofday/2022-04-11 the params would be year=”2022″, month=”04″ and day=”11″. So far, so good!

But the returned variables are still of arbitrary value. So how to ensure that only numbers are passed?

Regex validation for route parameters

To check the passed URL route parameters, we will make use of the regex parameter validation Express offers. For every route parameter you can add a regular expression (in brackets) which it should be validated against. For our showcase, let’s use trivial regular expressions to ensure that only numbers of cerrect length can be passed, like so:

app.get("/valueofday/:year(\\d{4})-:month(\\d{2})-:day(\\d{2})", (req, res) => {
  // logic goes here...
});

This will make Express to ensure that req.params.year is a four digit number and req.params.month and req.params.day are two digit numbers. Of course you can use much more sophisticated regexes in your solution to do any tighter checks. This is just to get you an idea of how this feature works.

Putting it all together: passing a date to an Express API

Having our YYYY-MM-DD values separated in req.params and also ensured we’ll only get passed numbers, we can now easily create our JavaScript date object in the request handler for further processing. Most easy way is to use the unary + operator here to convert everything to a number.

app.get("/valueofday/:year(\\d{4})-:month(\\d{2})-:day(\\d{2})", (req, res) => {
  let queryDate = new Date(
    +req.params.year,
    +req.params.month - 1,
    +req.params.day
  );
  // logic using queryDate goes here...
});

Please note the “-1” here for the month value as the JavaScript date constructor treats this as an index value with a range of 0..11.

That’s it. We are now able to pass a date value to an Express API without the need of any boilerplate code.

Testing the solution

For testing purposes we’ll put together a minimal working Express solution with a catch-all route indicating any miss of our date-passing route.

var express = require("express");
var app = express();

app.get("/valueofday/:year(\\d{4})-:month(\\d{2})-:day(\\d{2})", (req, res) => {
  res.status(200).json({
      queryDate: new Date(
          +req.params.year,
          +req.params.month - 1,
          +req.params.day
      )
  });
});

app.get('*', (req, res) => {
  res.status(404).send('Non-existing route');
});

app.listen(3000);

Now let’s use curl to fire some requests and check the result…

$ curl -w "\n" localhost:3000/valueofday/2022-01-11
{"queryDate":"2022-01-11T00:00:00.000Z"}

$ curl -w "\n" localhost:3000/valueofday/2022-01-1
Non-existing route

$ curl -w "\n" localhost:3000/valueofday/1999-03-11
{"queryDate":"1999-03-11T00:00:00.000Z"}

$ curl -w "\n" localhost:3000/valueofday/1999-03-111
Non-existing route

$ curl -w "\n" localhost:3000/valueofday/1999-03.11
Non-existing route

$ curl -w "\n" localhost:3000/valueofday/1999-03-10
{"queryDate":"1999-03-10T00:00:00.000Z"}

$ curl -w "\n" localhost:3000/valueofday/abcd
Non-existing route

$ curl -w "\n" localhost:3000/valueofday/
Non-existing route

Try it out

Here is the full example code in a CodeSandbox for trying out…

Happy coding 🙂

Useful links