Expose RAML contract instead WADL in CXF - rest

I am new in REST world, an in most of CXF examples that I saw there is an configuration to expose WADL in REST services when published.
Something like
Available RESTful services:
Endpoint address: http://localhost:8080/ouat-servicesImpl/api
WADL : http://localhost:8080/ouat-servicesImpl/api?_wadl
Then, when clicked
<application>
<grammars/>
<resources base="http://localhost:8080/ouat-servicesImpl/api">
<resource path="/topics">
<method name="POST">
<request>
<representation mediaType="application/json"/>
</request>
<response>
<representation mediaType="application/json"/>
</response>
</method>
</resource>
</resources>
</application>
I was learning RAML and its benefits in contract creation. Is there any way to expose RAML contract in this CXF "home" service page? Or am I mixing the concepts/ purpose of RAML and WADL? Actually I think both are ways to expose services contract, however in my opinion RAML is more complete

Assuming you package your CXF service as a WAR, here is how you can achieve your goal, based on a real project I'm working on:
Drop RAML and JSON files below the webroot folder: https://github.com/openanalytics/RPooli/tree/master/webapp/src/main/webapp/raml
Template baseUri so it can be injected at runtime: https://github.com/openanalytics/RPooli/blob/master/webapp/src/main/webapp/raml/api_v1.raml#L21
Declare .raml as if it's a JSP so injection can work: https://github.com/openanalytics/RPooli/blob/master/webapp/src/main/webapp/WEB-INF/web.xml#L70
Add the RAML mime-type: https://github.com/openanalytics/RPooli/blob/master/webapp/src/main/webapp/WEB-INF/web.xml#L76-L79
Add a filter to compute the dynamic part of the baseUri: https://github.com/openanalytics/RPooli/blob/master/webapp/src/main/java/eu/openanalytics/rpooli/web/BaseUriInjectionFilter.java
Wire it in web.xml: https://github.com/openanalytics/RPooli/blob/master/webapp/src/main/java/eu/openanalytics/rpooli/web/BaseUriInjectionFilter.java
Bonus point for:
Embedding the RAML API console: https://github.com/openanalytics/RPooli/tree/master/webapp/src/main/webapp/raml/ui
And redirecting to it from the web-app home page: https://github.com/openanalytics/RPooli/blob/master/webapp/src/main/webapp/index.html

Related

SOAP-body auto generated namespace

I have to do some support on a single-function SOAP webservice, and I am failing to understand a specific aspect of the WSDL file & the resulting SOAP request as generated by SoapUI.
The WSDL for this service specifies a targetNamespace in the definitions part (targetNamespace="tetra-river-common-types/trafficinfo").
If I load the WSDL file into SoapUI, it reads everything perfectly fine; no issues at all with any of the definitions. The types for this service are defined in a single external schema file with the following definition in the WSDL file:
<wsdl:types>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:import namespace="tetra-river-common-types" schemaLocation="tetra-river-interface.xsd" />
</xsd:schema>
</wsdl:types>
However, after loading the WSDL file into SoapUI, and opening the auto generated request, it shows the following:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tet="tetra-river-common-types">
<soapenv:Header/>
<soapenv:Body>
<tet:TrafficInformation>
<tet:Item1>?</tet:Item1>
<!-- several other items with the tet: namespace prefixed -->
</tet:TrafficInformation>
</soapenv:Body>
</soapenv:Envelope>
My question is: how is the tet: namespace determined by SoapUI? I see no mention of it in either the WSDL file or the XSD file. I assume it takes the first 3 characters from the targetNamespace, but I am unsure.
The problem I am facing is that the webservice itself expects this exact message, but with tetra: as the namespace.
If you see the wsdl, there is an import of namespace as below:
namespace="tetra-river-common-types"
And if you see the request in the soapUI, in the very first line has the same namespace with prefix tet i.e.,
xmlns:tet="tetra-river-common-types"
Hence, the respective request elements are prefixed with tet.
It does not really matter what the prefix is as along the referring to the same namespace.
For more information on namespaces, see here

Regarding the yang model for netconf xml file

