1035

How should I parse JSON using Node.js? Is there some module which will validate and parse JSON securely?

0

31 Answers 31

1145

You can simply use JSON.parse.

The definition of the JSON object is part of the ECMAScript 5 specification. node.js is built on Google Chrome's V8 engine, which adheres to ECMA standard. Therefore, node.js also has a global object JSON[docs].

Note - JSON.parse can tie up the current thread because it is a synchronous method. So if you are planning to parse big JSON objects use a streaming json parser.

7
  • Anyone know why that's not in the official documentation? Or, if it is, where to find it? Mar 21, 2012 at 18:58
  • 35
    @snapfractalpop: The documentation only describes functions, etc, which are part of node.js. Standard JavaScript features are part of V8, node.js is built on. I updated the answer accordingly. Mar 21, 2012 at 19:09
  • 1
    @FelixKling For what it's worth, there's a bunch of stuff here on node's github wiki: github.com/joyent/node/wiki/…
    – damianb
    Mar 18, 2013 at 18:18
  • here, i've published a demo where you can see and play with this answer online (the parsing example is in app.js file - then click on the run button and see the result in the terminal): link you can modify the code and see the impact...
    – nathan g
    Jan 6, 2015 at 8:56
  • Your answer requires prior knowledge of JavaScript syntax. How hard would it be to show a usage example? JSON.parse(str); // is the noob-friendly and therefore better answer
    – webb
    May 2, 2015 at 13:43
680

you can require .json files.

var parsedJSON = require('./file-name');

For example if you have a config.json file in the same directory as your source code file you would use:

var config = require('./config.json');

or (file extension can be omitted):

var config = require('./config');

note that require is synchronous and only reads the file once, following calls return the result from cache

Also note You should only use this for local files under your absolute control, as it potentially executes any code within the file.

16
  • 4
    If you are using this method to parse the file make sure to take the path into account for the require. For example, you might need to do something like this: require './file-name-with-no-extension' (for example if the file is in the current directory)
    – SnapShot
    Jun 20, 2012 at 21:36
  • 96
    Note that the response is cached. E.g. if you put above require call in a function, call the function, change the JSON file, and call the function again, you'll get the old version of the JSON file. Has caught me out a couple of times! Apr 9, 2013 at 20:42
  • 15
    Note also that require is synchronous. If you want to async friendly use fs.readFile instead with JSON.parse
    – Evan Moran
    Aug 25, 2013 at 21:57
  • 29
    Will this approach just treat the file as JavaScript, thus potentially running arbitrary code in the .json file?
    – d11wtq
    Jul 27, 2014 at 1:25
  • 15
    Simple note: don't forget to use the .json extension! If your file does NOT have the .json extension, require will not treat it as a json file.
    – Jason
    Jan 21, 2015 at 12:46
342

You can use JSON.parse().

You should be able to use the JSON object on any ECMAScript 5 compatible JavaScript implementation. And V8, upon which Node.js is built is one of them.

Note: If you're using a JSON file to store sensitive information (e.g. passwords), that's the wrong way to do it. See how Heroku does it: https://devcenter.heroku.com/articles/config-vars#setting-up-config-vars-for-a-deployed-application. Find out how your platform does it, and use process.env to retrieve the config vars from within the code.


Parsing a string containing JSON data

var str = '{ "name": "John Doe", "age": 42 }';
var obj = JSON.parse(str);

Parsing a file containing JSON data

You'll have to do some file operations with fs module.

Asynchronous version

var fs = require('fs');

fs.readFile('/path/to/file.json', 'utf8', function (err, data) {
    if (err) throw err; // we'll not consider error handling for now
    var obj = JSON.parse(data);
});

Synchronous version

var fs = require('fs');
var json = JSON.parse(fs.readFileSync('/path/to/file.json', 'utf8'));

You wanna use require? Think again!

You can sometimes use require:

var obj = require('path/to/file.json');

But, I do not recommend this for several reasons:

  1. require is synchronous. If you have a very big JSON file, it will choke your event loop. You really need to use JSON.parse with fs.readFile.
  2. require will read the file only once. Subsequent calls to require for the same file will return a cached copy. Not a good idea if you want to read a .json file that is continuously updated. You could use a hack. But at this point, it's easier to simply use fs.
  3. If your file does not have a .json extension, require will not treat the contents of the file as JSON.

