简体   繁体   中英

Can I have a dynamic output media type in a basic DataWeave transform?

I have a reasonably straight forward RESTful API written in Mule 4.1.5 which can produce XML or JSON based on the Accept header of the GET request.

For happy days scenarios where the data is retrieved and transformed from source, the transformations are different enough to justify separate dataweave scripts for each media type. But for the standard error situations (HTTP 400, 404, 405, 406 etc) in the API Kit error handler it is mostly just a canned response being returned, which can be created for either media type by the same script.

Is it possible to have one script which has a dynamic output media type based on the Accept Header?

My current approach (which does work) is to have a choice based on the accept header (which has been saved to a variable). But this is a bit clunky, and if there is a smarter way of doing it that would be great.

<choice doc:name="Route by Accept Header">
    <when expression="#[lower(vars.outputType) == 'application/xml']" >
        <ee:transform doc:name="XML">
            <ee:message>
                <ee:set-payload><![CDATA[%dw 2.0
output application/xml
---
{message: "Bad request"}]]></ee:set-payload>
            </ee:message>
            <ee:variables>
                <ee:set-variable variableName="httpStatus"><![CDATA[400]]></ee:set-variable>
            </ee:variables>
        </ee:transform>
    </when>
    <otherwise>
        <ee:transform doc:name="JSON">
            <ee:message >
                <ee:set-payload ><![CDATA[%dw 2.0
output application/json
---
{message: "Bad request"}]]></ee:set-payload>
            </ee:message>
            <ee:variables >
                <ee:set-variable variableName="httpStatus" ><![CDATA[400]]></ee:set-variable>
            </ee:variables>
        </ee:transform>
    </otherwise>
</choice>

There are a few options to achieve this.

First you can use the dynamic-evaluate component. Here are the docs: https://docs.mulesoft.com/mule-runtime/4.1/dynamic-evaluate-component-reference

In this example they use it to decide the output media type. But it still requires multiple scripts loaded from a db. You can tailor it to load from files or do some concatenation etc. For example here is a ROUGH example of building up the script using manual concatenation:

<set-variable value="application/xml" variableName="outputType" />
<set-variable value="#['output ' ++ lower(vars.outputType) ++ ' --- ' ++ '{message: \'Bad request\'}']" variableName="script" />

<ee:dynamic-evaluate expression="#[vars.script]" />

Second you can have all your transforms output 1 common media-type. Say application/java.

And then at the end call a flow-ref that does just the media-type mapping:

     <flow name="change-media-type">
            <choice>
                    <when expression="#[lower(vars.outputType) == 'application/xml']">
                        <set-payload value="#[output application/xml --- payload]" />
                    </when> 
                    <otherwise>
                        <set-payload value="#[output application/json --- payload]" />
                    </otherwise>
                </choice>
     </flow>
     ...

    <ee:transform>
        <ee:message>
           <ee:set-payload><![CDATA[%dw 2.0
    output application/java
    ---
    {message: "Bad request"}]]></ee:set-payload>
         </ee:message>
          <ee:variables>
              <ee:set-variable variableName="httpStatus"><![CDATA[400]] />
          </ee:variables>
    </ee:transform>

    <flow-ref name="change-media-type" />

Also note, using dynamic media type mapping you will need to make sure your body is always compatible with XML and JSON. Not all JSON payloads are compatible due to root elements etc in XML.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM