how to make http request from xml soap? - node.js

I am implementing one of the payment gateway(Advance cash) in my application.Here is the link :
Adv documentaion
According to its documentation I have to made request for transaction. But the request mention in it in xml format.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsm="http://wsm.advcash/">
<soapenv:Header/>
<soapenv:Body>
<wsm:sendMoney>
<arg0>
<apiName>api_name</apiName>
<authenticationToken>token</authenticationToken>
<accountEmail>name#example.com</accountEmail>
</arg0>
<arg1>
<amount>1.00</amount>
<currency>USD</currency>
<email>name#example.com</email>
<note>Some note</note>
<savePaymentTemplate>false</savePaymentTemplate>
</arg1>
</wsm:sendMoney>
</soapenv:Body>
</soapenv:Envelope>
I think it is kind of soap request,I want to know how to request this and what are the parameters I have to send using my node js application using "request" npm module.Please help.

You should use node-soap package. There is a request option which override the request module.

I made a sample, take a look
service.ts:
const service = {
UserService: {
ServicePort: {
getUserById(args) {
const user = { id: args.id, name: faker.name.findName(), email: faker.internet.email() };
return user;
}
}
}
};
service.wsdl:
<definitions name="Service" targetNamespace="http://localhost:8001/get-started/service.wsdl"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://localhost:8001/get-started/service.wsdl"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<message name="GetUserByIdInput">
<part name="id" type="xsd:string"></part>
</message>
<message name="GetUserByIdOutput">
<part name="id" type="xsd:string"></part>
<part name="name" type="xsd:string"></part>
<part name="email" type="xsd:string"></part>
</message>
<portType name="ServicePortType">
<operation name="getUserById">
<input message="tns:GetUserByIdInput"/>
<output message="tns:GetUserByIdOutput"></output>
</operation>
</portType>
<binding name="ServiceSoapBinding" type="tns:ServicePortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="getUserById">
<soap:operation soapAction="getUserById"/>
<input message="tns:GetUserByIdInput">
<soap:body parts="id" use="literal"/>
</input>
<output message="tns:GetUserByIdOutput">
<soap:body parts="id" use="literal"/>
<soap:body parts="name" use="literal"/>
<soap:body parts="email" use="literal"/>
</output>
</operation>
</binding>
<service name="UserService">
<documentation>Get started service</documentation>
<port name="ServicePort" binding="tns:ServiceSoapBinding">
<soap:address location="http://localhost:8001/get-started"/>
</port>
</service>
</definitions>
request.xml:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tns="http://localhost:8001/get-started/service.wsdl">
<soap:Body>
<tns:getUserById>
<id>8104d3c3-de13-432f-b4a0-a62f84f6206a</id>
</tns:getUserById>
</soap:Body>
</soap:Envelope>
server.spec.ts:
it('should get correct result using http request and static xml', async (done: jest.DoneCallback) => {
const xml = fs.readFileSync(path.resolve(__dirname, './static-xml.xml'), 'utf8');
const uuid = '8104d3c3-de13-432f-b4a0-a62f84f6206a';
const options = {
url,
method: 'POST',
body: xml,
headers: {
'Content-Type': 'text/xml;charset=utf-8',
'Accept-Encoding': 'gzip,deflate',
'Content-Length': xml.length
}
};
const rawXml = await request(options);
parser.parseString(rawXml, (err, actualValue) => {
if (err) {
done(err);
}
console.log('actualValue: ', JSON.stringify(actualValue));
expect(actualValue['soap:Envelope']['soap:Body']['tns:getUserByIdResponse']['tns:id']).toBe(uuid);
done();
});
});
The result:
actualValue: {"soap:Envelope":{"$":{"xmlns:soap":"http://schemas.xmlsoap.org/soap/envelope/","xmlns:tns":"http://localhost:8001/get-started/service.wsdl"},"soap:Body":{"tns:getUserByIdResponse":{"tns:id":"bf0f6172-2f53-4b33-94c8-9ff9ed8fd431","tns:name":"Theo Leannon","tns:email":"Brent.Berge#hotmail.com"}}}}
Here is the demo: https://github.com/mrdulin/nodejs-soap/tree/master/src/get-started

Related

Mule application blocked all of a sudden due to CORS