Seriously! Use JSON.parse.


load-json-file module

If you are reading large number of .json files, (and if you are extremely lazy), it becomes annoying to write boilerplate code every time. You can save some characters by using the load-json-file module.

const loadJsonFile = require('load-json-file');

Asynchronous version

loadJsonFile('/path/to/file.json').then(json => {
    // `json` contains the parsed object
});

Synchronous version

let obj = loadJsonFile.sync('/path/to/file.json');

Parsing JSON from streams

If the JSON content is streamed over the network, you need to use a streaming JSON parser. Otherwise it will tie up your processor and choke your event loop until JSON content is fully streamed.

There are plenty of packages available in NPM for this. Choose what's best for you.


Error Handling/Security

If you are unsure if whatever that is passed to JSON.parse() is valid JSON, make sure to enclose the call to JSON.parse() inside a try/catch block. A user provided JSON string could crash your application, and could even lead to security holes. Make sure error handling is done if you parse externally-provided JSON.

12
  • 2
    and could even lead to security holes out of curiosity, how?
    – natario
    Oct 28, 2016 at 11:01
  • 6
    @natario: We are talking about server-side JS here. Suppose someone is parsing user-supplied JSON. If the assumption is that the JSON is always well formed, an attacker can send some malformed JSON to trigger an error, which if spilled to the client side, may reveal vital information about the system. Or if the JSON was both malformed and contained some text with <script>..., and the error is spilled to the client side, you have an XSS bug right there. Therefore IMO it's important to handle JSON errors right where you parse it. Oct 28, 2016 at 11:11
  • 1
    @NickSteele: However, I changed "this is not recommended" to "I do not recommend". I hope you are happy now. Jan 9, 2017 at 3:48
  • 1
    @NickSteele: Given the flaws I have listed I don't think it's a well designed feature. Looks to me like some people thought "hey, wouldn't it be cool to use require to include JSON?" and didn't even bother documenting the side effects. This also meant that require accepts files in two languages: JavaScript, and JSON (no they're not the same). So much for SRP. Jan 10, 2017 at 7:24
  • 1
    @NickSteele: Yes, only for config it works fine. But JSON is not used only for config. Jan 11, 2017 at 3:10
87

use the JSON object:

JSON.parse(str);
10
  • 12
    This just duplicates the top answer. Please consider deleting it; you'll keep the points. Nov 25, 2014 at 6:59
  • 6
    This answer has 50 upvotes. According to the 1% rule, probably 5000 users have spent time reading this answer, which adds nothing to the top one. The fact that it's 3 years old only makes the problem worse :) Nov 28, 2014 at 21:00
  • 17
    @DanDascalescu -- If you'll notice, the two answers were posted at exactly the same time 3 years ago. They both provide the same information. This is the case all over SO, I'm not about to go culling half of my answers just because they weren't the accepted answer.
    – user578895
    Nov 28, 2014 at 22:25
  • 8
    I for one found this series of comments fairly interesting but the answer itself to be a waste of my time. ...I'm not sure if that implies that the answer should be deleted, because then I wouldn't have seen the comment thread. But otherwise I'd say yeah. Apr 6, 2015 at 13:20
  • 7
    @DanDascalescu, I believe this answer is clearer and straight to the point. The accepted one doesn't give a usage example and is confusing because of many links and extra stuff. Nov 26, 2015 at 4:08
37

Another example of JSON.parse :

var fs = require('fs');
var file = __dirname + '/config.json';

fs.readFile(file, 'utf8', function (err, data) {
  if (err) {
    console.log('Error: ' + err);
    return;
  }

  data = JSON.parse(data);

  console.dir(data);
});
1
  • 2
    I like that this approach does not require the json file to be local to the application. Thank you! May 8, 2014 at 16:52
35

I'd like to mention that there are alternatives to the global JSON object. JSON.parse and JSON.stringify are both synchronous, so if you want to deal with big objects you might want to check out some of the asynchronous JSON modules.

Have a look: https://github.com/joyent/node/wiki/Modules#wiki-parsers-json

3
  • 1
    This is especially true if one expects JSON data from incoming connections. If malformed JSON is being parsed by JSON.parse your whole application is going to crash or, using process.on('uncaughtException', function(err) { ... });, there will eventually be no chance to send a "malformed JSON" error to the user.
    – Paul
    Feb 2, 2013 at 11:25
  • 3
    Which one is async parser ? I did not find it.
    – bxshi
    Feb 4, 2013 at 9:33
  • 3
    The linked page is now marked "DEPRECATED" and describes itself as a "faded relic".
    – nobody
    May 8, 2014 at 4:56
