You Can Use require() To Load JSON (JavaScript Object Notation) Files In Node.js
At InVision App, we're hiring a lot of Node.js developers. Which means, I get to look at a lot of Node.js sample code. And, one odd thing, that I keep seeing over and over again, is developers using JavaScript modules to define static JSON (JavaScript Object Notation) configuration files. I think maybe they do this because they don't know that you can require() a JSON file in Node.js. As such, I wanted to put together a quick demo.
The require() function, in Node.js, can read in both .js and .json files. If a file ends with .js, the file is parsed and interpreted as a JavaScript file and is expected to use the module syntax. And, if the file ends with .json, the file is parsed and interpreted as a JSON text file and is expected to adhere to the JSON syntax.
To see this in action, let's create two configuration files: config.js and config.json. The first - config.js - is what I keep seeing in submitted Node.js code samples:
module.exports = {
server: "localhost",
port: 1234,
timeout: 10
};
Here, you can see the developer is using the module syntax; but, is really only exposing static configuration data. Now, let's create another file - config.json - which contains truly static configuration data:
{
"server": "localhost",
"port": 1234,
"timeout": 10
}
Ok, now let's try to read in both of these files using the require() method and log the result out to see what Node.js is doing:
// When loading a configuration file, we have the choice to load either .js file,
// which will be interpreted as a JavaScript module file, with the "exports" being
// returned from the require; or, we can load a .json file, which will be parsed as
// JavaScript Object Notation (JSON) with the result being returned from the require.
// Load configuration as JSON.
console.log( "JSON File:" );
console.log( require( "./config.json" ) );
// Load configuration as module.
console.log( "MODULE File:" );
console.log( require( "./config.js" ) );
When we run this code, we get the following terminal output
ben$ node explicit-ext.js
JSON File:
{ server: 'localhost', port: 1234, timeout: 10 }
MODULE File:
{ server: 'localhost', port: 1234, timeout: 10 }
As you can see, both approaches - requiring a .js and requiring a .json file - result in the same outcome: exposure of a JavaScript hash of configuration information.
At this point, you might be thinking that being able to require a .json file is nice; but, that you don't want to paint yourself into a "static" corner. Sure, you might start out with static configuration files; but, down the road, you might need to do a little post-read "data massaging."
This is no problem. All we have to do is omit the file extension and Node.js will look for a .js file first and then, if not found, look for a .json file. This means that we can start off using a completely static .json file, move to a .js file later on, and the calling code doesn't have to change at all.
To see this in action, let's try to require() a .json file without an explicit file extension:
// When loading a configuration file, we don't have to lock ourselves into a particular
// type of file. If we exclude the file-extension, Node will automatically try to look
// for a *.js and then, if not found, a *.json file. This means that we can start out
// using a .json file; then, if we need to add a programmatic aspect to the config file,
// we can transparently change it over to a "module" style file. The take-away here is
// that there is absolutely no reason to NOT start out with a .json file if your module
// just returns a static hash.
// Load configuration as UNKNOWN file type.
// --
// NOTE: On disk, it is "config.json". But, we're going to make Node.js look for it.
console.log( "UNKNOWN File:" );
console.log( require( "./config" ) );
Here, we're using the require() method to read in a file without an obvious file extension, although we do have a .json file on disk. And, when we run this code, we get the following terminal output:
ben$ node implicit-ext.js
UNKNOWN File:
{ server: 'localhost', port: 1234, timeout: 10 }
As you can see, it worked perfectly. This means that we can start out with a .json file. Then, over time, if we needed to make the application configuration more dynamic, we could seamlessly and transparently switch over to using a .js file. Such is the power of the require() method in Node.js.
Want to use code from this post? Check out the license.
Reader Comments
I have a few things that need to be configured for almost every application I create: loggers, email server, databases, errorhandlers etc and also a few application specific items like application name, port.
I created a node module dvconfigure and published it as an npm private package. It exposes one function which takes the path to two json files (common,and application) and an app object.
I use nconf to grab those config files and attach them to the app object.
When I start an application I just use:
require("@donvawter/dvconfigure")app,__dirname+"/common_config.json",__dirname+"/app_config.json")
.then(....)
.catch(...)
From the command line I often use the require method to validate a json file.
Just get in node REPL with node <ENTER>
and then type
foo=require("./package.json")
If I forgot a comma somewhere I know it immediately.
@Don,
Very interesting! I haven't done too much "production" node.js stuff yet; but, I think our team uses something similarish. I think we have a "core" node module that we sort of use as the bootstrap for all of the applications. It sets up things like what you mention - loggers, mongoDB connectors, etc.
But, I haven't had a chance to really dig into that stuff yet.
I didn't know this and used it the other day when I was testing stuff out in the REPL and had a .json file I wanted to walk through. Definitely saves a few steps requiring the .json file as opposed to requiring fs and reading the file in, especially when messing around in the REPL
@Rob,
Heck yeah!
On the plus side, using a ".js" file means you don't have to use strict JSON format. Hence:
{
foo: 'blah',
bar: foo + '/blah.html' // this must be an HTML file
}
rather than
{
"foo": "blah",
"bar": "blah/blah.html"
}
@Steve,
Yeah, that's actually a really good point!
@All,
A quick follow-up post to showcase that Node's require() function can seamlessly switch in between ".json" and ".json.js" files for more flexibility:
www.bennadel.com/blog/3106-node-s-require-function-can-seamlessly-switch-between-json-and-json-js-files.htm
Hello, I'm new with this kind of things. I have two files .js running, one on port 3000 and the other on the 4000. The one running on the port 4000 has a json message that I want to receive in the 3000 console.
3000:
... var request = require('request-json');
var client = request.createClient('http://localhost:4000/'); ...
4000:
app.get('/Teste2', function(req, res){
var jsonmsg= {"MSg":"teste"};
res.json(jsonmsg);
})
Can someone give me an advice please?
Amazing. Thanks for the tips !
Ya it is working for .js file.... but in requiring json file to console log it is showing a lot of error. Please suggest if you have any about this. I had followed your all steps but only working for js file.
@Moses,
Without seeing the actual file(s) that you are accessing, I might guess that your json file may not be pure JSON. A reason that I use .js files even for static configuration is that I can add comments.