Search code examples
mulemule-el

Working with arrays within objects in expressions


Good morning! I'm trying to create a Web API using Mule that will transform one JSON-based request from system A into another JSON-based format, invoke a Web API on system B using the transformed JSON, take the JSON response from system B and transform it to some JSON that system A can understand, and return that result in the response to the original HTTP request. I have it mostly working, but I can't figure out how to reference arrays within properties. Here's the JSON going into the Expression component:

{
    "FooObjects":
    [
        {
            "FooPropertyOne": "value for property one"
          , "FooPropertyTwo": "value for property two"
          , "FooPropertyThree": "value for property three"
          , "FooId": 22031
          , "FooBarRelationships":
            [
                {
                    "FooBarRelationshipId": 18014
                  , "RelationshipProperty": "value for rel property"
                  , "Bar": { "BarPropertyOne": "value for property one", "BarId": 11379 }
                }
              , {
                    "FooBarRelationshipId": 18015
                  , "RelationshipProperty": "value for rel property"
                  , "Bar": { "BarPropertyOne": "value for property one", "BarId": 10001 }
                }
            ]
        }
    ]
}

Here's the result I want:

{
    "FooObjects":
    [
        {
            "FooPropertyOne": "value for property one"
          , "FooPropertyTwo": "value for property two"
          , "FooPropertyThree": "value for property three"
          , "FooId": 22031
          , "FooUrl": "https://server/path/to/foo?FooId=22013"
          , "Bars":
            [
                { "BarPropertyOne": "value for property one", "BarId": 11379 }
              , { "BarPropertyOne": "value for property one", "BarId": 10001 }
            ]
        }
    ]
}

Here's the expression component:

    <expression-component doc:name="Expression"><![CDATA[payload =
[
    "FooObjects": ([
        "FooPropertyOne": $.FooPropertyOne
      , "FooPropertyTwo": $.FooPropertyTwo
      , "FooPropertyThree": $.FooPropertyThree
      , "FooId": $.FooId
      , "FooURl": "https://server/path/to/foo?FooId=" + $.FooId
      , "Bars": $.FooBarRelationships
    ] in payload.FooObjects)
];]]></expression-component>

I've been guessing at the syntax to put in place of $.FooBarRelationships. The best I can come up with is (['BarPropertyOne':$.Bar.BarPropertyOne]in $.FooBarRelationships). This gets me:

[Error: could not access: Bar; in class: java.util.LinkedHashMap]
[Near : {... $.Bar.BarPropertyOne....}]
             ^

How can I perform this transformation? If I leave out the part about Bars, everything works fine, apart from not getting all of the data I need. Thanks!

edit: I changed the example to show the multiplicity more clearly.


Solution

  • The only way I've been able to make this work is via a function:

    <configuration>
        <expression-language>
            <global-functions>
                def makeBars(fooBarRelationships) {
                  (['BarPropertyOne':$.Bar.BarPropertyOne] in fooBarRelationships)
                }
            </global-functions>
        </expression-language>
    </configuration>
    

    then in flow I can use:

    <expression-component doc:name="Expression"><![CDATA[payload =
        [
            "FooObjects": ([
                "FooPropertyOne": $.FooPropertyOne
              , "FooPropertyTwo": $.FooPropertyTwo
              , "FooPropertyThree": $.FooPropertyThree
              , "FooId": $.FooId
              , "FooURl": "https://server/path/to/foo?FooId=" + $.FooId
              , "Bars": makeBars($.FooBarRelationships)
            ] in payload.FooObjects)
        ];]]></expression-component>