30

Include the node-fs library.

var fs = require("fs");
var file = JSON.parse(fs.readFileSync("./PATH/data.json", "utf8"));

For more info on 'fs' library , refer the documentation at http://nodejs.org/api/fs.html

2
  • 2
    It might be worth noting that you should wrap your var file line in a try/catch just in case your JSON fails to parse or the file does not exist.
    – Fostah
    Sep 17, 2014 at 17:38
  • 3
    Or just use a callback!
    – lawx
    Dec 25, 2014 at 2:26
12

Since you don't know that your string is actually valid, I would put it first into a try catch. Also since try catch blocks are not optimized by node, i would put the entire thing into another function:

function tryParseJson(str) {
    try {
        return JSON.parse(str);
    } catch (ex) {
        return null;
    }
}

OR in "async style"

function tryParseJson(str, callback) {
    process.nextTick(function () {
      try {
          callback(null, JSON.parse(str));
      } catch (ex) {
          callback(ex)
      }
    })
}
1
  • 2
    I just want to make a note that process.nextTick is not aysnc. It's just putting off reading the file until the next function call in the JS event loop. To run JSON.parse asynchronously you have use a different thread than the main Node.js thread Jun 8, 2015 at 5:36
9

Parsing a JSON stream? Use JSONStream.

var request = require('request')
  , JSONStream = require('JSONStream')

request({url: 'http://isaacs.couchone.com/registry/_all_docs'})
    .pipe(JSONStream.parse('rows.*'))
    .pipe(es.mapSync(function (data) {
      return data
    }))

https://github.com/dominictarr/JSONStream

7

Everybody here has told about JSON.parse, so I thought of saying something else. There is a great module Connect with many middleware to make development of apps easier and better. One of the middleware is bodyParser. It parses JSON, html-forms and etc. There is also a specific middleware for JSON parsing only noop.

Take a look at the links above, it might be really helpful to you.

7
JSON.parse("your string");

That's all.

6

as other answers here have mentioned, you probably want to either require a local json file that you know is safe and present, like a configuration file:

var objectFromRequire = require('path/to/my/config.json'); 

or to use the global JSON object to parse a string value into an object:

var stringContainingJson = '\"json that is obtained from somewhere\"';
var objectFromParse = JSON.parse(stringContainingJson);

note that when you require a file the content of that file is evaluated, which introduces a security risk in case it's not a json file but a js file.

here, i've published a demo where you can see both methods and play with them online (the parsing example is in app.js file - then click on the run button and see the result in the terminal): http://staging1.codefresh.io/labs/api/env/json-parse-example

you can modify the code and see the impact...

0
5

Using JSON for your configuration with Node.js? Read this and get your configuration skills over 9000...

Note: People claiming that data = require('./data.json'); is a security risk and downvoting people's answers with zealous zeal: You're exactly and completely wrong. Try placing non-JSON in that file... Node will give you an error, exactly like it would if you did the same thing with the much slower and harder to code manual file read and then subsequent JSON.parse(). Please stop spreading misinformation; you're hurting the world, not helping. Node was designed to allow this; it is not a security risk!

Proper applications come in 3+ layers of configuration:

  1. Server/Container config
  2. Application config
  3. (optional) Tenant/Community/Organization config
  4. User config

Most developers treat their server and app config as if it can change. It can't. You can layer changes from higher layers on top of each other, but you're modifying base requirements. Some things need to exist! Make your config act like it's immutable, because some of it basically is, just like your source code.

Failing to see that lots of your stuff isn't going to change after startup leads to anti-patterns like littering your config loading with try/catch blocks, and pretending you can continue without your properly setup application. You can't. If you can, that belongs in the community/user config layer, not the server/app config layer. You're just doing it wrong. The optional stuff should be layered on top when the application finishes it's bootstrap.

Stop banging your head against the wall: Your config should be ultra simple.

Take a look at how easy it is to setup something as complex as a protocol-agnostic and datasource-agnostic service framework using a simple json config file and simple app.js file...

container-config.js...

