# The write-through pattern

Welcome back, this is part 4 of the "caching patterns with Redis" series. Click [**here**](https://blog.kariukigeorge.me/the-cache-aside-pattern) to get to the third part.

A write-through cache reverses the order of how the cache is populated. Instead of lazy-loading the data in the cache after a cache miss like in the [cache-aside pattern](https://blog.kariukigeorge.me/the-cache-aside-pattern), the cache is proactively updated immediately following the primary database update. To see how this pattern functions, consider the image below.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1692701580964/1dba43ef-0265-4e1c-95f1-cb0a1bca96d0.png align="center")

1. The application, batch, or backend process updates the primary database.
    
2. Immediately afterwards, the data is also updated in the cache.
    
3. Return a response to the mutator.
    

This approach has the following advantages:

1. The cache is always in sync with the database thus no stale data will be sent to the client.
    

A disadvantage to the write-through pattern is that the request needs to wait for the cache to be updated thus increasing the response time.

Let's see how we can use the write-through pattern in our posts application. Since we are using JWT tokens for our auth, there is a need to add expiration logic since the tokens don't expire. For our case, we can have a JWT versioning. When the user logs out, we'll increment the JWT version by one.

```typescript
export const logout = async ({ email }: IUser) => {
  // Update the JWT version in the db
  const user = await db.users.update({
    where: { email },
    data: { jwtVersion: { increment: 1 } },
    select: { email: true, name: true, id: true, jwtVersion: true },
  });
  // Update the user in Redis
  await redis.set("user-" + email, JSON.stringify(user));
  // Return success
  return true;
};

// Our router will look like this
router.post("/logout", async (req, res, next) => {
  try {
    const data = await logout(req.user);
    res.json(data);
  } catch (error) {
    next(error);
  }
});

// Updated authMiddleware to check for expiration
export const authMiddleware = async (
  req: Request,
  _res: Response,
  next: NextFunction
) => {
  try {
    // Auth token in passed in aid header
    const aid = req.headers["aid"] as string;
    if (!aid) {
      throw new Error("Auth token has not been provided");
    }
    // Verify the JWT
    const payload: IUser = verify(aid, process.env.JWT_SECRET as string, {
      issuer: "Caching-Code-Login",
      audience: "Caching-Code-Auth",
    }) as IUser;

    // Get the user using the email
    const user = await getUserByEmail(payload.email);

    // Verify the token version
    if (payload.jwtVersion !== user?.jwtVersion) {
      throw new Error("Expired auth token provided");
    }

    if (!user) {
      throw new Error("Authentication failed");
    }

    // Attach a user to the request
    req.user = user;

    //  Successfully authenticated. Call the next handler.
    next();
  } catch (error) {
    next(error);
  }
};
```

Thank you for reading this far, I hope you are liking it. Feel free to comment on your thoughts and jump into the [**next**](https://blog.kariukigeorge.me/the-write-behind-pattern) blog in the series.