I have been playing with React, Node and Mule in order to make requests go through Mule. I managed to get it all working but today for some reason I get an ERROR:
Access to XMLHttpRequest at 'http://localhost:88/api/courses/pizza' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
This ERROR was not there before, everything was perfectly working and it was returning JSON as it is supposed to. I reverted all changes I made but to no avail. I even used allow CORS extension for chrome but then it seemed like requests didn't even reach the Mule application executing in Anypoint Studio, since it returned no message. My Mule is on PORT 88, React 3000 and Node on 1234. I tried to use CORS interceptor in Anypoint Studio too according to this tutorial: https://dzone.com/articles/enable-cors-into-mule-4-at-application-level but that didn't help either. Please leave some advices as to what else I can try.
React request:
export default function APIRequest(url, method, body) {
return fetch(url, {
method: method,
body: body,
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
});
}
Node:
router.get("/:name", async (req, res) => {
console.log(req.params.name);
const courses = await Course.find();
course = courses.filter((course) => course.category === req.params.name);
res.send(course);
});
Mule:
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:ee="http://www.mulesoft.org/schema/mule/ee/core" xmlns:wsc="http://www.mulesoft.org/schema/mule/wsc"
xmlns:http="http://www.mulesoft.org/schema/mule/http"
xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation" 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/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/wsc http://www.mulesoft.org/schema/mule/wsc/current/mule-wsc.xsd
http://www.mulesoft.org/schema/mule/ee/core http://www.mulesoft.org/schema/mule/ee/core/current/mule-ee.xsd">
<http:listener-config name="HTTP_Listener_configuration" doc:name="HTTP_Listener_configuration" doc:id="70a95691-a977-48ff-8439-79a5d2fc7bb7" >
<http:listener-connection host="0.0.0.0" port="88" />
<http:listener-interceptors >
<http:cors-interceptor >
<http:origins>
</http:origins>
</http:cors-interceptor>
</http:listener-interceptors>
</http:listener-config>
<wsc:config name="Web_Service_Consumer_Config" doc:name="Web Service Consumer Config" doc:id="0a403287-6d01-45e1-bb5f-47ffcc7a5f71" >
<wsc:connection wsdlLocation="https://www.dataaccess.com/webservicesserver/NumberConversion.wso?wsdl" service="NumberConversion" port="NumberConversionSoap" address="https://www.dataaccess.com/webservicesserver/NumberConversion.wso">
<wsc:web-service-security actor="http://schemas.xmlsoap.org/soap/actor/next" />
</wsc:connection>
</wsc:config>
<http:request-config name="First_REST_API" doc:name="HTTP Request configuration" doc:id="84f17cc0-eb86-4c2a-b122-7d5f22781423" basePath="https://random-data-api.com/api/number/random_number?size=1" >
<http:request-connection protocol="HTTPS" />
</http:request-config>
<http:request-config name="HTTP_Request_configuration" doc:name="HTTP Request configuration" doc:id="93a99571-d4d7-43c3-9505-26f2a56e97b3">
<http:request-connection protocol="HTTPS" />
</http:request-config>
<http:request-config name="HTTP_Request_configuration1" doc:name="HTTP Request configuration" doc:id="282ae316-cee6-4305-ae58-283858258ec6">
<http:request-connection protocol="HTTPS" host="random-data-api.com"/>
</http:request-config>
<http:request-config name="Local_REST_API_Config" doc:name="HTTP Request configuration" doc:id="6cf97fb4-f770-44fb-b450-4ccccf29db1a" >
<http:request-connection host="localhost" port="1234" />
</http:request-config>
<http:listener-config name="HTTP_Listener_config" doc:name="HTTP Listener config" doc:id="0a9a912a-50df-4963-b17a-f61f53aaa656" >
<http:listener-connection host="0.0.0.0" port="3001" readTimeout="3000"/>
</http:listener-config>
<flow name="GET:\courses\id-find_course_by_id" doc:id="e4042d03-603f-41c5-91a1-e12c2992d75e" >
<http:listener doc:name="Listener with URI ID" doc:id="b1ecf442-8975-4385-b11b-cac1677613ef" config-ref="HTTP_Listener_configuration" path="/api/courses/find/{id}" />
<set-payload value="#[attributes.uriParams.id]" doc:name="Set payload with URI ID" doc:id="8499152a-c601-488c-8cbd-2a081e38b20f" />
<http:request method="GET" doc:name="REST API request for Course with ID" doc:id="d17382dd-e848-44fc-b4e4-495991b61325" config-ref="Local_REST_API_Config" path="/api/courses/find/{id}" outputMimeType="application/json">
<http:body><![CDATA[{}]]></http:body>
<http:uri-params><![CDATA[#[output application/java
---
{
id: payload
}]]]></http:uri-params>
</http:request>
<set-variable value='#[output application/json
---
{
isPublished: payload.isPublished,
tags: payload.tags map ( tag , indexOfTag ) -> tag,
"_id": payload."_id",
dishName: payload.dishName,
category: payload.category,
author: payload.author,
ingredients: payload.ingredients map ( ingredient , indexOfIngredient ) -> {
"_id": ingredient."_id",
quantity: ingredient.quantity,
unit: ingredient.unit,
description: ingredient.description
},
cookingTime: payload.cookingTime,
sourceUrl: payload.sourceUrl,
imageUrl: payload.imageUrl,
price: payload.price,
date: payload.date,
"__v": payload."__v"
}]' doc:name="Set variable with response JSON" doc:id="f712c7d0-65a8-48ab-a7a4-088ba23c9956" variableName="results" mimeType="application/json" />
<http:request method="GET" doc:name="Call REST API for random number" doc:id="90a7f6f5-aeba-4b28-a5af-43dcd4b87e16" config-ref="HTTP_Request_configuration1" path="/api/number/random_number?size=1" />
<set-variable value="#[output application/java
---
payload.decimal]" doc:name="Set Variable with REST API response " doc:id="5e409a00-0968-4cc7-a24e-da4efb9b2e03" variableName="price_number"/>
<ee:transform doc:name="Transform response to XML" doc:id="3a0f5690-a8ca-4e4d-9a8a-71645cf0940f" >
<ee:message >
<ee:set-payload ><![CDATA[output application/xml
---
{
NumberToDollars #(xmlns: "http://www.dataaccess.com/webservicesserver/"): {
dNum: payload.decimal
}
}]]></ee:set-payload>
</ee:message>
</ee:transform>
<wsc:consume operation="NumberToDollars" doc:name="Call SOAP API with payload for string version of number" doc:id="0a8622d2-98ab-4114-8902-57bcdc2f58ba" config-ref="Web_Service_Consumer_Config" />
<set-variable value="#[output application/java
ns ns0 http://www.dataaccess.com/webservicesserver/
---
payload.body.ns0#NumberToDollarsResponse.ns0#NumberToDollarsResult]" doc:name="Set Variable with SOAP API response" doc:id="25495ffe-b5ef-49de-a9c0-d4db668a58a6" variableName="price_string"/>
<ee:transform doc:name="Transform all responses into one JSON" doc:id="10c1c874-782b-4c4c-84d4-bb14bf3e50a7" >
<ee:message >
<ee:set-payload ><![CDATA[%dw 2.0
output application/json
---
{
isPublished: vars.results.isPublished,
tags: vars.results.tags map ( tag , indexOfTag ) -> tag,
"_id": vars.results."_id",
dishName: vars.results.dishName,
category: vars.results.category,
author: vars.results.author,
ingredients: vars.results.ingredients map ( ingredient , indexOfIngredient ) -> {
"_id": ingredient."_id",
quantity: ingredient.quantity,
unit: ingredient.unit,
description: ingredient.description
},
cookingTime: vars.results.cookingTime,
sourceUrl: vars.results.sourceUrl,
imageUrl: vars.results.imageUrl,
price: vars.price_number[0],
priceText: vars.price_string,
date: vars.results.date,
"__v": vars.results."__v"
}]]></ee:set-payload>
</ee:message>
</ee:transform>
</flow>
<flow name="GET:\courses\name-find_course_by_name" doc:id="11a73a6e-f58f-4c7d-b79a-a310f4e4dc8d" >
<http:listener doc:name="Listener with URI name" doc:id="ee5e9716-60c1-41ae-9c12-dcd1b44cbb96" config-ref="HTTP_Listener_configuration" path="/api/courses/{name}" />
<set-payload value="#[attributes.uriParams.name]" doc:name="Set payload with URI name" doc:id="bac678be-6661-42e7-ac54-db88dac44383" />
<http:request method="GET" doc:name="REST API request for Course with name" doc:id="9010ac49-c81f-4961-93f0-f0539494edb2" config-ref="Local_REST_API_Config" path="/api/courses/{name}" outputMimeType="application/json" >
<http:body ><![CDATA[{}]]></http:body>
<http:uri-params ><![CDATA[#[output application/java
---
{
name: payload
}]]]></http:uri-params>
</http:request>
</flow>
<flow name="GET:\courses-get_all_courses" doc:id="686d41ad-7d8b-40c6-9bb5-3e5ea53efd88" >
<http:listener doc:name="Listener" doc:id="3dc9bfa3-eff1-4cfd-b931-8d47eeeb6695" config-ref="HTTP_Listener_configuration" path="/api/courses/" />
<http:request method="GET" doc:name="REST API request for all courses" doc:id="c7ed66df-bb09-4ecd-9406-151dac1c1f30" config-ref="Local_REST_API_Config" path="/api/courses/" outputMimeType="application/json" >
<http:body ><![CDATA[{}]]></http:body>
</http:request>
</flow>
<flow name="POST:\courses\post-create_course" doc:id="c1fd8373-a7e3-4b7d-bb5b-f3c8214c488b" >
<http:listener doc:name="Listener" doc:id="18b0ed4d-5b6a-4d60-ba96-ed37d1ca10be" config-ref="HTTP_Listener_configuration" path="/api/courses/add/" />
<http:request method="POST" doc:name="REST API request for new course" doc:id="7b565a3e-8eef-4d3e-b3ab-113acca530ae" config-ref="Local_REST_API_Config" path="/api/courses/" outputMimeType="application/json" >
</http:request>
</flow>
<flow name="DELETE:\courses\delete\id-delete_course" doc:id="3c8d98ce-89a7-4437-b9f4-3db38582e596" >
<http:listener doc:name="Listener with URI ID" doc:id="77cfb541-b6e1-4d5d-a6e4-e66381b36af0" config-ref="HTTP_Listener_configuration" path="/api/courses/delete/{id}" />
<set-payload value="#[attributes.uriParams.id]" doc:name="Set payload with URI ID" doc:id="663d6350-4921-40b2-b923-71a24bd46f2c" />
<http:request method="DELETE" doc:name="REST API request for deleting course with ID" doc:id="6db59045-4d70-4901-b696-4f1068d7ef91" config-ref="Local_REST_API_Config" path="/api/courses/delete/{id}" outputMimeType="application/json" >
<http:body ><![CDATA[{}]]></http:body>
<http:uri-params ><![CDATA[#[output application/java
---
{
id: payload
}]]]></http:uri-params>
</http:request>
</flow>
<flow name="PUT:\courses\update\id-put_course" doc:id="42dc3b31-370b-4051-9799-0e957f2b1841" >
<http:listener doc:name="Listener with URI ID" doc:id="9ca7c395-64c4-4c4c-a3b7-3e70323be279" config-ref="HTTP_Listener_configuration" path="/api/courses/update/{id}" />
<set-variable value="#[attributes.uriParams.id]" doc:name="Set Variable with URI ID" doc:id="6677b155-ce84-445b-b608-bcd1f83c06b5" variableName="id" />
<logger level="INFO" doc:name="Logger" doc:id="526b8602-25ae-4c47-949a-dd9bd1fe7c43" message="#[vars.id]"/>
<http:request method="PUT" doc:name="REST API request for updating course with ID" doc:id="95024c7e-99df-4d2c-8ccd-5f2c9b09ca6a" config-ref="Local_REST_API_Config" path="/api/courses/update/{id}" outputMimeType="application/json" >
<http:uri-params ><![CDATA[#[output application/java
---
{
id: vars.id
}]]]></http:uri-params>
</http:request>
</flow>
</mule>
CORS is a restriction on the browser, not on the Mule application. It looks like in the CORS interceptor configuration you didn't add either an authorized origin (looks to be 'http://localhost:3000' based on the error), or configure the resource as public. The first option is more secure because restricts to a limited lists of origins allowed to do the request. Those options are explained in the article you linked.

