I am using the REST-SOAP-REST proxy-api
My WSDL endpoint consist of 3 parameters, call them p1, p2, p3. All of them are optional and has [0-9A-Za-Z]{8} 8 characters constraint for validation.
After deploying my WSDL, I attempted the rest call by doing http://xxx.xxx/myendpoint?p1=xx&p3=xx
Unfortunately I get an error doing that because it is saying p2 is not passing validation. So the leads me to think that even though I did not pass that parameter in the REST call, the proxy is passing p2 as an empty string to the WSDL endpoint.
Is there a way for me to not include parameters that are null?
Hi Churk,
How do you indicate your parameters are optional? Would you be willing to share your WSDL so we can debug it? If not, could you at least show the snippet where you indicate it's optional?
Thanks,
Charles
<s:element minOccurs="0" maxOccurs="1" name="param1" type="s:string"/> <s:element minOccurs="0" maxOccurs="1" name="param2" type="s:guid"/> <s:element minOccurs="0" maxOccurs="1" name="param3" type="s:string"/> <s:schema elementFormDefault="qualified" targetNamespace="http://microsoft.com/wsdl/types/"> <s:simpleType name="guid"> <s:restriction base="s:string"> <s:pattern value="[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"/> </s:restriction> </s:simpleType> </s:schema>
If you inspect your proxy there will be a AssignMessage Policy in request flow that produces the soap payload. currently, it includes all the parameters.
While charles is looking into this, one of the things you could do is to change the behavior how this soap payload is produced. For eg, you could create the soap payload either in Java or Js based on the input parameters and use it in you AssignMessage policy. Not ideal, but it would help overcome this for now
It's all good @mukundha@apigee.com I already came up with a solution using javascript policy.
For those who find this later and are looking for a solution to a similar problem I recommend the following pattern:
Examples:
ExtractCouponVariables
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <ExtractVariables async="false" continueOnError="false" enabled="true" name="extractCouponVars"> <DisplayName>extractCouponVars</DisplayName> <URIPath> <Pattern ignoreCase="true">/{version}/coupons/{coupon.code}</Pattern> </URIPath> <URIPath> <Pattern ignoreCase="true">/{version}/profile/{profile.aliasId}/coupons/{coupon.code}</Pattern> </URIPath> <QueryParam name="couponcode"> <Pattern ignoreCase="true">{coupon.code}</Pattern> </QueryParam> <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables> </ExtractVariables>
The Javascript code that builds the optional query elements for the SOAP message:
var filterOptions = ""; var entitled=context.getVariable("request.queryparam.entitled"); if(entitled==="true") entitled="Entitled"; else if(entitled==="false") entitled="NotEntitled"; if (entitled) { if (filterOptions === "") filterOptions = "<Option type=\"filter\">EntitlementState==" + entitled; else filterOptions += "&&EntitlementState=" + entitled; } var propogationState = context.getVariable("request.queryparam.propagation"); if (!propogationState || propogationState === "") propogationState = "true"; switch (propogationState) { case "true": if (filterOptions === "") filterOptions = "<Option type=\"filter\">[CustomProperties.href^propagationState&&CustomProperties==true]"; else filterOptions += "&&[CustomProperties.href^propagationState&&CustomProperties==true]"; break; case "false": if (filterOptions === "") filterOptions = "<Option type=\"filter\">[CustomProperties.href^propagationState&&CustomProperties==false]"; else filterOptions += "&&[CustomProperties.href^propagationState&&CustomProperties==false]"; break; } if (filterOptions !== "") filterOptions += "</Option>"; context.setVariable("coupon.filterOptions", filterOptions);
And finally the build SOAP policy (edited for privacy):
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <AssignMessage name="buildCouponLookup"> <DisplayName>buildCouponLookup</DisplayName> <AssignTo createNew="true" type="request">request</AssignTo> <Set> <Headers> <Header name="Content-Type">text/xml; charset=utf-8</Header> </Headers> <Payload contentType="text/xml"> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soap:Body> <fetchCoupon xmlns="http://soap.foo.com/v4_2/Coupon"> <auth> <version>4.2</version> <login>{target.username}</login> <password>{target.password}</password> </auth> <couponId>{coupon.code}</couponId> {coupon.filterOptions} </fetchCoupon> </soap:Body> </soap:Envelope> </Payload> <Verb>POST</Verb> </Set> <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables> </AssignMessage>
Of note here is the IgnoreUnresolvedVariables option in the AssignMessage policy - this allows the policy to execute even if we don't have a value for coupon.filterOptions - that line is blank in that case allowing us to achieve an optional filtered query with the same policy as an unfiltered query for all coupons matching a particular code.
The downside of this approach is the JSC can get fairly complex when you have many different options. In cases where this complexity is too great we find it worthwhile to replicate the build policies and live with the redundancy of the configuration in favor of readability and reduced complexity.