NodeJS - Parse JSON (only strings or numbers) - javascript

I have got a little dilema what to do (What should I do). I've got in my app several places where I am using AJAX to transfer a JSON data. So for example receiving a data from the registration form:
try {
var data = JSON.parse(json);
}
catch(e) {
// ...
}
var fields = {
firstName: data.firstName || "",
lastName: data.lastName || "",
...
};
Then I need to do something with these fields. Let's say:
if (fields.firstName) {
// OK save it to the DB
}
if(fields.lastName.xxx()) { // xxx() is a method that belongs to JS String Object
// Do something...
}
The problem is what if fields.firstName or fields.lastName is {} / []? That may happen if somebody sent a modified JSON with a wrong data types, the whole app will then crash since the method xxx is missing.
Do I have to check the type of every field whether it is really a string, a number, an array... or is there some another maybe nicer way how to do this?

Unfortunately that's a problem you'll have to face anytime using a dynamic language like JavaScript.
One possible solution is not using String methods, but creating a function that will check it's arguments first:
// original, with string methods
if (text instanceof String && text.trim().length === 0) { ... }
// alternative, define function first
var isEmptyString = function(text) {
if (!(text instanceof String)) throw new Error("Argument must be a String");
return text.trim().length === 0;
}
// use it in your code
if (isEmptyString(text)) { ... }
That can lead to cleaner code.
Just be sure not to define those functions in a global scope, when you have to use them in a Browser. Within the node.js modules that should not be a problem.

You'll have to make a little validator. Like that:
var format = {
foo: "string",
bar: "string"
};
var data = {
foo: "bar",
bar: []
}
var validate = function (data, format) {
for(var d in data) {
if(typeof data[d] !== format[d])
return false;
}
return true;
}
console.log(validate(data, format));
You can also remove invalid data like this:
var format = {
foo: "string",
bar: "string"
};
var data = {
foo: "bar",
bar: []
}
var validate = function (data, format) {
for(var d in data) {
if(typeof data[d] !== format[d])
delete data[d];
}
return data;
}
console.log(validate(data, format));

In addition to what Tharabas suggests, you could take advantage of the 2nd argument of JSON.parse for doing your sanity check:
JSON.parse(data, function(key, value) {
return key === 'firstName' ? cleanup(value) : '';
});
See this page for further information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse

Related

How to refine types in function that takes union of arrays?