My SOAP post response is not returning 200 in Python, but it works in Postman

So I ran my post method for SOAP in Postman and received 200, the response headers had text/xml; charset=utf-8 for Content type. My Headers in Postman excluding the default values are
ClientID 700,
SOAPAction urn,
Content-Type text/xml
url = www.xyz.com.svc
The SOAP raw XML used to run in Postman.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.xsd" xmlns:wsu="http://docs.oa.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-1234">
<wsse:Username>E</wsse:Username>
<wsse:Password Type="http://docs.o-username-token-profile-1.0#PasswordText">abcd</wsse:Password>
<wsse:Nonce EncodingType="http://docs.o.security-1.0#Base64Binary">happy</wsse:Nonce>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<ConfirmAppointment xmlns="urn:CompanyNameServices" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!--string occurs:0,1-->
<PatID xsi:nil="false">A1</PatID>
<!--string occurs:0,1-->
<PIDType xsi:nil="false">B</PIDType>
<!--string occurs:0,1-->
<MyCID xsi:nil="false">1</MyCID>
<!--string occurs:0,1-->
<MIDType xsi:nil="false">External</MyIDType>
<!--string occurs:0,1-->
<AppCID xsi:nil="false">1</AppCID>
</ConfirmAppointment>
</soapenv:Body>
</soapenv:Envelope>
I am trying to run this using Python requests.post, here is my code.
soap_body = '''
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.xsd" xmlns:wsu="http://docs.oa.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-1234">
<wsse:Username>E</wsse:Username>
<wsse:Password Type="http://docs.o-username-token-profile-1.0#PasswordText">abcd</wsse:Password>
<wsse:Nonce EncodingType="http://docs.o.security-1.0#Base64Binary">happy</wsse:Nonce>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<ConfirmAppointment xmlns="urn:CompanyNameServices" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!--string occurs:0,1-->
<PatID xsi:nil="false">A1</PatID>
<!--string occurs:0,1-->
<PIDType xsi:nil="false">B</PIDType>
<!--string occurs:0,1-->
<MyCID xsi:nil="false">1</MyCID>
<!--string occurs:0,1-->
<MIDType xsi:nil="false">External</MyIDType>
<!--string occurs:0,1-->
<AppCID xsi:nil="false">1</AppCID>
</ConfirmAppointment>
</soapenv:Body>
</soapenv:Envelope>'''
headers = {
'ClientID': '700',
'SOAPAction': 'urn',
'Content-Type': 'text/xml'
}
response = requests.post(url=url, data=soap_body, headers=headers)
print(response)
My output:
<Response [500]>
If I add <?xml version="1.0" encoding="UTF-8"?> to the beginning of my body, my output:
<Response [400]>
What am I doing wrong here?
Here are 2 sample SOAP requests. See if they work for you.
import requests
url = "https://httpbin.org/post"
headers = {"content-type" : "application/soap+xml"}
body = """
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:req="https://httpbin.org/post">
<soapenv:Header/>
<soapenv:Body/>
</soapenv:Envelope>
""".strip()
response = requests.post(url, data = body, headers = headers)
print(response.content.decode("utf-8") +'\n')
###########################################
url = "https://www.dataaccess.com/webservicesserver/NumberConversion.wso"
headers = {"content-type" : "application/soap+xml"}
body = """
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<NumberToWords xmlns="http://www.dataaccess.com/webservicesserver/">
<ubiNum>500</ubiNum>
</NumberToWords>
</soap:Body>
</soap:Envelope>
""".strip()
response = requests.post(url, data = body, headers = headers)
print(response.content.decode("utf-8") +'\n')

In Python, how to set _soapheaders for Zeep using Dictionaries?

In working with a SOAP api, the wsdl spec describes the api key passed in the header in a complex namespaced structure as well as additional non-namespaced XML that relates to a paging mechanism for accessing bulk results successively:
Specification:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="https://webservice_address_here">
<soapenv:Header>
<ns:apiKey>
<api_key>***</api_key>
</ns:apiKey>
<pager>
<page>1</page>
<per_page>100</per_page>
</pager>
</soapenv:Header>
</soapenv:Envelope>
API Documentation:
Pagination; this method returns paginated results. To specify pages or
results per page, use the pager header:
<soapenv:Header>
<ns:pager>
<page>1</page>
<per_page>100</per_page>
</ns:pager>
</soapenv:Header> Max per page is 100
Pagination information is returned in a pager header:
<soapenv:Header>
<ns:pager>
<page>1</page>
<per_page>100</per_page>
<next_page>2</next_page>
<page_items>100</page_items>
<total_items>2829</total_items>
<total_pages>29</total_pages>
</ns:pager>
</soapenv:Header>
The answer, How to set soap headers in zeep when header has multiple elements, describes a similar scenario, without the namespace "ns" but with "acm." I have not been successful in using this method.
This works, allowing access to the api but without the pager making it mostly useless for any methods that return more than 100 results:
from zeep import Client, xsd
# Generate the header structure
header = xsd.Element(
'{wsdl}AuthenticateRequest',
xsd.ComplexType([xsd.Element("{wsdl}api_key", xsd.String())])
)
# Insert values into header placeholders
self._header_value = header(api_key=self.api_key)
This does not work:
from zeep import Client, xsd
# Generate the header structure
header = xsd.Element(
'Header',
xsd.ComplexType([
xsd.Element(
'{wsdl}AuthenticateRequest',
xsd.ComplexType([
xsd.Element('{wsdl}api_key', xsd.String()),
])
),
xsd.Element(
'pager',
xsd.ComplexType([
xsd.Element('page', xsd.String()),
xsd.Element('per_page', xsd.String()),
])
),
])
)
# ERROR HERE: Insert values into header placeholders
self._header_value = header(api_key=self.api_key, pager={'page':1,'per_page':100})
Error: TypeError: ComplexType() got an unexpected keyword argument 'api_key'. Signature: AuthenticateRequest: {api_key: xsd:string}, pager: {page: xsd:string, per_page: xsd:string}
This also does not work:
header = xsd.Element(
'{wsdl}AuthenticateRequest',
xsd.ComplexType([xsd.Element("{wsdl}api_key", xsd.String())]),
xsd.Element(
'pager',
xsd.ComplexType([
xsd.Element('page', xsd.String()),
xsd.Element('per_page', xsd.String()),
])
)
)
# ERROR HERE: Insert values into header placeholders
self._header_value = header(api_key=self.api_key, pager={"page":1,"per_page":100})
'pager' is not defined in the wsdl but the server expects that it could be there.
TypeError: ComplexType() got an unexpected keyword argument 'pager'.
Signature: api_key: xsd:string
Recent Failed (2022) Attempt Using #markoan answer:
def get_pager(self, page: int = 1, per_page: int = 100):
""" Create header that contains the page and records per page. """
pager_header = xsd.Element(
'pager',
xsd.ComplexType([
xsd.Element(
'page', xsd.Integer()
),
xsd.Element(
'per_page', xsd.Integer()
)
])
)
return pager_header(page=page, per_page=per_page)
def call(self, endpoint: str, *args, **kwargs):
"""Allows calling of any client service defined in the WSDL."""
# get the endpoint
endpoint = getattr(self.client.service, endpoint)
# get SOAP authentication header which includes the API key embedded from CFG
headers = [self.get_header()]
# add the pager complex element to headers if required in kwargs
if page := kwargs.get("page"):
per_page = kwargs.get("per_page") or 100
headers.append(self.get_pager(page, per_page))
# call the endpoint with provided unnamed and named parameters if any
result = endpoint(*args, **kwargs, _soapheaders=headers)
# serialize and return result
return self.serialize(result)
What is the simplest way using Zeep to set the namespace api_key and non-namespaced complex pager element?
I find it's easier to work with Zeep if we have a valid and complete WSDL.
A simple API service WSDL that expects an element without namespace would import a schema with no namespace like this:
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://tempuri.org/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="http://tempuri.org/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" >
<wsdl:types>
<s:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/">
<s:import schemaLocation="namespaceLessElement.xsd"/>
<s:element name="Api" minOccurs="0" maxOccurs="1">
</s:element>
<s:element name="ApiResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1" name="ApiResult" type="s:int"/>
</s:sequence>
</s:complexType>
</s:element>
<s:element name="apiKey">
<s:complexType>
<s:sequence>
<s:element name="api_key" type="s:string"></s:element>
</s:sequence>
</s:complexType>
</s:element>
</s:schema>
</wsdl:types>
<wsdl:message name="ApiSoapIn">
<wsdl:part name="parameters" element="tns:Api"/>
</wsdl:message>
<wsdl:message name="ApiSoapOut">
<wsdl:part name="parameters" element="tns:ApiResponse"/>
</wsdl:message>
<wsdl:message name="ApiKeyHeader">
<wsdl:part name="ApiKeyHeaderParam" element="tns:apiKey"/>
</wsdl:message>
<wsdl:message name="PagerHeader">
<wsdl:part name="PagerHeaderParam" ref="pager"/>
</wsdl:message>
<wsdl:portType name="ApiSoap">
<wsdl:operation name="Api">
<wsdl:documentation>This is a test WebService. Returns a number</wsdl:documentation>
<wsdl:input message="tns:ApiSoapIn"/>
<wsdl:output message="tns:ApiSoapOut"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="ApiSoap" type="tns:ApiSoap">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="Api">
<soap:operation soapAction="http://tempuri.org/Api" style="document"/>
<wsdl:input>
<soap:header message="tns:ApiKeyHeader" part="ApiKeyHeaderParam" use="literal"/>
<soap:header message="tns:PagerHeader" part="PagerHeaderParam" use="literal"/>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="ApiTest">
<wsdl:port name="ApiSoap" binding="tns:ApiSoap">
<soap:address location="http://superpc:8082/"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
With namespaceLessElement.xsd:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<s:schema xmlns:s="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<s:element name="pager">
<s:complexType>
<s:sequence>
<s:element name="page" type="s:int"></s:element>
<s:element name="per_page" type="s:int"></s:element>
</s:sequence>
</s:complexType>
</s:element>
</s:schema>
Note how the operation definition that expects header values points to correct messages:
<wsdl:operation name="Api">
<soap:operation soapAction="http://tempuri.org/Api" style="document"/>
<wsdl:input>
<soap:header message="tns:ApiKeyHeader" part="ApiKeyHeaderParam" use="literal"/>
<soap:header message="tns:PagerHeader" part="PagerHeaderParam" use="literal"/>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
and these in turn reference correct elements:
<wsdl:message name="ApiKeyHeader">
<wsdl:part name="ApiKeyHeaderParam" element="tns:apiKey"/>
</wsdl:message>
<wsdl:message name="PagerHeader">
<wsdl:part name="PagerHeaderParam" ref="pager"/>
</wsdl:message>
You should check in the WSDL of your web service that the operation describes both headers and that it includes a schema definition for both elements. In the example WSDL the service namespace is targetNamespace="http://tempuri.org/" but this should point to your web service URL.
So assuming your WSDL is valid and complete, we need to define the Client pointing to the WSDL and then set the header values using the _soapheaders parameter, similar to the method I used here but building the content reference. Zeep can take care of the different namespaces but I found issues with empty ones:
transport = Transport(cache=SqliteCache())
self.Test = Client(wsdl='http://my-endpoint.com/production.svc?wsdl', transport=transport)
# Header objects
apiKey_header = xsd.Element(
'{http://tempuri.org/}apiKey',
xsd.ComplexType([
xsd.Element(
'api_key', xsd.String()
)
])
)
pager_header = xsd.Element(
'pager',
xsd.ComplexType([
xsd.Element(
'page', xsd.Integer()
),
xsd.Element(
'per_page', xsd.Integer()
)
])
)
apiKey_header_value = apiKey_header( api_key=key)
pager_header_value = pager_header( page=page, per_page=perpage)
# Request
response = self.Test.service.Api( _soapheaders=[apiKey_header_value, pager_header_value] )
logger.debug("Result={1}".format(response))
# Prints: Result=2 (or whatever value the test API sends)
EDIT: Example of generated XML request:
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Header>
<ns0:apiKey xmlns:ns0="http://tempuri.org/">
<api_key>1230011</api_key>
</ns0:apiKey>
<pager>
<page>2</page>
<per_page>10</per_page>
</pager>
</soap-env:Header>
<soap-env:Body>
<ns0:Api xmlns:ns0="http://tempuri.org/"/>
</soap-env:Body>
</soap-env:Envelope>
Make sure that the header that has a namespace is defined with the correct URL.
If you still have problems it may mean your WSDL does not define all elements or that it's not linking correctly to external XSDs. In those cases one option is to save a local copy os the WSDL and linked XSDs, then edit the files to fix references and then point Zeep to that local file instead.

Hazelcast + Spring(xml config) + hz map store error

Using hazelcast 3.8.2 (hazelcast-all jar) + IMap+ mapstore + Spring 4.3.8 (xml config). In Spring xml config, 'hz:map-store' throws an error saying:
17:49:40.519 ERROR [main] org.springframework.test.context.TestContextManager – Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener#1868ed54] to prepare test instance [com.twc.ctg.ecp.service.dataaccess.maps.EntitlementMapTest#1b9ea3e3] org.xml.sax.SAXParseException: cvc-complex-type.2.1: Element 'hz:map' must have no character or element information item [children], because the type's content type is empty.
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:203) ~[?:1.8.0_101]
What am I doing wrong?
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:hz="http://www.hazelcast.com/schema/spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.hazelcast.com/schema/spring
http://www.hazelcast.com/schema/spring/hazelcast-spring.xsd">
<hz:hazelcast id="hzInstance1">
<hz:config>
...
</hz:config>
</hz:hazelcast>
<hz:client id="hzInstance1Client">
...
</hz:client>
<hz:map id="entitlementCache" instance-ref="hzInstance1" name="entitlement">
<hz:map-store enabled="true" implementation="linearEntitlementMapStore"
write-delay-seconds="30000"/>
</hz:map>
<bean id="linearEntitlementMapStore" class="com.twc.ctg.ecp.service.dataaccess.maps.LinearEntitlementMapStore" />
</beans>
You need to configure MapStore in <hz:config> section.
Correct config should look like this
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:hz="http://www.hazelcast.com/schema/spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.hazelcast.com/schema/spring
http://www.hazelcast.com/schema/spring/hazelcast-spring.xsd">
<hz:hazelcast id="hzInstance1">
<hz:config>
<hz:map name="entitlement">
<hz:map-store enabled="true" implementation="linearEntitlementMapStore"
write-delay-seconds="30000"/>
<!-- ... -->
</hz:map>
</hz:config>
</hz:hazelcast>
<hz:client id="hzInstance1Client">
<!--... -->
</hz:client>
<bean id="linearEntitlementMapStore" class="com.twc.ctg.ecp.service.dataaccess.maps.LinearEntitlementMapStore"/>

Setting Flag for an Email in ActiveSync

Trying to set status Flag for an email using ActiveSync. Below is my request. I receive status 6. What's wrong with my request?
Request
<Sync xmlns="AirSync:" xmlns:email="Email:" xmlns:tasks="Tasks:" >
<Collections>
<Collection>
<SyncKey>648263900</SyncKey>
<CollectionId>11</CollectionId>
<GetChanges>0</GetChanges>
<Commands>
<Change>
<ServerId>11:2</ServerId>
<ApplicationData>
<email:Flag>
<email:Status>1</email:Status>
<email:FlagType>Follow Up</email:FlagType>
<tasks:StartDate>113-04-23T05:30:00.000Z</tasks:StartDate>
<tasks:UTCStartDate>113-04-23T05:30:00.000Z</tasks:UTCStartDate>
<tasks:DueDate>113-04-26T05:30:00.000Z</tasks:DueDate>
<tasks:UTCDueDate>113-04-26T05:30:00.000Z</tasks:UTCDueDate>
</email:Flag>
</ApplicationData>
</Change>
</Commands>
</Collection>
</Collections>
Response I receive
<?xml version="1.0"?>
<!DOCTYPE ActiveSync PUBLIC "-//MICROSOFT//DTD ActiveSync//EN" "http://www.microsoft.com/">
<Sync xmlns="AirSync:">
<Collections>
<Collection>
<SyncKey>648263900</SyncKey>
<CollectionId>11</CollectionId>
<Status>1</Status>
<Responses>
<Change>
<ServerId>11:2</ServerId>
<Status>6</Status>
</Change>
</Responses>
</Collection>
</Collections>
</Sync>
Change email:FlagType from Follow Up to for Follow Up.
And add </Sync> in the end.
Try:
<?xml version="1.0" encoding="utf-8"?>
<Sync xmlns="AirSync:" xmlns:email="Email:" xmlns:tasks="Tasks:" >
<Collections>
<Collection>
<SyncKey>648263900</SyncKey>
<CollectionId>11</CollectionId>
<GetChanges>0</GetChanges>
<Commands>
<Change>
<ServerId>11:2</ServerId>
<ApplicationData>
<email:Flag>
<email:Status>1</email:Status>
<email:FlagType>for Follow Up</email:FlagType>
<tasks:StartDate>113-04-23T05:30:00.000Z</tasks:StartDate>
<tasks:UTCStartDate>113-04-23T05:30:00.000Z</tasks:UTCStartDate>
<tasks:DueDate>113-04-26T05:30:00.000Z</tasks:DueDate>
<tasks:UTCDueDate>113-04-26T05:30:00.000Z</tasks:UTCDueDate>
</email:Flag>
</ApplicationData>
</Change>
</Commands>
</Collection>
</Collections>
</Sync>
See more: MS-ASEMAIL

Resources