0
votes

I have a mule 3.7.3 workflow which accepts http POST requests and is being called from a UI application written in angular.

When the http POST call is made to Mule, it fails with method not allowed because the message is being sent with the http method set to OPTIONS. I have found that this is expected behaviour for applications that send XHR type messages which have the content type set to application/json and in these circumstances the UI application will send a preflighted OPTIONS request before sending the POST request.

My questions are:

  1. It it possible for the UI to only send the POST request?
  2. What is the best way for Mule to handle this? Will I need to add OPTIONS calls into the RAML file alongside all of the POST methods and create more workflows?

XML Flow:

<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:tracking="http://www.mulesoft.org/schema/mule/ee/tracking" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:cors="http://www.mulesoft.org/schema/mule/cors" xmlns:apikit="http://www.mulesoft.org/schema/mule/apikit" xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns:spring="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/cors http://www.mulesoft.org/schema/mule/cors/current/mule-cors.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/apikit http://www.mulesoft.org/schema/mule/apikit/current/mule-apikit.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.mulesoft.org/schema/mule/ee/tracking http://www.mulesoft.org/schema/mule/ee/tracking/current/mule-tracking-ee.xsd">
    <apikit:config name="test-order-config" raml="test-order.raml" consoleEnabled="true" consolePath="console" doc:name="Router">
        <apikit:flow-mapping resource="/orders/order" action="post" content-type="application/json" flow-ref="post:/orders/order:test-order-config"/>    
    </apikit:config>

    <cors:config name="Cors_Configuration" doc:name="Cors Configuration">
        <cors:origins>
            <cors:origin url="*">
                <cors:methods>
                    <cors:method>POST</cors:method>
                    <cors:method>DELETE</cors:method>
                    <cors:method>PUT</cors:method>
                    <cors:method>GET</cors:method>
                </cors:methods>
                <cors:headers>
                    <cors:header>content-type</cors:header>
                </cors:headers>
            </cors:origin>
        </cors:origins>
    </cors:config>

    <flow name="test-order-main">
        <http:listener config-ref="HTTP_Listener_Configuration" path="/*" doc:name="HTTP"/>
        <cors:validate config-ref="Cors_Configuration" publicResource="true" acceptsCredentials="false" doc:name="CORS Validate"/>
        <apikit:router config-ref="test-order-config" doc:name="APIkit Router"/>               
        <exception-strategy ref="test-order-apiKitGlobalExceptionMapping" doc:name="Reference Exception Strategy"/>
    </flow>

    <flow name="set-access-control-allow-values">
        <set-property propertyName="Access-Control-Allow-Origin" value="*" doc:name="Set Access Control Allow Origin"/>
        <set-property propertyName="Access-Control-Allow-Credentials" value="false" doc:name="Set Access Control Allow Credentials"/>
        <set-property propertyName="Access-Control-Allow-Methods" value="GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS" doc:name="Set Access Control Allow Methods"/>
        <set-property propertyName="Access-Control-Allow-Headers" value="DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,origin,authorization,accept,client-security-token" doc:name="Set Access Control Allow Headers"/>
    </flow>

    <flow name="get:/products:test-order-config">
        <set-payload value="#['{ &quot;getProducts&quot;: { &quot;productsList&quot;: [{ &quot;productId&quot;: &quot;001&quot;, &quot;name&quot;: &quot;test_product1&quot;}]}}']" doc:name="Set Payload"/>
        <flow-ref name="set-access-control-allow" doc:name="set-access-control-allow"/>
        <logger message="#[payload]" level="INFO" doc:name="Logger"/>
    </flow>

    <flow name="get:/customer/{customerId}:test-order-config">
        <set-payload value="#['{&quot;getCustomer&quot;:{&quot;customerId&quot;:&quot;1234567890&quot;,&quot;title&quot;:&quot;MR&quot;,&quot;Name&quot;:&quot;John&quot;}}']" doc:name="Set Payload"/>
        <flow-ref name="set-access-control-allow" doc:name="set-access-control-allow"/>
        <logger message="#[payload]" level="INFO" doc:name="Logger"/>
    </flow>

    <flow name="post:/orders/order:test-order-config">
        <set-payload value="#['{&quot;createOrder&quot;:{&quot;orderId&quot;:&quot;8a493ecd-e842-4ca2-b33b-a03aa9136673&quot;,&quot;success&quot;:true}}']" doc:name="Set Payload"/>
        <flow-ref name="set-access-control-allow" doc:name="set-access-control-allow"/>
        <logger message="#[payload]" level="INFO" doc:name="Logger"/>
    </flow>

    <apikit:mapping-exception-strategy name="test-order-apiKitGlobalExceptionMapping">
        <apikit:mapping statusCode="404">
            <apikit:exception value="org.mule.module.apikit.exception.NotFoundException"/>
            <set-property propertyName="Content-Type" value="application/json" doc:name="Property"/>
            <set-payload value="{ &quot;message&quot;: &quot;Resource not found&quot; }" doc:name="Set Payload"/>
        </apikit:mapping>
        <apikit:mapping statusCode="405">
            <apikit:exception value="org.mule.module.apikit.exception.MethodNotAllowedException"/>
            <set-property propertyName="Content-Type" value="application/json" doc:name="Property"/>
            <set-payload value="{ &quot;message&quot;: &quot;Method not allowed&quot; }" doc:name="Set Payload"/>
        </apikit:mapping>
        <apikit:mapping statusCode="415">
            <apikit:exception value="org.mule.module.apikit.exception.UnsupportedMediaTypeException"/>
            <set-property propertyName="Content-Type" value="application/json" doc:name="Property"/>
            <set-payload value="{ &quot;message&quot;: &quot;Unsupported media type&quot; }" doc:name="Set Payload"/>
        </apikit:mapping>
        <apikit:mapping statusCode="406">
            <apikit:exception value="org.mule.module.apikit.exception.NotAcceptableException"/>
            <set-property propertyName="Content-Type" value="application/json" doc:name="Property"/>
            <set-payload value="{ &quot;message&quot;: &quot;Not acceptable&quot; }" doc:name="Set Payload"/>
        </apikit:mapping>
        <apikit:mapping statusCode="400">
            <apikit:exception value="org.mule.module.apikit.exception.BadRequestException"/>
            <set-property propertyName="Content-Type" value="application/json" doc:name="Property"/>
            <set-payload value="{ &quot;message&quot;: &quot;Bad request&quot; }" doc:name="Set Payload"/>
        </apikit:mapping>
    </apikit:mapping-exception-strategy>

</mule>

Thanks

1
I dont know mule but you have to make it accept OPTIONS. The request does not need to return any result but should respond with 200 status.Paulson Peter
probably you're facing it for CORS. Can you post the actual errorstring.Amit Kumar Ghosh

1 Answers

1
votes

That's a CORS issue, the OPTIONS request is a pre-flight request.

Use the CORS module to allow OPTIONS or make it public to accept all:

<cors:config name="corsConfig" />

<flow name="rest-api-main" doc:name="rest-api-main">
        <http:listener path="api/${api.version}/*" config-ref="restAPIMainHttpConfig" />

        <cors:validate config-ref="corsConfig" publicResource="true" />
</flow>

Update

xmlns:core="http://www.mulesoft.org/schema/mule/core" 

and

http://www.mulesoft.org/schema/mule/cors http://www.mulesoft.org/schema/mule/cors/current/mule-cors.xsd

But if you drag it from the palette in studio it will auto add it.

And heres the Maven dependency:

    <dependency>
        <groupId>org.mule.modules</groupId>
        <artifactId>mule-module-cors</artifactId>
        <version>2.1.1</version>
    </dependency>