There is some function that delegate job to other functions depending of the type of the input array. How can I point out that particular array has to be processed by particular function?
I've been thinking about it and searching for several hours, but couldn't find a solution.
type nameType = {
name: string,
}
type surnameType = {
surname: string
};
type inputType = nameType[] | surnameType[];
function processSurnames(suranmes: surnameType[]) {
let result = {};
// do something with surnames
return result;
}
function processNames(names: nameType[]) {
let result = {};
// do something with names
return result;
}
function process(input: inputType) {
if (typeof input[0].name === 'string') { // <--- this refinement doesn't work
return processNames(input);
} else {
return processSurnames(input);
}
}
the code on flow.org/try
It is not possible to refine based on the types of items in an array.
This is because array access is unsafe -- it is always possible for array access to return undefined. Refinements can be made with anything other than an array.
I've rewritten your example wrapping the arrays in objects and refining based the "type" property.
// ...
type Names = { type: "names", list: nameType[] }
type Surnames = { type: "surnames", list: surnameType[] }
// ...
export function process(input: Names | Surnames) {
if (input.type === "names") {
return processNames(input.list)
} else {
return processSurnames(input.list)
}
}
Here is the try flow link.
Unfortunate :(
Have you tried instanceof?
What does it mean doesnt't work? Have you checked what typeof input[0].name returns?

How to get instance of the "class" from JSON string?

Given that I have a class defined such as
(function () {
function Dummy(){
var toReturn ={
myProp : "asdf",
myFunc : myFunc
}
return toReturn;
function myFunc(){};
}
})();
how does one get an instance of the same type after
var dummy = new Dummy();
JSON.stringify(dummy);
so that I have myFunc still available on the type.
JSON.parse(JSON.stringify(dummy)) returns same shape of the object by not the same type.
NOTE: I am not asking about capability of JSON, but how do people deal with this in general. Do you hand roll your mapping mechanism so that after parsing from JSON you map it onto instance of the type, or if there is such functionality in some library, such as underscore.
I created a helper function that helps me do this, but would like to hear from others how do you deal with situation like this. As I put in comments, JSON comes over the wire, for which we have a type defined. To get the values from JSON in our type, we parse json, create instance of type and then apply map function below.
function map(fromObj, toObj) {
Object.keys(fromObj)
.forEach(function (key) {
if (typeof fromObj[key] != 'function') {
if (toObj.hasOwnProperty(key)) {
if (typeof fromObj[key] !== 'object') {
toObj[key] = fromObj[key];
} else {
map(fromObj[key], toObj[key]);
}
}
}
}
});
}
Note, Not certain about requirement , if this similar to what posed at Question. If off-topic , please post comment , will withdraw.
Piece was originally composed for this Question Organizing large javascript files [on hold] . With a json response , having "x" type of contents , could map returned object to new object , copying properties utilizing $.extend() .
Result would be new object having both properties and functions of returned data. At piece below, at completion of process , $.Pages begins as function , then type gets converted to object - though it could retain both function and object properties by including || {} at definition stage.
Functions within returned json objects could be called within .then() callback ; see console at jsfiddle , object init functions.
At conclusion , $.Pages object has properties of returned json , including access to functions . Based on a jsonp - type processing flow.
Piece is "frame" of a processing approach ; could extend to include other functionality
$(function() {
var dfd = new $.Deferred();
dfd.progress(function(msg) {
console.log(msg);
});
ProductPage = {
name : "ProductPage",
addToCartBtn: "#add-to-cart",
initName : function() {return dfd.notify(this.name)},
init: function() {
this.initName();
// ProductPage.initAddToCartPopup();
// ProductPage.initSidebar();
}
};
ContactPage = {
name : "ContactPage",
validateEmail : function (e) {return dfd.notify(e)},
initName : function() {return dfd.notify(this.name)},
init: function() {
this.initName();
// ProductPage.initAddToCartPopup();
// ProductPage.initSidebar();
}
};
var mods = function() {
return {"ContactPage" : ContactPage
, "ProductPage" : ProductPage };
};
$.Pages = function() {
$.when(mods())
.done(function(pages) {
$.Pages = pages;
});
return $.Pages
};
$.when($.Pages())
.then(function() {
$.each($.Pages, function(k, v) {
v.init();
})
});
console.log($.Pages)
});
jsfiddle http://jsfiddle.net/guest271314/60kv2439/1/ (see console)
basic approach
$p = {};
var queue = [];
var mods = ["dep1.json", "service1.json"];
var mod = function(m) {
queue.push(m);
if (queue.length === mods.length) {
$.each(queue, function(k, v) {
$p = $.extend(v, $p)
})
}
};
$.each(mods, function(k, v) {
$.getScript(v, function(script, status, jqxhr) {
console.log($p)
})
})

Javascript, passing a function in an object literal and is it callable?

