0

I am making a simple get request to an API endpoint.

 request(URL, {headers},(err,res,body) => {
        if(err){return log(err)}
        // object keys are sorted but body is a string, not JSON yet.
        log(body);
        const obj = JSON.parse(body);
        // object keys are sorted. no good.
        log(obj);
    })

The structure of the API is as follows.

"data": {
 "965841069":"cmfvFd}leMvA_F`@wDNc@"
 "380131943":"whhvF|emeMr@jAbChDTVvChCdCdAtCz@xFd@zGR"
 "486015769":"i}dvFnpkeMxFiC"
 "646940714":"sydvFt~jeM_HrA"
 "248417189":"{}dvFxpkeMwCoN"
 "659848152":"oudvFdlkeMuB{K"
 "688067745":"k|ivFliieM|@t@z@Id@q@KoA]g@a@Y"
 "500301841":"adfvFpwleMbTqT"
 "537970914":"uqivFffjeMW@"
}

As you can see the keys ( which are dynamic, I have no way of knowing in advance what it will be) are not sorted ( in terms of their integer value) which is exactly what I want.

However when I use request to make a get request I get the following result (for example):

"data":{
 "543144906":"unfvF|_meMm@fF"
 "554312533":"cgfvF|jleMYB{@CYGm@VWh@MhAElA"
 "576762470":"eydvFh_keMMS"
 "614379898":"qzevF`ukeM}GzOiAvBi@f@"
 "616186189":"{}dvFxpkeMPI"
 "620745528":"}nevF~aleM~HkI`FyE"
 "622882868":"mmfvFnqleMa@`MEJ"
 "636661460":"_dgvFpxmeMjCGd@E~Aa@zAw@`As@^_@d@g@p@aA|@eBZiAPc@\eB? 
 [h@oF"
}

Here the keys are sorted which is not what the API returns. I know JSON objects do not have order but is there any way to preserve the structure/order of the original object from the API in the response object?

I have attemped at getting the response as a string and then parsing it manually but there must be a more sane solution.

Note: I dont feel this is a duplicate because in my case the keys are dynamic and I have no control over the API structure ( can't change from object to array/map)

Ridhwaan
  • 57
  • 8
  • 1
    Will the keys always follow the same format? You could use a Regular Expression to extract them from the JSON string. e.g. `/"(\d{9})":"/g` – RobertAKARobin Aug 28 '19 at 20:07
  • I'm just curious why you want to do that – Marc Sloth Eastman Aug 28 '19 at 20:08
  • Why does the order of the keys matter? You should use an array if order is significant. – Barmar Aug 28 '19 at 20:09
  • 1
    Are you sure they are not in the original order? How are you determining the new order? Note that the console in, say, Chrome automatically sorts the keys of objects... – Heretic Monkey Aug 28 '19 at 20:09
  • Possible duplicate of [Keep order of objects inside a JSON String after they are parsed](https://stackoverflow.com/questions/32006162/keep-order-of-objects-inside-a-json-string-after-they-are-parsed) – Heretic Monkey Aug 28 '19 at 20:10
  • @Barmar The keys need to be ordered because they are polyline encodings and need to be ordered for them be drawn correctly. What do you mean I need to use an array? Do I set my body object to be a new array variable? – Ridhwaan Aug 28 '19 at 20:15
  • It would be best to use an array. Prior to ES6, there was no guarantee that object keys remembered the order they were added. I'm not sure if JSON parsing is guaranteed to retain the order. – Barmar Aug 28 '19 at 20:17
  • @HereticMonkey I am using console.log function in node.js. I am logging the body object , then i JSON.parse(body), then log that and see that it is different. – Ridhwaan Aug 28 '19 at 20:21

2 Answers2

1

Following @RobertAKARobin advice, I get the response of the axios get request as a raw string by setting the responseType : 'arraybuffer' and transformResponse :undefined. Then I captured the result in a Buffer which allowed me to view the response as a raw string. Then I used regex to find each occurrence of the key and replaced it with a running count (i). Then I called JSON.parse() which parses the object without sorting which is just what I wanted.

Here is the code.

const cleanSegmentsResult = result => {
    const b = new Buffer(result.data,'binary');
    const str = b.toString();
    const regexp = /"(\d{9})"/;

    // replace each 9 digit number (the keys to each segment) with a random key. 
    // This prevents JSON.parse from sorting the keys and messing with the segments
    let i = 0;
    let prev = str;
    let running_str = '';
    while(prev.match(regexp) != null){
        running_str = prev.replace(regexp,`\"key${i}\"`);
        prev = running_str;
        i++;
    }
    const final_segments = JSON.parse(running_str)
    return final_segments;     
}

Ridhwaan
  • 57
  • 8
-1

There are some thoughts below: Keep order of objects inside a JSON String after they are parsed

But actually properties are unordered in JS. Not only in JSON. And even if to perform some workaround like parsing - it is not a good practice.

Better solution would be to use array instead. Or Map - depending on your purposes.

Alex Vovchuk
  • 2,828
  • 4
  • 19
  • 40
  • 1
    What do you mean return it as an array? Do you mean changing the API structure? I can not do that as it is a remote API. – Ridhwaan Aug 28 '19 at 20:28
  • Yes, I meant that. If you can't change API but order is required then only workaround can be used. Nothing better then custom parsing function comes to my mind. JSON.stringify saves order, but JSON.parse doesn't. – Alex Vovchuk Aug 28 '19 at 20:33