Team
I have the below xml file:
<?xml version="1.0" encoding="utf-8"?>
<rpc message-id="${TIMESTAMP}" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<get-config>
<source>
<running></running>
</source>
<filter>
<interface-configurations xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-ifmgr-cfg"/>
</filter>
</get-config>
</rpc>
Q1: Will this netconf xml file have a yang model?
Q2: How can i access the underlying yang model(file) for this xml file?
Q1: Will this netconf xml file have a yang model?
You can easily determine if a device is using YANG to model its content from its <hello> message. Compliant devices advertise the YANG modules they support. The advertised capabilities will differ for YANG 1 and YANG 1.1.
For YANG 1 (RFC6020), this is what the specification says (5.6.4.1):
Servers indicate the names of supported modules via the <hello>
message. Module namespaces are encoded as the base URI in the
capability string, and the module name is encoded as the "module"
parameter to the base URI.
A server MUST advertise all revisions of all modules it implements.
For example, this <hello> message advertises one module "syslog".
<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<capability>
http://example.com/syslog?module=syslog&revision=2008-04-01
</capability>
</hello>
For YANG 1.1 (RFC7950), in 5.6.4:
A NETCONF server MUST announce the modules it implements (see
Section 5.6.5) by implementing the YANG module "ietf-yang-library"
defined in [RFC7895] and listing all implemented modules in the
"/modules-state/module" list.
The server also MUST advertise the following capability in the
<hello> message (line breaks and whitespaces are used for formatting
reasons only):
urn:ietf:params:netconf:capability:yang-library:1.0?
revision=<date>&module-set-id=<id>
The parameter "revision" has the same value as the revision date of
the "ietf-yang-library" module implemented by the server. This
parameter MUST be present.
The parameter "module-set-id" has the same value as the leaf
"/modules-state/module-set-id" from "ietf-yang-library". This
parameter MUST be present.
With this mechanism, a client can cache the supported modules for a
server and only update the cache if the "module-set-id" value in the
<hello> message changes.
can't seem to find a way to stop the above blockquote, hence this
Q2: How can i access the underlying yang model(file) for this xml file?
Device manufacturers usually provide a download page on their website, where you obtain their YANG files. Note that not all devices support YANG. NETCONF does not specify what content is modeled with; could be a bunch of XSD schemas, YANG, RelaxNG, etc., though YANG was designed with this purpose in mind (initially).
There is also an optional standard operation defined, called <get-schema>, which is part of ietf-netconf-monitoring YANG module. You first discover available schema, then obtain them. Since it is optional, not all devices support it.
<?xml version="1.0" encoding="utf-8"?>
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="2">
<get>
<filter type="subtree">
<ncm:netconf-state xmlns:ncm="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">
<ncm:schemas/>
</ncm:netconf-state>
</filter>
</get>
</rpc>
<?xml version="1.0" encoding="utf-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="2">
<data>
<netconf-state xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">
<schemas>
<schema>
<identifier>ietf-inet-types</identifier>
<version>2013-07-15</version>
<format>yang</format>
<namespace>urn:ietf:params:xml:ns:yang:ietf-inet-types</namespace>
<location>NETCONF</location>
</schema>
<!-- ... -->
</schemas>
</netconf-state>
</data>
</rpc-reply>
<?xml version="1.0" encoding="utf-8"?>
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="8">
<get-schema xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">
<identifier>ietf-interfaces</identifier>
<version>2014-05-08</version>
<format>yang</format>
</get-schema>
</rpc>
<?xml version="1.0" encoding="utf-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="8">
<data xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">module ietf-interfaces {
namespace "urn:ietf:params:xml:ns:yang:ietf-interfaces";
prefix if;
// ...
}
</data>
</rpc-reply>

RESTLET on Camel with Jetty