{
    "service": {
        "type"  : "http",
        "name"  : "login",
        "port"  : 8085
    },
    "data": {
        "type"  : "mysql",
        "host"  : "localhost",
        "user"  : "notRoot",
        "pass"  : "oober1337",
        "name"  : "connect"
    }
}

index.js... (the engine that powers everything)

var config      = require('./container-config.json');       // Get our service configuration.
var data        = require(config.data.type);            // Load our data source plugin ('npm install mysql' for mysql).
var service     = require(config.service.type);         // Load our service plugin ('http' is built-in to node).
var processor   = require('./app.js');                  // Load our processor (the code you write).

var connection  = data.createConnection({ host: config.data.host, user: config.data.user, password: config.data.pass, database: config.data.name });
var server      = service.createServer(processor);
connection.connect();
server.listen(config.service.port, function() { console.log("%s service listening on port %s", config.service.type, config.service.port); });

app.js... (the code that powers your protocol-agnostic and data-source agnostic service)

module.exports = function(request, response){
    response.end('Responding to: ' + request.url);
}

Using this pattern, you can now load community and user config stuff on top of your booted app, dev ops is ready to shove your work into a container and scale it. You're read for multitenant. Userland is isolated. You can now separate the concerns of which service protocol you're using, which database type you're using, and just focus on writing good code.

Because you're using layers, you can rely on a single source of truth for everything, at any time (the layered config object), and avoid error checks at every step, worrying about "oh crap, how am I going to make this work without proper config?!?".

5

If you need to parse JSON with Node.js in a secure way (aka: the user can input data, or a public API) I would suggest using secure-json-parse.

The usage is like the default JSON.parse but it will protect your code from:

const badJson = '{ "a": 5, "b": 6, "__proto__": { "x": 7 }, "constructor": {"prototype": {"bar": "baz"} } }'

const infected = JSON.parse(badJson)
console.log(infected.x) // print undefined

const x = Object.assign({}, infected)
console.log(x.x) // print 7

const sjson = require('secure-json-parse')
console.log(sjson.parse(badJson)) // it will throw by default, you can ignore malicious data also
4

My solution:

var fs = require('fs');
var file = __dirname + '/config.json';

fs.readFile(file, 'utf8', function (err, data) {
    if (err) {
        console.log('Error: ' + err);
        return;
    }

    data = JSON.parse(data);

    console.dir(data);
});
1
  • Thanks @eloyesp, I tried using this code but I keep getting TypeError: path must be a string or Buffer errors - any idea where to start debugging this issue?
    – GPP
    Oct 15, 2018 at 17:07
4

Just want to complete the answer (as I struggled with it for a while), want to show how to access the json information, this example shows accessing Json Array:

var request = require('request');
request('https://server/run?oper=get_groups_joined_by_user_id&user_id=5111298845048832', function (error, response, body) {
  if (!error && response.statusCode == 200) {
    var jsonArr = JSON.parse(body);
    console.log(jsonArr);
    console.log("group id:" + jsonArr[0].id);
  }
})

3

Just to make this as complicated as possible, and bring in as many packages as possible...

const fs = require('fs');
const bluebird = require('bluebird');
const _ = require('lodash');
const readTextFile = _.partial(bluebird.promisify(fs.readFile), _, {encoding:'utf8',flag:'r'});
const readJsonFile = filename => readTextFile(filename).then(JSON.parse);

This lets you do:

var dataPromise = readJsonFile("foo.json");
dataPromise.then(console.log);

Or if you're using async/await:

let data = await readJsonFile("foo.json");

The advantage over just using readFileSync is that your Node server can process other requests while the file is being read off disk.

2

JSON.parse will not ensure safety of json string you are parsing. You should look at a library like json-safe-parse or a similar library.

From json-safe-parse npm page:

JSON.parse is great, but it has one serious flaw in the context of JavaScript: it allows you to override inherited properties. This can become an issue if you are parsing JSON from an untrusted source (eg: a user), and calling functions on it you would expect to exist.

2

Leverage Lodash's attempt function to return an error object, which you can handle with the isError function.

// Returns an error object on failure
function parseJSON(jsonString) {
   return _.attempt(JSON.parse.bind(null, jsonString));
}


// Example Usage
var goodJson = '{"id":123}';
var badJson = '{id:123}';
var goodResult = parseJSON(goodJson);
var badResult = parseJSON(badJson);

