0

We have

  1. C# WebAPI server backend
  2. node JS client SPA frontend

One of our APIs generates a C# object which represents a ChartJS model. Like so

public virtual IActionResult Chart()
{
        var chartModel = GetChart();
        return new ObjectResult(chartModel);
}

The ChartModel class simplified looks like this

public class ChartJSModel
{
    ...
    public string callback { get; set; } //FUNCTION
    ...
}

The client receives this JSON ObjectResult (again simplified)

{
    "callback": "function(value, index, values) { return Number(value.toString());}"        
}

The callback function is in quotes. This breaks ChartJS.

Question

  1. So JSON is purely meant for data description language but how do I get the C# WebAPI to send back the callback without quotes?
  2. I could process the JSON on the client but maybe there is an alternative.
robor
  • 2,969
  • 2
  • 31
  • 48
  • you can't have functions in JSON - in JSON, values can only be ... object, array, string, number, null, true or false – Jaromanda X Sep 19 '19 at 12:20
  • 1
    Whenever response happen, model will convert to json so better to handle it UI side or as alternate use xml as media formatter instead json and then convert xml to json at ui side. I know its not optimal solution but just to fulfill your purpose. – Harshad Vekariya Sep 19 '19 at 12:31
  • 1
    that's not to say what you want to do is unachievable - you'll just have to think outside the box ... e.g. on the server send `{ "callback": "fn1" }` ... in the client, process the parsed JSON (i,e, the javascript Object you now have) and look for `callback` key, and changing the value accordingly ... "fn1" to `function(....` etc – Jaromanda X Sep 19 '19 at 12:33
  • @HarshadVekariya - how will XML, also a text only response, help – Jaromanda X Sep 19 '19 at 12:33
  • Check answer to return xml: https://stackoverflow.com/questions/18266952/asp-net-web-api-returning-xml-instead-of-json . Though its for json but you can change code accordingly. – Harshad Vekariya Sep 19 '19 at 12:38
  • @HarshadVekariya - "though it's for JSON" ... well, that's **exactly** what the OP is using ... and how is that link at all relevant? How will XML help? – Jaromanda X Sep 19 '19 at 12:39

1 Answers1

1

you can't have functions in JSON - in JSON, values can only be ... object, array, string, number, null, true or false

that's not to say what you want to do is unachievable - you'll just have to think outside the box ... e.g. on the server send { "callback": "fn1" } ... in the client, process the parsed JSON (i,e, the javascript Object you now have) and look for callback key, and changing the value accordingly ... "fn1" to function(.... etc

so, if you change your server code to send something like

{
    "type": "line",
    "data": {
        "datasets": [
        ]
    },
    "options": {
        "scales": {
            "xAxes": [{
                    "type": "logarithmic",
                    "position": "bottom",
                    "ticks": {
                        "beginAtZero": false,
                        "min": 0.0,
                        "max": "NaN",
                        "stepSize": "NaN",
                        "callback": "fn1"
                    },
                }
            ],
            "yAxes": [{
                    "type": "logarithmic",
                    "position": "left",
                    "ticks": {
                        "beginAtZero": false,
                        "min": 0.0,
                        "max": "NaN",
                        "stepSize": "NaN",
                        "callback": "fn1arrow"
                    },
                }
            ]
        },

    }
}

Then you can write a function like

function fixCallbacks(obj) {
    const fns = {
        fn1: function(value, index, values) { return Number(value.toString());},
        fn1arrow: (value, index, values) => Number(value.toString()),
    };
    Object.entries(obj).forEach(([k, v]) => {
        if (typeof v === 'object' || typeof v === 'array') {
            fixCallbacks(v);
        } else if (k === 'callback') {
            obj[k] = fns[v] || obj[k];
        }
    });
}

Note: fn1 and fn1arrow do the same thing, just showing you can use functions and arrow functions as a solution

And it should work - like this

const data = {
    "type": "line",
    "data": {
        "datasets": [
        ]
    },
    "options": {
        "scales": {
            "xAxes": [{
                    "type": "logarithmic",
                    "position": "bottom",
                    "ticks": {
                        "beginAtZero": false,
                        "min": 0.0,
                        "max": "NaN",
                        "stepSize": "NaN",
                        "callback": "fn1"
                    },
                }
            ],
            "yAxes": [{
                    "type": "logarithmic",
                    "position": "left",
                    "ticks": {
                        "beginAtZero": false,
                        "min": 0.0,
                        "max": "NaN",
                        "stepSize": "NaN",
                        "callback": "fn1arrow"
                    },
                }
            ]
        },

    }
};

function fixCallbacks(obj) {
    const fns = {
        fn1: function(value, index, values) { return Number(value.toString());},
        fn1arrow: (value, index, values) => Number(value.toString()),
    };
    Object.entries(obj).forEach(([k, v]) => {
        if (typeof v === 'object' || typeof v === 'array') {
            fixCallbacks(v);
        } else if (k === 'callback') {
            obj[k] = fns[v] || obj[k];
        }
    });
}

// here we "fix" the data
fixCallbacks(data);
//
console.log(data);
Jaromanda X
  • 53,868
  • 5
  • 73
  • 87
  • Thanks for that Javascript in the middle. – robor Sep 19 '19 at 12:59
  • @robor78 - not sure what you mean by "that Javascript in the middle" - it's the code you would need, the snippet is to demonstrate it works : – Jaromanda X Sep 19 '19 at 13:01
  • I'm refering to fixCallbacks. My javascript is a little rusty, so I was already wondering how to find all the "callbacks" in the JSON object. Your function fixCallbacks does that. Thanks. – robor Sep 19 '19 at 13:03