Search code examples
jsonpowershelldictionaryserializationinvoke-restmethod

Serialize REST response in powershell


I'm connecting to a REST service

$response = Invoke-RestMethod -Uri $URL -Headers $headers -Method POST -Body $body_json -ContentType "application/json" 
$response.Outputs

and I get a response in that format

    Actual: {
        "2017-08-29T14:37:47.137",
        "2017-08-30T13:07:09.563",
        "2017-08-30T14:41:29.023"
    },
    Start: {
        "2017-08-29T14:36:12.42",
        "2017-08-30T12:59:53.05",
        "2017-08-30T14:40:45.34"
    },
    NumScrapsList: {
        0,
        3,
        ...
        

but I would like to have it in that form

    {   
        "NumScrapsList":0,
        "Actual":"2017-08-29T14:37:47.137",
        "Start":"08-29T14:36:12.42"
    },
    {
        "NumScrapsList":3,
        "Actual":"2017-08-30T13:07:09.563",
        "Start":"2017-08-30T12:59:53.05"
    }

In a pythonic approach I can do it like so (including "outputs" key):

outputs = [dict(zip(resp['Outputs'].keys(), e))
           for e in zip(*resp['Outputs'].values())]

pprint(outputs)

but in powershell I cannot know how to do it. Could you put me in the right direction?

EDIT with the full $response.outputs from Invoke-RestMethod

the $response.outputs is

Type         : {a, b, c}
Code        : {xxx, yyy, eee}
CompletionDate : {1900-01-01T00:00:00, 1900-01-01T00:00:00, 1900-01-01T00:00:00}
OrderQuantity        : {30, 30, 3}
NumScraps            : {0, 0, 0}
ActualDate      : {2021-11-16T15:17:00, 2021-11-16T15:18:00, 1900-01-01T00:00:00}
Status               : {WT, FD, RT}
Order           : {70000, 30794, 94098}
Sequence        : {0300, 0400, 0500}

Then I can convertto-json and the output is:

{
    "Type":  [
                         "a",
                         "b",
                         "c"
                     ],
    "Code":  [
                          "xxx",
                          "yyy",
                          "eee"
                      ],
    "CompletionDate":  [
                                 "1900-01-01T00:00:00",
                                 "1900-01-01T00:00:00",
                                 "1900-01-01T00:00:00"
                             ],
    "OrderQuantity":  [
                          30,
                          30,
                          3
                      ],
    "NumScraps":  [
                      0,
                      0,
                      0
                  ],
    "ActualDate":  [
                            "2021-11-16T15:17:00",
                            "2021-11-16T15:18:00",
                            "1900-01-01T00:00:00"
                        ],
    "Status":  [
                   "WT",
                   "FD",
                   "RT"
               ],
    "Order":  [
                       "70000",
                       "30794",
                       "94098"
                   ],
    "Sequence":  [
                          "0300",
                          "0400",
                          "0500"
                      ]
}

that said the waitingforguacamole solution works even if is a bit tricky (and thanks, sure, for your help!)


Solution

  • OK, I took a shot at this, perhaps inelegantly (it's neither functional nor Pythonic), and I'm sure others will have far more expressive methods of doing this, but this could be a start:

    I cleaned up the JSON to look like this

    {
        "Actual": [
            "2017-08-29T14:37:47.137",
            "2017-08-30T13:07:09.563",
            "2017-08-30T14:41:29.023"
        ],
        "Start": [
            "2017-08-29T14:36:12.42",
            "2017-08-30T12:59:53.05",
            "2017-08-30T14:40:45.34"
        ],
        "NumScrapsList": [
            0,
            3,
            7
        ]
    }
    

    (I added a value to NumScrapsList for completeness, and turned each top-level JSON field into an array)

    Then,

    #simulate your REST method call result
    $json = "{
        `"Actual`": [
            `"2017-08-29T14:37:47.137`",
            `"2017-08-30T13:07:09.563`",
            `"2017-08-30T14:41:29.023`"
        ],
        `"Start`": [
            `"2017-08-29T14:36:12.42`",
            `"2017-08-30T12:59:53.05`",
            `"2017-08-30T14:40:45.34`"
        ],
        `"NumScrapsList`": [
            0,
            3,
            7
        ]
    }"
    
    #create a field map
    $fieldMap = @("NumScrapsList", "Start", "Actual")
    
    #convert the JSON to a Powershell object, create an empty array
    $in = $json | ConvertFrom-JSON
    
    #using NumScrapsList as your iterator
    0..($in.NumScrapsList.Count-1) | ForEach-Object {
        $fieldMap | ForEach-Object -Begin {
            #reference the outer loop index
            $index = $_
            #initialize an accumulator for the object whose properties to be mapped
            $obj = @{}
        } -Process {
            #in order of fieldMap's properties, grab those fields from the input
            #and add them to the accumulator by name
            $obj."$_" = $in."$_"[$index]
        } -End {
            #return that accumulator
            $obj
        }
    } | ConvertTo-Json
    

    and that processing block can be reduced to:

    $fieldMap = @("NumScrapsList", "Start", "Actual"); 
    $in = $json | ConvertFrom-JSON
    0..($in.NumScrapsList.Count-1) | ForEach-Object { 
        $fieldMap | ForEach-Object { $index = $_; $obj = @{} } {
            $obj."$_" = $in."$_"[$index]
        } { $obj }
    } | ConvertTo-Json