I am trying to make a liftweb rest server that accepts POST requests for a small internal testing and call it through Spring framework's RestTemplate#postForObject("http://localhost:9090/api/validate/", request, String.class);. I went through Simply liftweb's Chapter 11 REST.
My RestController.scala is
13 object RestController extends RestHelper {
14 val data = LiftRules.loadResourceAsXml("/ValidationReply.xml");
21 serve {
22 case "api" :: "validate" :: _ XmlPost xml -> _ => <system>
26 <id>TEST</id>
27 <name>PILOT</name>
28 <version>1</version>
29 <ip_address>192.168.2.18</ip_address>
30 <connector>
31 <id>UPD</id>
32 </connector>
33 </system>
124 case JsonGet("api" :: "validate" :: _, _) => JString("Validated")
125 }
126 }
When I request the server with postUrl = "http://localhost:9090/api/validate", I get the not found error response
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<body>The Requested URL /api/validate was not found on this server</body>
</html>
When restUrl = "http://localhost:9090/api/validate", I get second api called with reply "Validated". How do I make the POST request in liftweb?
What you have is looking for a POST that is XML. As per the source,
it gets passed through A trait that defines the TestPost extractor.
Is the request a POST, has JSON or XML data in the post body and
something that expects JSON or XML in the response.
I'm not sure if you are just making the request or if you are actually sending data. But, assuming you are just making a post request, I would try posting XML in the body. Otherwise, you could try rewriting the rule using Post instead of XmlPost like:
case Post("api" :: "validate" :: Nil, req) =>
<system>
<id>TEST</id>
<name>PILOT</name>
<version>1</version>
<ip_address>192.168.2.18</ip_address>
<connector>
<id>UPD</id>
</connector>
</system>
Related
I must be missing out something in the format of my XML file for adding an invoice to Quickbooks Desktop Enterprise US version, my qbxml request is as follows;
<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="13.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<InvoiceAddRq>
<InvoiceAdd>
<CustomerRef>
<FullName>XXXXXXXXX</FullName>
</CustomerRef>
<ClassRef>
<FullName>XXXXXXX</FullName>
</ClassRef>
<ARAccountRef>
<FullName>XXXXXXXXXX</FullName>
</ARAccountRef>
<TemplateRef>
<FullName>Standard invoice</FullName>
</TemplateRef>
<TxnDate/>
<RefNumber>83434</RefNumber>
<BillAddress>
<Addr1>4xxxxxx</Addr1>
<City>xxxxxxxx</City>
<State>XX</State>
<PostalCode>0000</PostalCode>
</BillAddress>
<IsPending>1</IsPending>
<IsFinanceCharge>0</IsFinanceCharge>
<PONumber>12345</PONumber>
<TermsRef>
<FullName>Net 30</FullName>
</TermsRef>
<DueDate/>
<SalesRepRef/>
<FOB/>
<ShipDate/>
<ShipMethodRef/>
<ItemSalesTaxRef/>
<Memo/>
<CustomerMsgRef/>
<IsToBePrinted>0</IsToBePrinted>
<IsToBeEmailed>0</IsToBeEmailed>
<IsTaxIncluded>0</IsTaxIncluded>
<CustomerSalesTaxCodeRef/>
<Other/>
<ExchangeRate>1</ExchangeRate>
<SetCredit>
<CreditTxnID>1</CreditTxnID>
<AppliedAmount>0</AppliedAmount>
<Override>1</Override>
</SetCredit>
<InvoiceLineAdd>
<itemRef>
<FullName>S-check UT</FullName>
</itemRef>
<Desc>Interpreter</Desc>
<Quantity>1</Quantity>
<UnitOfMeasure/>
<Rate>10</Rate>
<RatePercent>100</RatePercent>
<PriceLevelRef/>
<ClassRef/>
<Amount>10</Amount>
<OptionForPriceRuleConflict>0</OptionForPriceRuleConflict>
<InventorySiteRef/>
<InventorySiteLocationRef/>
<SerialNumber/>
<LotNumber/>
<ServiceDate/>
<SalesTaxCodeRef/>
<OverrideItemAccountRef/>
<Other1/>
<Other2/>
<LinkToTxn>
<TxnID>0</TxnID>
<TxnLineID>0</TxnLineID>
</LinkToTxn>
<DataExt>
<OwnerID>3caa4f6f-fcb3-4767-99e6-0ba5dfd34e8f</OwnerID>
<DataExtName>Sample</DataExtName>
<DataExtValue>Sample</DataExtValue>
</DataExt>
</InvoiceLineAdd>
</InvoiceAdd>
</InvoiceAddRq>
</QBXMLMsgsRq>
</QBXML>
When i check this xml request using the qbxml validator i'm getting the following error message even though i have supplied all the required fields as outlined in the OSR tool;
Line: 53
LinePos: 20
Src Text: <itemRef>
Reason: Element content is invalid according to the DTD/Schema.
Expecting: ItemRef, Desc, Quantity, UnitOfMeasure, Rate, RatePercent, PriceLevelRef, ClassRef,
Amount, TaxAmount, OptionForPriceRuleCon....
I'm not sure about what's wrong with my xml file, when i run the quickbooks webconnector, the error message i get is;
Message: QuickBooks found an error when parsing the provided XML text stream.
I understand this is coming up because of the wrong format of my qbxml request which could be incorrect. Kindly assist
I have filtered your QBXML and removed all error producing QBXML tags
<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="13.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<InvoiceAddRq>
<InvoiceAdd>
<CustomerRef>
<FullName>XXXXXXXXX</FullName>
</CustomerRef>
<ClassRef>
<FullName>XXXXXXX</FullName>
</ClassRef>
<ARAccountRef>
<FullName>XXXXXXXXXX</FullName>
</ARAccountRef>
<TemplateRef>
<FullName>Standard invoice</FullName>
</TemplateRef>
<TxnDate/>
<RefNumber>83434</RefNumber>
<BillAddress>
<Addr1>4xxxxxx</Addr1>
<City>xxxxxxxx</City>
<State>XX</State>
<PostalCode>0000</PostalCode>
</BillAddress>
<IsPending>1</IsPending>
<IsFinanceCharge>0</IsFinanceCharge>
<PONumber>12345</PONumber>
<TermsRef>
<FullName>Net 30</FullName>
</TermsRef>
<DueDate/>
<SalesRepRef/>
<FOB/>
<ShipDate/>
<ShipMethodRef/>
<ItemSalesTaxRef/>
<Memo/>
<CustomerMsgRef/>
<IsToBePrinted>0</IsToBePrinted>
<IsToBeEmailed>0</IsToBeEmailed>
<IsTaxIncluded>0</IsTaxIncluded>
<CustomerSalesTaxCodeRef/>
<Other/>
<ExchangeRate>1</ExchangeRate>
<SetCredit>
<CreditTxnID>1</CreditTxnID>
<AppliedAmount>0</AppliedAmount>
<Override>1</Override>
</SetCredit>
<InvoiceLineAdd>
<Desc>Interpreter</Desc>
<Quantity>1</Quantity>
<UnitOfMeasure/>
<Rate>10</Rate>
<ClassRef/>
<Amount>10</Amount>
<InventorySiteRef/>
<InventorySiteLocationRef/>
<SerialNumber/>
<ServiceDate/>
<SalesTaxCodeRef/>
<OverrideItemAccountRef/>
<Other1/>
<Other2/>
<LinkToTxn>
<TxnID>0</TxnID>
<TxnLineID>0</TxnLineID>
</LinkToTxn>
</InvoiceLineAdd>
</InvoiceAdd>
</InvoiceAddRq>
</QBXMLMsgsRq>
</QBXML>
I am trying to send a SOAP request using Spring Integration like
<int:chain input-channel="wsOutChannel" output-channel="stdoutChannel">
<int-ws:header-enricher>
<int-ws:soap-action value="..."/>
</int-ws:header-enricher>
<int-ws:outbound-gateway
uri="..."/>
</int:chain>
but you can only add the SOAP body, and Spring Integration adds the envelope, header, and body tags like
<SOAP-ENV:Envelope>
<SOAP-ENV:Header>
<SOAP-ENV:Body>
...
</SOAP-ENV:Body>
<SOAP-ENV:Header>
</SOAP-ENV:Envelope>
I need to customize the envelope and header tags with specific attributes, for example:
<soapenv:Envelope attribute1="value1" attribute2="value2">
and child elements, for example:
<soapenv:Header>
<child>...<child>
<soapenv:Header>
Is this possible with Spring Integration Web Services, or should I not use int-ws:outbound-gateway and take a different approach?
You can add a ClientInterceptor (via the interceptor attribute) which allows you to modify the request before it's sent out.
EDIT
#Artem's suggestion is simpler but the interceptor gives you access to the response too; but either way, the code is similar.
For the interceptor:
public class MyInterceptor extends ClientInterceptorAdapter {
#Override
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
SoapMessage request = (SoapMessage) messageContext.getRequest();
SoapEnvelope envelope = request.getEnvelope();
envelope.addAttribute(new QName("foo"), "bar");
SoapHeader header = envelope.getHeader();
header.addHeaderElement(new QName("http://fiz/buz", "baz"));
return super.handleRequest(messageContext);
}
}
For the callback version:
#Override
public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException {
SoapEnvelope envelope = ((SoapMessage) message).getEnvelope();
envelope.addAttribute(new QName("foo"), "bar");
SoapHeader header = envelope.getHeader();
header.addHeaderElement(new QName("http://fiz/buz", "baz"));
}
I thing you can inject WebServiceMessageCallback:
<xsd:attribute name="request-callback" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Reference to a Spring Web Services WebServiceMessageCallback. This enables changing
the Web Service request message after the payload has been written to it but prior
to invocation of the actual Web Service.
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.ws.client.core.WebServiceMessageCallback"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
and cast the message to the SoapMessage and use its getEnvelope() to customize a desired way.
I am trying to write configure a gateway, which should take a complete SOAP Message and then delegate it to another SOAP Provider (incl. all SOAP headers of the first request).
What I have done so far:
1) web.xml
MessageDispatcherServlet with Mapping:
<servlet-mapping>
<servlet-name>spring-ws</servlet-name>
<url-pattern>/appservices/*</url-pattern>
</servlet-mapping>
2) Configuration with an Endpoint-Mapping
<bean class="org.springframework.ws.server.endpoint.mapping.UriEndpointMapping">
<property name="defaultEndpoint" ref="ws-in-gw"/>
</bean>
3) Configuration of Spring Integration inbound-gateway and outbound-gateway
<int-ws:inbound-gateway id="ws-in-gw"
request-channel="in"
reply-channel="out"
mapped-request-headers="*" />
<int:channel id="in" />
<int:channel id="out" />
<int-ws:outbound-gateway
id="ws-out-gw-status"
request-channel="in-status"
reply-channel="out-status"
uri="http://${delegationServer}/${delegation.contextroot}/soap/AnotherService"
interceptor="soapEnricher"
</int-ws:outbound-gateway>
<bean id="soapEnricher" class="foo.bar.SoapHeaderEnricher" />
public class SoapHeaderEnricher implements ClientInterceptor {
#Override
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
try {
SoapMessage soapMessage = (SoapMessage) messageContext.getRequest();
SoapHeader sh = soapMessage.getSoapHeader();
// can use sh.addHeaderElement(new QName(...)) now, but where are the original Headers???
} catch () {
}
}
My first Problem was, that the original SOAP Headers had been cut of, so I introduced the ' mapped-request-headers="*" ' attribute at the inbound gateway.
When I now configure a wire-tap, I see the Headers (myToken:MySecretToken) are received:
DEBUG 10:46:53 - [Payload DOMSource content=javax.xml.transform.dom.DOMSource#24a6ce98][Headers={errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel#43456ff4, myToken:MySecretToken=org.springframework.ws.soap.saaj.SaajSoapHeaderElement#3b91ead, ...}]
This is the SOAP Message for my test:
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:stat="http://status.service.promakler.provinzial.com/">
<soapenv:Header>
<myToken:MySecretToken xmlns=""
xmlns:myToken="http://foo.bar">12345</myToken:MySecretToken>
</soapenv:Header>
<soapenv:Body>
<stat:getStatus/>
</soapenv:Body>
</soapenv:Envelope>
So the Headers are now in my Message, but in the ClientInterceptor, there is no way to get the Headers (just the payload)?! I can add new Headers, but how can I get the original Header?
Can anybody give me a hint (or perhaps there is even a quiet simpler solution??)
Regards
Timo
Try to introduce a custom extension of DefaultSoapHeaderMapper and override populateUserDefinedHeader to extract those SaajSoapHeaderElement from the MessageHeaders and populate them to the SoapHeader. And finally inject your solution to the header-mapper of your <int-ws:outbound-gateway>.
I can't get the SOAP server working in Zend Framework 2 module. I am not completely sure, but I believe that the problem is the WSDL file. I try to create the WSDL file via Autodiscover, which is provided by the Zend Framework. Here is the error.log:
[Fri Apr 19 20:39:29 2013] [error] [client 172.23.31.109] PHP Warning: SoapServer::SoapServer(): I/O warning : failed to load external entity "http-LINK/services?wsdl" in /PATH/public_html/vendor/zendframework/zendframework/library/Zend/Soap/Server.php on line 749
[Fri Apr 19 20:39:29 2013] [error] [client 172.23.31.109] PHP Fatal error: SOAP-ERROR: Parsing WSDL: Couldn't load from 'http-LINK/services?wsdl' : failed to load external entity "http-LINK/services?wsdl"\n in /PATH/public_html/vendor/zendframework/zendframework/library/Zend/Soap/Server.php on line 749
I added an own module for this services test, this is the structure, module is called "Services":
-Services
--config
---module.config.php
--src
---Services
----API
-----1.0
------servicesAPI.php
---Controller
----ServicesController.php
--view
---services
----serivces
-Module.php
-autoload_classmap.php
This is my file "servicesAPI.php"
class servicesAPI {
/**
* This method takes a value and gives back the md5 hash of the value
*
* #param String $value
* #return String
*/
public function md5Value($value) {
return md5($value);
}
}
And this is ServicesController.php:
namespace Services\Controller;
ini_set("soap.wsdl_cache_enabled", 0);
use Zend\Mvc\Controller\AbstractActionController;
use Zend\Soap\AutoDiscover;
use Zend\Soap\Server;
require_once __DIR__ . '/../API/1.0/servicesAPI.php';
class ServicesController extends AbstractActionController {
private $_options;
private $_URI = "http-LINK/services";
private $_WSDL_URI = "http-LINK/services?wsdl";
public function indexAction() {
if (isset($_GET['wsdl'])) {
$this->handleWSDL();
} else {
$this->handleSOAP();
}
}
private function handleWSDL() {
$autodiscover = new AutoDiscover();
$autodiscover->setClass('servicesAPI')
->setUri($this->_URI);
$autodiscover->handle();
}
private function handleSOAP() {
$soap = new Server($this->_WSDL_URI);
$soap->setClass('servicesAPI');
$soap->handle();
}
}
So when I deploy this and open http-LINK/services in the browser, it gives me the following:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>WSDL</faultcode>
<faultstring>
SOAP-ERROR: Parsing WSDL: Couldn't load from 'http-LINK/services?wsdl' : failed to load external entity "http-LINK/services?wsdl"
</faultstring>
<detail/>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
On this call also the PHP error output is written!
If I try to open the services?wsdl in browser, it shows me this (chrome and safari):
This page contains the following errors:
error on line 3 at column 1: Extra content at the end of the document
Below is a rendering of the page up to the first error.
This method takes a value and gives back the md5 hash of the value
But if I inspect the element, it looks completely ok:
<?xml version="1.0" encoding="utf-8"?>
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http-LINK/services" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" name="servicesAPI" targetNamespace="http-LINK/services"><types><xsd:schema targetNamespace="http-LINK/services"/></types><portType name="servicesAPIPort"><operation name="md5Value"><documentation>This method takes a value and gives back the md5 hash of the value</documentation><input message="tns:md5ValueIn"/><output message="tns:md5ValueOut"/></operation></portType><binding name="servicesAPIBinding" type="tns:servicesAPIPort"><soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/><operation name="md5Value"><soap:operation soapAction="http-LINK/services#md5Value"/><input><soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http-LINK/services"/></input><output><soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http-LINK/services"/></output></operation></binding><service name="servicesAPIService"><port name="servicesAPIPort" binding="tns:servicesAPIBinding"><soap:address location="http-LINK/services"/></port></service><message name="md5ValueIn"><part name="value" type="xsd:string"/></message><message name="md5ValueOut"><part name="return" type="xsd:string"/></message></definitions>
I can validate this xml with any xml validator, it seems to be valid.
I read all the posts concerning this on stackoverflow, searched google, but none of the solutions helped me. Here a short list of what else I tried:
According to this: https://bugs.php.net/bug.php?id=48216 I tried to save the wsdl xml to a file and open it from this file when starting the soap server, fail
I tried to run the autodiscover and soapserver statements with try/catch to catch any exceptions, nothing appears
I tried with echo-ing through toXML() and other outputs, fail
Used XMLReader::open and isValid to make sure, that the xml is valid (it is)
Some more information:
PHP Version 5.3.23
Ubuntu server 11.04
php-soap module is loaded
Zend Framework version 2.1.4
Any help or hints are appreciated. Thanks in advance.
Try instantiate the Soap Server class this way:
...
private function handleSOAP() {
$soap = new Server(
null, array(,
'wsdl' => http-LINK/services?wsdl,
)
);
$soap->setClass('servicesAPI');
$soap->handle();
}
....
Also you should add this line to the end of your indexAction()
return $this->getResponse();
.. it disables the layout.
I have this error
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<soap:Fault>
<faultcode>soap:Client</faultcode>
<faultstring>Message part {http://soap.ws.server.wst.fit.cvut.cz/}createOrders was not recognized. (Does it exist in service WSDL?)</faultstring>
</soap:Fault>
</soap:Body>
</soap:Envelope>
which is completely fine. But the problem is that CXF is returning Internal Server Error (HTTP 500). I would expect it to return 400 Bad Request because a wrong request is causing this. How can I change that?
DETAILS
The wrong request which produces the error above - there should be <soap:createOrder/> instead of <soap:createOrders/>.
POST http://localhost:8080/wst-server-1.0.0/services/soap/order
POST data:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="http://soap.ws.server.wst.fit.cvut.cz/">
<soapenv:Header/>
<soapenv:Body>
<soap:createOrders/>
</soapenv:Body>
</soapenv:Envelope>
[no cookies]
Request Headers:
Content-Length: 238
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
I know maybe this is too late for the answer but another way to handle HTTP status code is using CXF interceptors.
you can add an interceptor in your server CXF configure
public class ServiceConfigurer implements CxfConfigurer {
#Override
public void configureServer(Server server) {
server.getEndpoint().getOutFaultInterceptors().add(new ChangingStatusCodeInterceptor();
}
}
and in your interceptor, you can change this
public class SaveInfluxDataInterceptor extends WSS4JOutInterceptor {
#Override
public void handleMessage(SoapMessage soapMessage) {
((Fault)exchange.get(Exception.class)).setStatusCode(202); // this is because of soap12OutFaultInterceptor look to this fault
// or you can use this
// exchange.getOutFaultMessage().put(Message.RESPONSE_CODE, 202);
}
}
I used Camel with CXF. maybe this solution should change in yours.