Django CORS headers – You want to use ‘Cache-Control’

I was happily writing React app, and at one point, I realized I have to not have any cache at all to access Django API. So, I added,

headers: { "cache-control": "no-store" }

Then, Django API complains. I knew I already set up CORS middleware so I thought I am all set. For development, Django/React are being developed and need to do a bit of HTTP dance so I disabled the CORS check, I thought.
Long sotry short, as I read the code, what React app is complaining is that the “cache-control” is not part of approved headers.
Take a look at "site-packages/corsheaders/conf.py"

class Settings:
    """
    Shadow Django's settings with a little logic
    """

    @property
    def CORS_ALLOW_HEADERS(self):
        return getattr(settings, "CORS_ALLOW_HEADERS", default_headers)

    @property
    def CORS_ALLOW_METHODS(self):
        return getattr(settings, "CORS_ALLOW_METHODS", default_methods)

    @property
    def CORS_ALLOW_CREDENTIALS(self):
        return getattr(settings, "CORS_ALLOW_CREDENTIALS", False)

    @property
    def CORS_PREFLIGHT_MAX_AGE(self):
        return getattr(settings, "CORS_PREFLIGHT_MAX_AGE", 86400)

    @property
    def CORS_ORIGIN_ALLOW_ALL(self):
        return getattr(settings, "CORS_ORIGIN_ALLOW_ALL", False)
...

In my setting, I did "CORS_ORIGIN_ALLOW_ALL=true"so that part Okayes any origin, but to use cache-control header, you now have to set "CORS_ALLOW_HEADERS".
Since setting CORS_ALLOW_HEADERS in settings.py completely replaces the value, I copied the default header, and set it as follows:

CORS_ALLOW_HEADERS = [
    "accept",
    "accept-encoding",
    "authorization",
    "content-type",
    "dnt",
    "origin",
    "user-agent",
    "x-csrftoken",
    "x-requested-with",
    "cache-control",
    "credentials",
    "http-access-control-request-method",
]

# if you want to allow all. You could use whitelist instead.
CORS_ORIGIN_ALLOW_ALL = True

Now, my React app is back to accessing Django.

Refreshing JWT Access Token with Redux – Concept

I spent multiple days trying to figure out how to refresh JWT access token in Redux store. (Getting JWT token in first place – some other time but it’s straightforward.)

My React app works for like 5 minutes, and gets “access denied”, and it turns out the JWT access token has the life expectancy of 5 minutes, and you have to use refresh token to get new access token once it expires.

I googled and everyone is solving the problem using “stash the actions, create new JWT toekn refresh action, do that first, and re-run the stashed actions”.
This works fine as long as you don’t use Redux Thunk to do some kind of processing after dispatching action. In my case, Material Table needs the result to be given back to the table data once the fetch succeeds, and I was using Thunk for it.

This approach – “stash actions and refresh JWT token” does not work for me. This morning, I asked myself “is there a different way?”, and I answered myself – “if a token is expiring, refresh it before it expires with timer.”

When you store the JWT access token, parse it, get the expiration, and set a timeout 30 seconds before it expires, and refresh the token.
The all of changes needed 30 minutes. I already had all the Redux actions and types shaped out. Rewiring of refreshing access token with timeout took very little time, and I get to keep the existing Thunks’ post-action processing.

Only downside – the access token may be refreshed if the user is dormant for long time and no need to refresh the token. if you are using the web app intereactively, this would probably be very neglegible downside. Overall, this is a big win for me.

If you came here googling “Refresh JWT Access Token Redux”, don’t follow the examples out there. Use setTimeout or setInterval.

I will prep some code, and write another post about this.

Running TypeScript Project causes inotify to run out

I decided to redo my React project with TypeScript. It causes an error event and doesn’t run at all.

Starting the development server...

events.js:183
      throw er; // Unhandled 'error' event
      ^