always in the process of learning Javascript and modifying a cool autocomplete library, i am now in front of this :
i need to check if something passed in an object literal is a variable/field (that is to be considered as a simple value) or is something that can be called.
(as MY autocomplete depend on many input fields, i need to "value" the right things, just before the Ajax.Request) so that this declaration (see the 'extra' parts...)
myAutoComplete = new Autocomplete('query', {
serviceUrl:'autoComplete.rails',
minChars:3,
maxHeight:400,
width:300,
deferRequestBy:100,
// callback function:
onSelect: function(value, data){
alert('You selected: ' + value + ', ' + data);
}
// the lines below are the extra part that i add to the library
// an optional parameter, that will handle others arguments to pass
// if needed, these must be value-ed just before the Ajax Request...
, extraParametersForAjaxRequest : {
myExtraID : function() { return document.getElementById('myExtraID').value; }
}
see the "1 // here i'm lost..." below, and instead of 1 => i would like to check, if extraParametersForAjaxRequest[x] is callable or not, and call it if so, keeping only its value if not. So that, i get the right value of my other inputs... while keeping a really generic approach and clean modification of this library...
{
var ajaxOptions = {
parameters: { query: this.currentValue , },
onComplete: this.processResponse.bind(this),
method: 'get'
};
if (this.options.hasOwnProperty('extraParametersForAjaxRequest'))
{
for (var x in this.options.extraParametersForAjaxRequest)
{
ajaxOptions.parameters[x] = 1 // here i'm lost...
}
}
new Ajax.Request(this.serviceUrl, ajaxOptions );
You can do a typeof to see if the parameter is a function, and call it if it is.
var value;
for (var x in this.options.extraParametersForAjaxRequest)
{
value = this.options.extraParametersForAjaxRequest[x];
if (typeof(value) == 'function') {
ajaxOptions.parameters[x] = value();
}
else {
ajaxOptions.parameters[x] = value;
}
}
if (typeof this.options.extraParametersForAjaxRequest[x]==='function') {
}
You should also do this:
if (this.options.extraParametersForAjaxRequest.hasOwnProperty(x) {
if (typeof this.options.extraParametersForAjaxRequest[x]==='function') {
}
}
when iterating through properties of objects, otherwise you can end up looking at prototype members too.
Another suggestion is to make this more readable with an alias for the thing you're working with. So the ultimate would be:
var opts = this.options.extraParametersForAjaxRequest;
// don't need to check for existence of property explicitly with hasOwnProperty
// just try to access it, and check to see if the result is
// truthy. if extraParametersForAjaxRequest isn't there, no error will
// result and "opts" will just be undefined
if (opts)
{
for (var x in opts) {
if (opts.hasOwnProperty(x) && typeof opts[x]==='function') {
}
}
}

Is there any possibility to have JSON.stringify preserve functions?

Take this object:
x = {
"key1": "xxx",
"key2": function(){return this.key1}
}
If I do this:
y = JSON.parse( JSON.stringify(x) );
Then y will return { "key1": "xxx" }. Is there anything one could do to transfer functions via stringify? Creating an object with attached functions is possible with the "ye goode olde eval()", but whats with packing it?
json-stringify-function is a similar post to this one.
A snippet discovered via that post may be useful to anyone stumbling across this answer. It works by making use of the replacer parameter in JSON.stringify and the reviver parameter in JSON.parse.
More specifically, when a value happens to be of type function, .toString() is called on it via the replacer. When it comes time to parse, eval() is performed via the reviver when a function is present in string form.
var JSONfn;
if (!JSONfn) {
JSONfn = {};
}
(function () {
JSONfn.stringify = function(obj) {
return JSON.stringify(obj,function(key, value){
return (typeof value === 'function' ) ? value.toString() : value;
});
}
JSONfn.parse = function(str) {
return JSON.parse(str,function(key, value){
if(typeof value != 'string') return value;
return ( value.substring(0,8) == 'function') ? eval('('+value+')') : value;
});
}
}());
Code Snippet taken from Vadim Kiryukhin's JSONfn.js or see documentation at Home Page
I've had a similar requirement lately. To be clear, the output looks like JSON but in fact is just javascript.
JSON.stringify works well in most cases, but "fails" with functions.
I got it working with a few tricks:
make use of replacer (2nd parameter of JSON.stringify())
use func.toString() to get the JS code for a function
remember which functions have been stringified and replace them directly in the result
And here's how it looks like:
// our source data
const source = {
"aaa": 123,
"bbb": function (c) {
// do something
return c + 1;
}
};
// keep a list of serialized functions
const functions = [];
// json replacer - returns a placeholder for functions
const jsonReplacer = function (key, val) {
if (typeof val === 'function') {
functions.push(val.toString());
return "{func_" + (functions.length - 1) + "}";
}
return val;
};
// regex replacer - replaces placeholders with functions
const funcReplacer = function (match, id) {
return functions[id];
};
const result = JSON
.stringify(source, jsonReplacer) // generate json with placeholders
.replace(/"\{func_(\d+)\}"/g, funcReplacer); // replace placeholders with functions
// show the result
document.body.innerText = result;
body { white-space: pre-wrap; font-family: monospace; }
Important: Be careful about the placeholder format - make sure it's not too generic. If you change it, also change the regex as applicable.
Technically this is not JSON, I can also hardly imagine why would you want to do this, but try the following hack:
x.key2 = x.key2.toString();
JSON.stringify(x) //"{"key1":"xxx","key2":"function (){return this.key1}"}"
Of course the first line can be automated by iterating recursively over the object. Reverse operation is harder - function is only a string, eval will work, but you have to guess whether a given key contains a stringified function code or not.
You can't pack functions since the data they close over is not visible to any serializer.
Even Mozilla's uneval cannot pack closures properly.
Your best bet, is to use a reviver and a replacer.
https://yuilibrary.com/yui/docs/json/json-freeze-thaw.html
The reviver function passed to JSON.parse is applied to all key:value pairs in the raw parsed object from the deepest keys to the highest level. In our case, this means that the name and discovered properties will be passed through the reviver, and then the object containing those keys will be passed through.
This is what I did https://gist.github.com/Lepozepo/3275d686bc56e4fb5d11d27ef330a8ed
function stringifyWithFunctions(object) {
return JSON.stringify(object, (key, val) => {
if (typeof val === 'function') {
return `(${val})`; // make it a string, surround it by parenthesis to ensure we can revive it as an anonymous function
}
return val;
});
};
function parseWithFunctions(obj) {
return JSON.parse(obj, (k, v) => {
if (typeof v === 'string' && v.indexOf('function') >= 0) {
return eval(v);
}
return v;
});
};
The naughty but effective way would be to simply:
Function.prototype.toJSON = function() { return this.toString(); }
Though your real problem (aside from modifying the prototype of Function) would be deserialization without the use of eval.
I have come up with this solution which will take care of conversion of functions (no eval). All you have to do is put this code before you use JSON methods. Usage is exactly the same but right now it takes only one param value to convert to a JSON string, so if you pass remaning replacer and space params, they will be ignored.
void function () {
window.JSON = Object.create(JSON)
JSON.stringify = function (obj) {
return JSON.__proto__.stringify(obj, function (key, value) {
if (typeof value === 'function') {
return value.toString()
}
return value
})
}
JSON.parse = function (obj) {
return JSON.__proto__.parse(obj, function (key, value) {
if (typeof value === 'string' && value.slice(0, 8) == 'function') {
return Function('return ' + value)()
}
return value
})
}
}()
// YOUR CODE GOES BELOW HERE
x = {
"key1": "xxx",
"key2": function(){return this.key1}
}
const y = JSON.parse(JSON.stringify(x))
console.log(y.key2())
It is entirely possible to create functions from string without eval()
var obj = {a:function(a,b){
return a+b;
}};
var serialized = JSON.stringify(obj, function(k,v){
//special treatment for function types
if(typeof v === "function")
return v.toString();//we save the function as string
return v;
});
/*output:
"{"a":"function (a,b){\n return a+b;\n }"}"
*/
now some magic to turn string into function with this function
var compileFunction = function(str){
//find parameters
var pstart = str.indexOf('('), pend = str.indexOf(')');
var params = str.substring(pstart+1, pend);
params = params.trim();
//find function body
var bstart = str.indexOf('{'), bend = str.lastIndexOf('}');
var str = str.substring(bstart+1, bend);
return Function(params, str);
}
now use JSON.parse with reviver
var revivedObj = JSON.parse(serialized, function(k,v){
// there is probably a better way to determ if a value is a function string
if(typeof v === "string" && v.indexOf("function") !== -1)
return compileFunction(v);
return v;
});
//output:
revivedObj.a
function anonymous(a,b
/**/) {
return a+b;
}
revivedObj.a(1,2)
3
To my knowledge, there are no serialization libraries that persist functions - in any language. Serialization is what one does to preserve data. Compilation is what one does to preserve functions.
It seems that people landing here are dealing with structures that would be valid JSON if not for the fact that they contain functions. So how do we handle stringifying these structures?
I ran into the problem while writing a script to modify RequireJS configurations. This is how I did it. First, there's a bit of code earlier that makes sure that the placeholder used internally (">>>F<<<") does not show up as a value in the RequireJS configuration. Very unlikely to happen but better safe than sorry. The input configuration is read as a JavaScript Object, which may contain arrays, atomic values, other Objects and functions. It would be straightforwardly stringifiable as JSON if functions were not present. This configuration is the config object in the code that follows:
// Holds functions we encounter.
var functions = [];
var placeholder = ">>>F<<<";
// This handler just records a function object in `functions` and returns the
// placeholder as the value to insert into the JSON structure.
function handler(key, value) {
if (value instanceof Function) {
functions.push(value);
return placeholder;
}
return value;
}
// We stringify, using our custom handler.
var pre = JSON.stringify(config, handler, 4);
// Then we replace the placeholders in order they were encountered, with
// the functions we've recorded.
var post = pre.replace(new RegExp('"' + placeholder + '"', 'g'),
functions.shift.bind(functions));
The post variable contains the final value. This code relies on the fact that the order in which handler is called is the same as the order of the various pieces of data in the final JSON. I've checked the ECMAScript 5th edition, which defines the stringification algorithm and cannot find a case where there would be an ordering problem. If this algorithm were to change in a future edition the fix would be to use unique placholders for function and use these to refer back to the functions which would be stored in an associative array mapping unique placeholders to functions.

How do you know if an object is JSON in javascript? [duplicate]

This question already has answers here:
How to check if it's a string or json [duplicate]
(5 answers)
Closed 8 years ago.
How do I know if a variable is JSON or if it is something else? Is there a JQuery function or something I can use to figure this out?
Based on your comments, it sounds like you don't want to know whether a string is valid JSON, but rather whether an object could be successfully encoded as JSON (e.g. doesn't contain any Date objects, instances of user-defined classes, etc.).
There are two approaches here: try to analyze the object and its "children" (watch out for recursive objects) or suck-it-and-see. If you have a JSON encoder on hand (JSON.stringify in recent browsers or a plugin such as jquery-json), the latter is probably the simpler and more robust approach:
function canJSON(value) {
try {
JSON.stringify(value);
return true;
} catch (ex) {
return false;
}
}
Analyzing an object directly requires that you be able to tell whether it is a "plain" object (i.e. created using an object literal or new Object()), which in turn requires you be able to get its prototype, which isn't always straightforward. I've found the following code to work in IE7, FF3, Opera 10, Safari 4, and Chrome (and quite likely other versions of those browsers, which I simply haven't tested).
var getPrototypeOf;
if (Object.getPrototypeOf) {
getPrototypeOf = Object.getPrototypeOf;
} else if (typeof ({}).__proto__ === "object") {
getPrototypeOf = function(object) {
return object.__proto__;
}
} else {
getPrototypeOf = function(object) {
var constructor = object.constructor;
if (Object.prototype.hasOwnProperty.call(object, "constructor")) {
var oldConstructor = constructor; // save modified value
if (!(delete object.constructor)) { // attempt to "unmask" real constructor
return null; // no mask
}
constructor = object.constructor; // obtain reference to real constructor
object.constructor = oldConstructor; // restore modified value
}
return constructor ? constructor.prototype : null;
}
}
// jQuery.isPlainObject() returns false in IE for (new Object())
function isPlainObject(value) {
if (typeof value !== "object" || value === null) {
return false;
}
var proto = getPrototypeOf(value);
// the prototype of simple objects is an object whose prototype is null
return proto !== null && getPrototypeOf(proto) === null;
}
var serializablePrimitives = { "boolean" : true, "number" : true, "string" : true }
function isSerializable(value) {
if (serializablePrimitives[typeof value] || value === null) {
return true;
}
if (value instanceof Array) {
var length = value.length;
for (var i = 0; i < length; i++) {
if (!isSerializable(value[i])) {
return false;
}
}
return true;
}
if (isPlainObject(value)) {
for (var key in value) {
if (!isSerializable(value[key])) {
return false;
}
}
return true;
}
return false;
}
So yeah… I'd recommend the try/catch approach. ;-)
function isJSON(data) {
var isJson = false
try {
// this works with JSON string and JSON object, not sure about others
var json = $.parseJSON(data);
isJson = typeof json === 'object' ;
} catch (ex) {
console.error('data is not JSON');
}
return isJson;
}
You can use [json2.js] from Douglas Crockfords JSON Github site to parse it.
JSON is an encoding method not an internal variable type.
You might load in some text that is JSON encoded that javascript then uses to populate your variables. Or you might export a string that contains a JSON encoded dataset.
The only testing I've done is to check for a string, with and without double quotes, and this passes that test. http://forum.jquery.com/topic/isjson-str
Edit:
It looks like the latest Prototype has a new implementation similar to the one linked above. http://prototypejs.org/assets/2010/10/12/prototype.js
function isJSON() {
var str = this;
if (str.blank()) return false;
str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '#');
str = str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
str = str.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
return (/^[\],:{}\s]*$/).test(str);
}

Categories

Resources