Using an expiry date in JavaScript to create self-destructing data
Tags: javascript, webdev, tutorial, react
Published: 2020-07-15 19:21:38

Let's say you've created a web application that, in addition to the rest of its functionality, presents a piece of information to a user that you'd like to only have a certain shelf life on the page. This could be any range of things, from personal information in a temporary note, to a "Quote of the Day" that should expire every evening at midnight, to data being pulled from a rate-limited external API.

There are multiple ways you could go about this as a developer, but a simple and interesting one is to give that piece of information an *expiry date*, upon which it will self-destruct back into the digital nether from whence it came.

This trick will explore a few different built-in functionalities within the JavaScript language, and will prove to be a versatile tool to modify or inspire other ideas in your applications later on.

***

For this tutorial, I'm going to use the context of an application I built with [React](https://reactjs.org/) that provides the user with a meditation timer, a focus/pomodoro timer, and a home and landing page featuring the date and time, local weather, and an inspiring quote of the day.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/5us6wf52s2amfbyzg13y.png)
<figcaption>Hosted at <a href="https://focus-timer.app/">https://focus-timer.app/</a></figcaption>

Within this home page, I knew that I wanted to pull in the quote from an external API automatically-- but I encountered an issue where the API was rate limited in order to preserve their bandwidth. I could only make a certain number of calls per hour before my app became temporarily restricted, and the quote disappeared from the page entirely (replace by an unsightly console error!)

I knew I could try and prevent this by only fetching the quote once a day on the server side, but I thought I would use the opportunity to experiment with keeping the fetch on the client side and experimenting with giving the data an expiry date on a visitor-by-visitor basis, as I knew that might benefit me in future applications.

***

Within this discussion we're going to be using two standardized functionalities of modern web development.

The first of which is an aspect of the Window containing the DOM document of the site:

```
Window.localStorage
```

And the second being a built in object of the JavaScript language:

```
Date()
```

[**localStorage**](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) is a property that gives you access to a [storage](https://developer.mozilla.org/en-US/docs/Web/API/Storage) object in the document that persists across browser sessions. It can be accessed through your JavaScript code or through the browser console directly.

[**Date()**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) is an object that represents a single point in time when it is created, measured in the number of milliseconds since January 1st 1970 UTC. This Date() object has a number of built in functions to manipulate it, one of which we'll be making use of in our example.

***

The bullet-pointed version of what I'm going to be showing is as follows:

1. When the home page is loaded, we check the user's localStorage to see if there's already a quote there that has been fetched.
 - If there *isn't* a quote, then we fetch a new quote from the API, save that quote to localStorage, and also run a function to save an expiry date/time along with it for when we want that quote to be replaced.
2. If there *is* a quote, then we compare the current date/time against the expiry date/time (in this case the expiry is the midnight of the same day that the quote was saved to localStorage).
 - If the current date/time is *before* the expiry date/time, then we pull the quote from localStorage and render it on the page.
 - If the current date/time is *after* the expiry date/time, then we clear the localStorage and go back to step 1 and fetch a new quote from the API.

Now let's see this in action in the code!

***

First off, I'm creating two helper functions that are abstracted out to keep the code clean and [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself).



The first is a function labeled *secondsToMidnight()* that takes in a **Date()** object as *n* and uses the object's built in functions *getHours()*, *getMinutes()*, and *getSeconds()* to find the amount of seconds until midnight of the same day as the **Date()** object. This might seem a bit confusing, but essentially this is the step that can be modified to find the amount of time anywhere in the future that you'd like to set as an expiry date for your data.

```javascript
const secondsToMidnight = (n) => {
    return (
      ((24 - n.getHours() - 1) * 60 * 60) + ((60 - n.getMinutes() - 1) * 60) + (60 - n.getSeconds())
    )
  }
```

***

The second helper function is labeled *assignQuoteToLocalStorage()*, which does 4 things:
1. Makes use of a fetch to the API (*getQuoteOfTheDay()*) to get a quote.
2. Creates a **Date()** object under the variable *currentTime* and does 3 things with it to create an expiry date/time:
 - Use the built in function *getTime()* to get the current time in milliseconds (the measurement of current time as a distance from January 1st 1970).
 - Passes the *currentTime* date object into the *secondsToMidnight()*, then multiplies that by 1000 to get the milliseconds until midnight.
 - Adds the two numbers together to get a future date/time in milliseconds that equals exactly midnight of the same day.
3. Sets both the quote and the expiry to localStorage as key/value pairs in the object.
4. Sets the quote to state in React to be rendered on the page (*setQuoteOfTheDay()*).

```javascript
const assignQuoteToLocalStorage = () => {
  getQuoteOfTheDay()
  .then( quote => {
    
    const currentTime = new Date()
    const expiry = currentTime.getTime() + (secondsToMidnight(currentTime) * 1000)
    
    localStorage.quote = JSON.stringify(quote)
    localStorage.expiry = expiry

    setQuoteOfTheDay(quote)
    
  })
}
```

***

Now we make use of both of the above helper methods to do the following in our component mounting (happening every time the page is loaded):

```javascript
if (!!localStorage.quote) {

  let quoteExpiry = parseInt(localStorage.getItem("expiry"))
  let now = new Date()

  if (now.getTime() > quoteExpiry) {

    localStorage.removeItem("quote")
    localStorage.removeItem("expiry")

    assignQuoteToLocalStorage()

  } else {

    let quote = JSON.parse(localStorage.getItem("quote"))
    setQuoteOfTheDay(quote)
    
  }

} else {

  assignQuoteToLocalStorage()

}
```

In our first *if* statement we're checking to see if there's a quote in the localStorage. If there is, we then pull the expiry date out of localStorage, create a new current **Date()** object, and compare the two.

We use a nested *if* statement to check if the current time is after the expiry time. If so, we remove both the quote and the expiry from our localStorage and call our helper function (*assignQuoteToLocalStorage()*) to fetch a new quote and create a new expiry for it. If the current time is still before the expiry, we pull the quote from localStorage and set it to our state for rendering on the page.

If our first *if* statement returned false and no quote was found in localStorage, then we call *assignQuoteToLocalStorage()* and fetch a new quote and assign it and an expiry date to localStorage.

***

And we're done! While this was all done in the specific context of my application, the same principles hold true anywhere.

You can use a trick like this with JavaScript **Date()** objects and their associated functions to save expiry times to localStorage or to your database in whatever format you'd like, to create self-destructing pieces of data.

Thanks for reading! Let me know in the comments if you have any questions or suggestions.