Error: watch /home/ntai/sand/triageui/public ENOSPC
    at _errnoException (util.js:1022:11)
    at FSWatcher.start (fs.js:1382:19)
    at Object.fs.watch (fs.js:1408:11)
    at createFsWatchInstance (/home/ntai/sand/triageui/node_modules/chokidar/lib/nodefs-handler.js:38:15)
    at setFsWatchListener (/home/ntai/sand/triageui/node_modules/chokidar/lib/nodefs-handler.js:81:15)
    at FSWatcher.NodeFsHandler._watchWithNodeFs (/home/ntai/sand/triageui/node_modules/chokidar/lib/nodefs-handler.js:233:14)
    at FSWatcher.NodeFsHandler._handleDir (/home/ntai/sand/triageui/node_modules/chokidar/lib/nodefs-handler.js:429:19)
    at FSWatcher.<anonymous> (/home/ntai/sand/triageui/node_modules/chokidar/lib/nodefs-handler.js:477:19)
    at FSWatcher.<anonymous> (/home/ntai/sand/triageui/node_modules/chokidar/lib/nodefs-handler.js:482:16)
    at FSReqWrap.oncomplete (fs.js:153:5)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Process finished with exit code 1

After few minutes of Google, it turns out file system monitor resource is running out. You need to increase the fs.inotify.max_user_watches.

Add following line to “”/etc/sysctl.conf”.

fs.inotify.max_user_watches = 524288

Then let the system fetch the value by:

sudo sysctl -p

Fake Fake with Real

I wanted to learn something new. I know nothing about JavaScript, TypeScript or any of web framework. When I found time, I started taking a look at Angular. I don’t know I’d ever use it but it’s all the industry rage. (Friend of mine mentioned React is better, but I know nothing so I’ll see.)

I was happily following the tutorial, and when it came to the part of using fake RESTful in-memory database angular-in-memory-web-api, I hit a wall. The piece just doesn’t want to work at all. I know very little of anything at this point about npm or node or JavaScript. But, I understood that it’s mimicing the database. So, “fine. I’ll use real database instead.”.

So, I started a project, thanks to evaluation of IntelliJ, and googling like storm to find out how to write the RESTful service using PostgreSQL.

I found this post to be pretty much what I need. Just swap out the puppies with heroes. (Yes, the post uses puppy database.) But, I also wanted to use the express/router.

The part accessing database and returning records started working pretty quickly. I spent most of the day Googling and learning JavaScript, Observables, Express router, and then write a few lines of code to access database.

The pain started once I swapped out the web service URL from the fake URL of Angular Tutorial to my own. As a complete newbie, I didn’t know how to debug but it just doesn’t work at all. After a few more Google, someone said, “console output shows up on Chrome.”. I was hoping IntelliJ’s “debug” to work but I couldn’t manage it to work. (Another time to learn this.) So, I opened the tutorial’s endpoint, I can see the console log and errors! Horay!.

And the error says No Access-Control-Allow-Origin present in the header. What on earth? Yet another googling. (I don’t know how people write code before google.)

Now, I learned when you make a call from other domain (well, in this case port 4200 to port 3001.), it’s crossing boundaries and web services don’t like that kind of deal for security reason. The way to do this is to add the header. Rather than doing it by myself, I found a library “cors”. I confess that I googled. I have no clue what it does. Also, the location of app.use(cors()) seems to matter. When I moved it around, it got totally wedged. So, be careful using this piece.

app.use(cors());
app.options('*', cors()); // enable pre-flight

Second missing piece was, the Angular’s example’s accessing service didn’t like the header that node’s service returns. Googling, googling and more googling. And here was the answer. 42! No. JK.

app.disable('etag')

Apparently, this “etag” thing needs to be suppressed. I’m not quite sure of what it is (I’ll learn some day), but disabling this bit made the Angular tutorial happy.

https://github.com/ntai/realherodb

Here is the result of it. I faked the fake database with real database. Named it “Real Hero DB”