if (_.isError(goodResult)) {
   console.log('goodResult: handle error');
} else {
   console.log('goodResult: continue processing');
}
// > goodResult: continue processing

if (_.isError(badResult)) {
   console.log('badResult: handle error');
} else {
   console.log('badResult: continue processing');
}
// > badResult: handle error
1
  • 3
    Can you explain why you added .bind instead of just using _.attempt(JSON.parse, str)
    – steviesh
    Sep 2, 2016 at 22:39
2

Always be sure to use JSON.parse in try catch block as node always throw an Unexpected Error if you have some corrupted data in your json so use this code instead of simple JSON.Parse

try{
     JSON.parse(data)
}
catch(e){
   throw new Error("data is corrupted")
  }
2

I use fs-extra. I like it a lot because -although it supports callbacks- it also supports Promises. So it just enables me to write my code in a much more readable way:

const fs = require('fs-extra');
fs.readJson("path/to/foo.json").then(obj => {
    //Do dome stuff with obj
})
.catch(err => {
    console.error(err);
});

It also has many useful methods which do not come along with the standard fs module and, on top of that, it also bridges the methods from the native fs module and promisifies them.

NOTE: You can still use the native Node.js methods. They are promisified and copied over to fs-extra. See notes on fs.read() & fs.write()

So it's basically all advantages. I hope others find this useful.

2

As mentioned in the above answers, We can use JSON.parse() to parse the strings to JSON But before parsing, be sure to parse the correct data or else it might bring your whole application down

it is safe to use it like this

let parsedObj = {}
try {
    parsedObj = JSON.parse(data);
} catch(e) {
    console.log("Cannot parse because data is not is proper json format")
}
2

Use JSON.parse(str);. Read more about it here.

Here are some examples:

var jsonStr = '{"result":true, "count":42}';

obj = JSON.parse(jsonStr);

console.log(obj.count);    // expected output: 42
console.log(obj.result);   // expected output: true
1

If you want to add some comments in your JSON and allow trailing commas you might want use below implemention:

var fs = require('fs');

var data = parseJsData('./message.json');

console.log('[INFO] data:', data);

function parseJsData(filename) {
    var json = fs.readFileSync(filename, 'utf8')
        .replace(/\s*\/\/.+/g, '')
        .replace(/,(\s*\})/g, '}')
    ;
    return JSON.parse(json);
}

Note that it might not work well if you have something like "abc": "foo // bar" in your JSON. So YMMV.

1

If the JSON source file is pretty big, may want to consider the asynchronous route via native async / await approach with Node.js 8.0 as follows

const fs = require('fs')

const fsReadFile = (fileName) => {
    fileName = `${__dirname}/${fileName}`
    return new Promise((resolve, reject) => {
        fs.readFile(fileName, 'utf8', (error, data) => {
            if (!error && data) {
                resolve(data)
            } else {
                reject(error);
            }
        });
    })
}

async function parseJSON(fileName) {
    try {
        return JSON.parse(await fsReadFile(fileName));
    } catch (err) {
        return { Error: `Something has gone wrong: ${err}` };
    }
}

parseJSON('veryBigFile.json')
    .then(res => console.log(res))
    .catch(err => console.log(err))
0

You can use JSON.parse() (which is a built in function that will probably force you to wrap it with try-catch statements).

Or use some JSON parsing npm library, something like json-parse-or

0

Use this to be on the safe side

var data = JSON.parse(Buffer.concat(arr).toString());
0

NodeJs is a JavaScript based server, so you can do the way you do that in pure JavaScript...

Imagine you have this Json in NodeJs...

var details = '{ "name": "Alireza Dezfoolian", "netWorth": "$0" }';
var obj = JSON.parse(details);

And you can do above to get a parsed version of your json...

-1

No further modules need to be required.
Just use
var parsedObj = JSON.parse(yourObj);
I don think there is any security issues regarding this

-2

It's simple, you can convert JSON to string using JSON.stringify(json_obj), and convert string to JSON using JSON.parse("your json string").

2
  • 2
    Have you looked at the top answer for this question? It's 3 years old and very complete. What were you hoping to contribute with the trivial information you're offering here? Jun 27, 2014 at 3:10
  • 2
    Now, now, let's not hold a double standard Jul 20, 2014 at 19:04

Not the answer you're looking for? Browse other questions tagged or ask your own question.