Is it possible to do expressions/calculations in json?

Viewed 13141

I am using the wonderful json-server as the backend of my application and it's really useful for hitting custom endpoints to retrieve some data. but what would be super useful if it allowed me to do calculations/expression so that i can mimic that backend behaviour too.

take this data structure for example

{
  "products": [
    {
      "name": "football",
      "id": "SPO-001",
      "category": "sport",
      "price": 40,
      "couponApplied": "false",
      "coupons": [
        "daw124qdw",
        "a1212cxn"
      ]
    }
  ]
}

I would like some way of saying something like "discountPrice": couponApplied ? price * couponDiscount

that's just me pseudo coding. but I would like to do something where I can calculate the price on the fly. or when I make a request it does a calculation and returns me the calculated data (like a backend app would)

I understand I can make a request, apply the coupon and render that new price. or even make a post request and change the price. but that is all done client side. is there any way to do this either with json or json-server or any other solutions. if that makes sense?

6 Answers

JSON means JavaScript Object Notation and is data structure, and does not have any preprocessor for it. You can use any JSON parser and append/change values that you need dynamically.

So in short: no, there is no possibility to add dynamic values

No, you'll not be able to do computations inside json. The data would need to be mutated elsewhere and then sent.

No, it isn't possible to do math or any kind of expression in JSON as JSON is just a data structure format, and not a programming language.

You will need to load the JSON data in using a programming language of your choice, at which point you can then manipulate it.

For example, since you mention javascript a simple Node program as an example..

//It would be better to use the FileSystem API, but for simplicity for this example, I'm using require
var json = require('./myjson.json'); 
var product = json.products[0];

//Since the dataset has "false", this if will handle both "false" (string) and false (boolean) values. The value should really be boolean if possible
product.discountPrice = product.couponApplied && product.couponApplied !== "false" ? product.price * couponDiscount : null;

If you are trying to create logic dynamically, like user creates some logic, and you want to save it into DB and later apply it somewhere, these might be useful:

In your example, using formula parser could be like:

const response = {
  "products": [
    {
      "name": "football",
      "id": "SPO-001",
      "category": "sport",
      "price": 40,
      "couponApplied": "false",
      "coupons": [
        "daw124qdw",
        "a1212cxn"
      ]
    },
    {
      "name": "football",
      "id": "SPO-001",
      "category": "sport",
      "price": 40,
      "couponApplied": "true",
      "couponDiscount": 0.2,
      "coupons": [
        "daw124qdw",
        "a1212cxn"
      ]
    }
  ],
  formulaFields: {
    "discountPrice": 'IF("{couponApplied}"="true", {price} * {couponDiscount}, "")', // excel standard formula, with {variable} as product field keys
  }
}

const productsWithValues = response.products.map((product)=>{
  const productWithValues = { ...product };
  for (const field in response.formulaFields){
    const formula = response.formulaFields[field].replace(/\{([^\}]+)\}/g, (_, key) => product[key])
    const parser = new Parser();
    const { result } = parser.parse(formula);
    productWithValues[field] = result;
  }
  return productWithValues;
})
console.log(productsWithValues)

Output:

[
  {
    "name": "football",
    "id": "SPO-001",
    "category": "sport",
    "price": 40,
    "couponApplied": "false",
    "coupons": ["daw124qdw", "a1212cxn"],
    "discountPrice": null
  },
  {
    "name": "football",
    "id": "SPO-001",
    "category": "sport",
    "price": 40,
    "couponApplied": "true",
    "couponDiscount": 0.2,
    "coupons": ["daw124qdw", "a1212cxn"],
    "discountPrice": 8
  }
]

JSON doesn't support this, but if you turn it into a Javascript object, you could do something like this:

var obj = JSON.parse(
`{
  "products": [
    {
      "name": "football",
      "id": "SPO-001",
      "category": "sport",
      "price": 40,
      "couponApplied": "true",
      "couponDiscount": 0.5,
      "coupons": [
        "daw124qdw",
        "a1212cxn"
      ]
    }
  ]
}`).products[0];

Object.defineProperty(obj,"discountPrice",{
  get:function(){
    return (this.couponApplied==="true"||this.couponApplied===true) ? this.price*this.couponDiscount : this.price;
  },
  set:function(){
    return;
  }
});

console.log(obj.discountPrice);

This uses an accessor descriptor to define an object property that depends on the values of the other object properties.

Note that json-server allow you to add custom middleware. So you could write something like this:

const updateProduct = (p) => ({
  ...p,
  discountPrice: p.couponApplied ? p.price * p.couponDiscount : p.price
})

const transform = ({products, ...rest}) => ({
  ...rest, 
  products: products.map(updateProduct)
})

const modify = (req, res, next) => {
  if (req.path !== '/my-route') return next();

  res.body = JSON.stringify(transform(JSON.parse(res.body)))
  next();
}


// dummy call -- would really be handled by json-server/express

(() => {
  const req = {path: '/my-route'};
  const res = {body: `{"products":[{"name":"football","id":"SPO-001","category":"sport","price":40,"couponApplied":false,"coupons":["daw124qdw","a1212cxn"]},{"name":"helmet","id":"SPO-042","category":"sport","price":50,"couponApplied":true,"couponDiscount":0.75,"coupons":["foobarbaz"]}]}`}
  const next = () => {console.log(JSON.parse(res.body))}
  
  modify(req, res, next)
})()

Related