> ## Content Index
> Fetch the complete content index at: https://tomblanchard.co.uk/llms.txt
> Use this file to discover other available public pages before exploring further.

# Storing instances in Express sessions
- URL: https://tomblanchard.co.uk/storing-instances-in-express-sessions/
- Published: 2018-06-11T15:38:03.000Z
- Updated: 2018-06-11T15:38:26.000Z
- Author: Tom Blanchard
- Tags: #Import 2026-10-26 21:01

When developing apps with Express, at some point you'll probably need to store user data across different requests, that's where sessions come in. I was using [express-session](https://github.com/expressjs/session?ref=tomblanchard.co.uk) when I came across an issue, I needed to store [Shopify-api-node](https://github.com/MONEI/Shopify-api-node?ref=tomblanchard.co.uk) instances across sessions.

This is how the app was structured at first:

```javascript
// entry-index.js

var express = require("express");
var session = require("express-session");
var RedisStore = require("connect-redis")(session);

var middlewareShopify = require("./middleware-shopify");
var routerRoutes = require("./router-routes");

var app = express();
var appPort = process.env.PORT || 3000;

app.use(session({
  store: new RedisStore({ host: "localhost", port: 6379, ttl: 260 }),
  secret: "gu2cQL7z2z4pKypm",
  resave: false,
  saveUninitialized: true
}));

app.use(middlewareShopify);
app.use(routerRoutes);

app.listen(appPort, () => {
  console.log(`App listening on port ${appPort}!`);
});

```

```javascript
// middleware-shopify.js

module.exports = (req, res, next) => {
  if( !req.session.shopName || !req.session.apiKey || !req.session.password ) {
    req.session.shopName = req.query.shopName;
    req.session.apiKey = req.query.apiKey;
    req.session.password = req.query.password;
  }

  var { shopName, apiKey, password }  = req.session;

  if( !shopName || !apiKey || !password ) {
    return res.status(500).send("Something broke.");
  }

  return next();
};

```

```javascript
// routes-routes.js

var express = require("express");

var Shopify = require("shopify-api-node");

var router = express.Router();

router.get("/", (req, res) => {
  var { shopName, apiKey, password }  = req.session;

  var shopify = new Shopify({
    shopName,
    apiKey,
    password,
    autoLimit: true
  });

  shopify.shop.get()
    .then((shop) => {
      return res.send(JSON.stringify(shop));
    })
    .catch((err) => {
      return res.status(500).send("Something broke.");
    });
});

router.get("/other-route", (req, res) => {
  var { shopName, apiKey, password }  = req.session;

  var shopify = new Shopify({
    shopName,
    apiKey,
    password,
    autoLimit: true
  });

  shopify.shop.get()
    .then((shop) => {
      return res.send(JSON.stringify(shop));
    })
    .catch(() => {
      return res.status(500).send("Something broke.");
    });
});

module.exports = router;

```

This works like so:

1. Visit the URL: [https://localhost:3000](https://localhost:3000/?ref=tomblanchard.co.uk) and you'll get an error due to the lack of required query parameters (`shopName`, `apiKey` and `password`).
2. Visit a URL like: [http://localhost:3000/?shopName=your-shop-name&apiKey=your-api-key&password=your-app-password](http://localhost:3000/?shopName=your-shop-name&apiKey=your-api-key&password=your-app-password&ref=tomblanchard.co.uk) and you'll see data displayed from an API call to the `your-shop-name` shop.
3. The query parameters are now saved to your session, so you can now visit routes without the query parameters and it'll still work.

This is great and *almost* works exactly how I want, but there's one issue; every route defines a new `Shopify` instance. If you take a look at the [Shopify-api-node](https://github.com/MONEI/Shopify-api-node?ref=tomblanchard.co.uk) documentation, you'll see it provides a `autoLimit` option, this is a simple way around hitting the [Shopify API call limit](https://help.shopify.com/api/getting-started/api-call-limit?ref=tomblanchard.co.uk). The only catch is that for `autoLimit` to work properly, there needs to be just *one* `Shopify` instance per shop.

My first thought was to setup the `Shopify` instance in the `middleware-shopify` middleware, like this:

```javascript
// middleware-shopify.js

var Shopify = require("shopify-api-node");

module.exports = (req, res, next) => {
  if( !req.session.shopName || !req.session.apiKey || !req.session.password ) {
    req.session.shopName = req.query.shopName;
    req.session.apiKey = req.query.apiKey;
    req.session.password = req.query.password;
  }

  var { shopName, apiKey, password }  = req.session;

  if( !shopName || !apiKey || !password ) {
    return res.status(500).send("Something broke.");
  }

  if( !req.session.shopify ) {
    req.session.shopify = new Shopify({
      shopName,
      apiKey,
      password,
      autoLimit: true
    });
  }

  return next();
};

```

Then in my `router-routes.js` router, I could use it like this:

```javascript
router.get("/", (req, res) => {
  var { shopify }  = req.session;

  shopify.shop.get()
    .then((shop) => {
      return res.send(JSON.stringify(shop));
    })
    .catch((err) => {
      return res.status(500).send("Something broke.");
    });
});

```

This doesn't work because you can only store JSON-serializable data in `req.session`, instances can't be serialized. What I ended up doing was creating a session/`Shopify` instance map, each session gets it's own `Shopify` instance, identified via the `session.id`. I started off by creating a new `object-shopifys.js` file which exports an empty object:

```
// object-shopifys.js

module.exports = {};

```

I then changed the `middleware-shopify` middleware, like this:

```javascript
// middleware-shopify.js

var Shopify = require("shopify-api-node");

var shopifys = require("./object-shopifys");

module.exports = (req, res, next) => {
  if( !req.session.shopName || !req.session.apiKey || !req.session.password ) {
    req.session.shopName = req.query.shopName;
    req.session.apiKey = req.query.apiKey;
    req.session.password = req.query.password;
  }

  var { shopName, apiKey, password }  = req.session;

  if( !shopName || !apiKey || !password ) {
    return res.status(500).send("Something broke.");
  }

  if( !shopifys[req.session.id] ) {
    shopifys[req.session.id] = new Shopify({
      shopName,
      apiKey,
      password,
      autoLimit: true
    });
  }

  return next();
};

```

By default, the `shopifys` object is empty, but after the middleware has executed for the first time of the users session, it'll look like:

```javascript
// `Shopify...` refers to the actual instance, I left it out
// due to brevity.
{
  "Xur_jku_V-pUfwu3tuNtAqEydp8CTxbK": Shopify...
}

```

I then changed the router to reference the new `shopifys` object:

```javascript
// router-routes.js

var express = require("express");

var shopifys = require("./object-shopifys");

var router = express.Router();

router.get("/", (req, res) => {
  var shopify = shopifys[req.session.id];

  shopify.shop.get()
    .then((shop) => {
      return res.send(JSON.stringify(shop));
    })
    .catch((err) => {
      return res.status(500).send("Something broke.");
    });
});

router.get("/other-route", (req, res) => {
  var shopify = shopifys[req.session.id];

  shopify.shop.get()
    .then((shop) => {
      return res.send(JSON.stringify(shop));
    })
    .catch(() => {
      return res.status(500).send("Something broke.");
    });
});

module.exports = router;

```

There we go, each session gets one `Shopify` instance and we don't have to worry about hitting the API call limit if we navigate to multiple API-heavy routes at the same time.

One thing we do have to worry about is a potential memory leak. Over time the `shopifys` object will build up and get larger. A simple solution would be to setup a cron-job which periodically checks the session IDs in the `shopifys` map and compares them to the redis `sess:*` keys, if the key no longer exists in redis, then remove it from the `shopifys` map.

I'd like to thank [Luigi Pinca](https://github.com/lpinca?ref=tomblanchard.co.uk) (the main contributer of the [Shopify-api-node module](https://github.com/MONEI/Shopify-api-node?ref=tomblanchard.co.uk)) for walking me through this on a [GitHub issue](https://github.com/MONEI/Shopify-api-node/issues/191?ref=tomblanchard.co.uk) I opened.