As far as I understand, Camel by default uses the default RESTLET engine. How can I tell Camel to use Jetty instead?
I know there are ways to bundle your application and deploy it in Tomcat or Jetty. If I do that, however, the biggest question becomes how to integrate with RESTLET.
I did some further digging. I took one of the tomcat examples that come with the camel. Then I tried to make it RESTLET capable. It almost works. The problem now is that the parameters are not being passed to the route. I would expect that when calling this server: http://x.x.x.x:8080/rs/user/?name=Paul, I would get: Hello Paul how are you?
However, I simply get: Hello how are you?
My camel configuration is:
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="restlet:/user/?restletMethods=GET,POST" />
<transform>
<simple>Hello ${header.name} how are you?</simple>
</transform>
</route>
</camelContext>
<bean id="RestletComponent" class="org.restlet.Component" />
<bean id="RestletComponentService" class="org.apache.camel.component.restlet.RestletComponent">
<constructor-arg index="0">
<ref bean="RestletComponent" />
</constructor-arg>
</bean>
And my web.xml is:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:camel-config.xml</param-value>
</context-param>
<servlet>
<servlet-name>RestletServlet</servlet-name>
<servlet-class>org.restlet.ext.spring.SpringServerServlet</servlet-class>
<init-param>
<param-name>org.restlet.component</param-name>
<param-value>RestletComponent</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>RestletServlet</servlet-name>
<url-pattern>/rs/*</url-pattern>
</servlet-mapping>
I am getting a little bit closer with my investigation. It appears that ${in.body} will indeed pass the body of the request to the route. I am still trying to find out what is going on with the header. I even tried using the producer template to call the headers, still it does work. So, this somehow suggests that the way to access the header in RESTLET is different than in the pure servlet? Here is my producer template:
Map<String, Object> headers = new HashMap<String, Object>();
headers.put("name","Paul");
context.createProducerTemplate().requestBodyAndHeaders(
"restlet:http://localhost:8080/camel-example-servlet-tomcat/rs/user/?restletMethod=post", "Halleluia",headers);
Have a look at the org.apache.camel.component.restlet.DefaultRestletBinding class. By default form data is only bound when content type is "application/x-www-form-urlencoded". Also, only URI template values will be bound to headers.
To get at arbitrary query parameters you can do something like:
Request request = exchange.getIn().getHeader(RestletConstants.RESTLET_REQUEST, Request.class);
String value = request.getResourceRef().getQueryAsForm().getFirstValue("foo");
Also, the raw query string will be available in the CamelHttpQuery header.
You can supply your own class which implements RestletBinding (or extend DefaultRestletBinding) by specifying the bean ID of a RestletBinding object in the Camel Registry using the 'restletBinding' endpoint query option. If you are using Spring register a bean like this:
<bean id="myRestletBinding" class="com.example.MyRestletBinding"/>
OK. It appears I had to access the URL parameter with in.header.name instead of header.name. I have no explanation as to why header.name would work in the normal servlet. Also, I managed to get this working only with POST. With GET, the parameters are still not passed to the RESTLET engine or I do not know how to retrieve them. On the contrary, GET works fine when using pure servlet. Solution is good for me and I thus mark this as answered.
I would suggest you to use camel CXFRS component. Have a service class where all REST annotations are declared. You can have the username as path parameter or query parameter.
Syntax would be something like this :
from("cxfrs://http://localhost:9992/service?resourceClasses=com.xyz.web.resources.RESTresource")
REST resource would be your resource class. This will run a REST web service over a jetty web server.

Create a REST proxy for SOAP service in wso2 esb

We have a SOAP service that I want to proxy in WSO2 ESB. This is for POC that I am working on. I came across various documents and some explanation on forums but nothing concrete yet. I looked at API option but couldn't get anything to work. Whats the best way to do this? Can the transformation occur in esb itself or is the api the only option? Please advise.
You can better choose RESTAPI option.
Here is the documentation for that
What do you mean by couldn't get this working? This is not a big configuration, you need to define your proxy service such that you send the message (REST message) to the back end as a SOAP message. Here is a sample configuration.
<proxy name="StockQuoteProxy" transports="http https" startOnLoad="true">
<target>
<endpoint>
<address uri="http://localhost:9000/services/SimpleStockQuoteService"
format="soap11"/>
</endpoint>
<outSequence>
<send/>
</outSequence>
</target>
</proxy>
You can call this proxy in REST manner and it will automatically send the message to the backend SOAP service.
you can do it with the sample axis2 client as below.
ant stockquote -Daddurl=http://localhost:8280/services/StockQuoteProxy -Drest=true

Hand-crafted WSDL from XSD fails in CXF: the namespace on the "QueryResponse" element, is not a valid SOAP version

I have a web service that follows some of the semantics of a SOAP service, but they don't provide a WSDL for said service. Instead, they provide an XSD, by which I'm reverse-engineering a WSDL out of. Things seemed to be going well, even so far as to be able to
create a WSDL
Import the XSD as part of the WSDL using the xsd:import tag
Create Java wrappers with CXF
Call the service.
Now, what I get when I call the service is an exception:
INFO: Creating Service {http://service.something.net/xml}QueryService from WSDL: file:/C:/mydocs/Work/project/my-service.wsdl
Aug 09, 2011 1:22:34 PM org.apache.cxf.phase.PhaseInterceptorChain doDefaultLogging
WARNING: Interceptor for {http://service.something.net/xml}QueryService#{http://servicesomething..../xml}QueryRequest has thrown exception, unwinding now
org.apache.cxf.binding.soap.SoapFault: "http://service.something.net/xml", the namespace on the "QueryResponse" element, is not a valid SOAP version.
The WSDL can be found in this gist, and the XSD is something I got from the vendor.
What does the error mean? What might I have done wrong in my .wsdl file generation?
Edit 1
I have manually tested the service from the vendor service, and the response seems okay to me:
<?xml version="1.0" encoding="UTF-8"?>
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Body>
<QueryResponse xmlns="http://service.something.net/xml">
....
</QueryResponse>
</Body>
</Envelope>
Unless I'm missing something, there should not be any reason why CXF even wants the QueryResponse to be a SOAP element, since it's namespace isn't SOAP but http://service.something.net/xml.
Where you are importing your XSD:
<wsdl:types>
<xsd:schema targetNamespace="http://service.something.net/xml">
<xsd:include schemaLocation="My-XSD.xsd" />
</xsd:schema>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:import namespace="http://service.something.net/xml"
schemaLocation="My-XSD.xsd">
</xsd:import>
</xsd:schema>
</wsdl:types>
try this instead:
<wsdl:types>
<xs:schema targetNamespace="http://service.something.net/xml"
elementFormDefault="qualified">
<xs:import schemaLocation="My-XSD.xsd"/>
</xs:schema>
</wsdl:types>
Basically you shouldn't need the include, just the import. Also you want to specify fully qualified element form.
Hope this works.