user3165854
user3165854

Reputation: 1655

Http POST call returns Method not allowed error in Mule because http method is being set to OPTIONS

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

Upvotes: 0

Views: 2876

Answers (1)

Ryan Carter
Ryan Carter

Reputation: 11606

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>

Upvotes: 1

Related Questions