RSS

Consuming Google Geo REST service using the OSB

25 Oct

In this article I will explain how you can make use of the Google Geo Service API using the OSB. Check out this page to see what we can do with this API. Basically it makes it possible to enter address details and Google comes up with the geographical details including longitude and latitude if Google can find it. The result can either be returned as JSON or as XML. In this example we are going build a webservice in the OSB which will call Google and transform the returned XML into a nice response.

So lets start with making a simple WSDL which is going to expose the Google API. Mine looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions name="GeoService" targetNamespace="http://www.rubix.nl/geo/service" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://www.rubix.nl/geo/service" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:geo="http://www.rubix.nl/geo/service/schema">
	<wsdl:types>
		<xsd:schema targetNamespace="http://www.rubix.nl/imports" elementFormDefault="qualified">
			<xsd:import schemaLocation="../Schemas/GeoService.xsd" namespace="http://www.rubix.nl/geo/service/schema" />
		</xsd:schema>
	</wsdl:types>
	<wsdl:message name="GetGeocodeRequest">
		<wsdl:part name="parameters" element="geo:GetGeocodeRequest">
		</wsdl:part>
	</wsdl:message>
	<wsdl:message name="GetGeocodeResponse">
		<wsdl:part name="parameters" element="geo:GetGeocodeResponse">
		</wsdl:part>
	</wsdl:message>
	<wsdl:portType name="GeoService">
		<wsdl:operation name="GetGeocode">
			<wsdl:input message="tns:GetGeocodeRequest">
			</wsdl:input>
			<wsdl:output message="tns:GetGeocodeResponse">
			</wsdl:output>
		</wsdl:operation>
	</wsdl:portType>
	<wsdl:binding name="GeoService" type="tns:GeoService">
		<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
		<wsdl:operation name="GetGeocode">
			<soap:operation soapAction="http://www.rubix.nl/geo/service"/>
			<wsdl:input>
				<soap:body use="literal"/>
			</wsdl:input>
			<wsdl:output>
				<soap:body use="literal"/>
			</wsdl:output>
		</wsdl:operation>
	</wsdl:binding>
	<wsdl:service name="GeoService">
		<wsdl:port name="GeoServicePort" binding="tns:GeoService">
			<soap:address location="http://www.rubix.nl/geo/service"/>
		</wsdl:port>
	</wsdl:service>
</wsdl:definitions>

With the data defined in a seperate file GeoService.xsd.

<?xml version="1.0" encoding="UTF-8"?>
<!-- edited with XMLSpy v2011 rel. 2 sp1 (http://www.altova.com) by Hugo Hendriks (Rubix) -->
<xsd:schema xmlns:tns="http://www.rubix.nl/geo/service/schema" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.rubix.nl/geo/service/schema" elementFormDefault="qualified">
	<xsd:element name="GetGeocodeRequest">
		<xsd:complexType>
			<xsd:sequence>
				<xsd:element name="Street" minOccurs="1" maxOccurs="1" type="xsd:string"/>
				<xsd:element name="Number" minOccurs="1" maxOccurs="1" type="xsd:integer"/>
				<xsd:element name="City" minOccurs="1" maxOccurs="1" type="xsd:string"/>
			</xsd:sequence>
		</xsd:complexType>
	</xsd:element>
	<xsd:element name="GetGeocodeResponse">
		<xsd:complexType>
			<xsd:choice>
				<xsd:element ref="tns:Messages"/>
				<xsd:sequence>
					<xsd:element name="Longitude" type="xsd:string"/>
					<xsd:element name="Latitude" type="xsd:string"/>
				</xsd:sequence>
			</xsd:choice>
		</xsd:complexType>
	</xsd:element>
	<xsd:element name="Messages">
		<xsd:complexType>
			<xsd:sequence>
				<xsd:element name="Message">
					<xsd:complexType>
						<xsd:sequence>
							<xsd:element name="Code">
								<xsd:annotation>
									<xsd:documentation>The code</xsd:documentation>
								</xsd:annotation>
							</xsd:element>
							<xsd:element name="Description">
								<xsd:annotation>
									<xsd:documentation>The description</xsd:documentation>
								</xsd:annotation>
							</xsd:element>
						</xsd:sequence>
					</xsd:complexType>
				</xsd:element>
			</xsd:sequence>
		</xsd:complexType>
	</xsd:element>
</xsd:schema>

First we are going to create a business service which will call Google. Create it as a messaging service:

Set the Request Message Type to none and the Response Message Type to XML.

And finally set the Endpoint URI to http://maps.googleapis.com/maps/api/geocode/xml

Next we are going to create a proxy service which uses the created WSDL.

After this we do the usuall stuff we want to do in our flow like a bit of logging, validation and errorhandling. As a last step insert a Route and a Routing and select the BusinessService we created.

But now for the good part. We need to make a HTTP GET request to Google with a certain set of http-parameters. You can test this in your own browser by using the following example URI: http://maps.googleapis.com/maps/api/geocode/xml?address=koningsplein+1+amsterdam&sensor=false&language=nl. Try and input your own address in there to see if Google can find it for you. In this case the http-parameters are: address=koningsplein+1+amsterdam. The sensor=false means we are not using a measuring device and the language parameter speaks for itself. Oke…..how do we make a HTTP GET request to Google using these parameters. You can accomplish this by adding an Insert action to you Route with the following settings:

This insert chances the HTTP request from a PUT to a GET. The next step is to set the http-parameters. This is done like this:

You can see we insert another piece of xml into the outbound variable. We are using an XQuery to create this piece of xml. Mine looks like this:

(:: pragma bea:global-element-parameter parameter="$GetGeocodeRequest" element="geo:GetGeocodeRequest" location="../Schemas/GeoService.xsd" ::)
(:: pragma bea:global-element-return element="http:query-string" location="../Schemas/HttpTransport.xsd" ::)

declare namespace http = "http://www.bea.com/wli/sb/transports/http";
declare namespace geo = "http://www.rubix.nl/geo/service/schema";
declare namespace xf  = "http://www.rubix.nl/transformation/SoapToHttpGet/";

declare function xf:SoapToHttpGet($GetGeocodeRequest as element(geo:GetGeocodeRequest))
    as element(http:query-string) {
        <http:query-string>{ concat("address=",$GetGeocodeRequest/geo:Street , "+" ,$GetGeocodeRequest/geo:Number, "+",
                           					 $GetGeocodeRequest/geo:City, "&sensor=false&language=nl") }
        </http:query-string>
};

declare variable $GetGeocodeRequest as element(geo:GetGeocodeRequest) external;

xf:SoapToHttpGet($GetGeocodeRequest)

You can see we create a query-string element using the request we receive from the user. The HttpTransport.xsd is needed for this which also has some references to ther xsd’s (EnvValues.xsd, MessageContext.xsd and TransportCommon.xsd) so make sure to put these in your Schemas directory. So in the end, my project looks like this:

When we make the call to Google, we receive XML back which we want to transform into a response previously defined. First we check if we receive an answer at all or multiple answers.

Next we transform the response into our pre-defined response using a replace of the body.

<sch:GetGeocodeResponse>
	<sch:Longitude>{$body/GeocodeResponse/result/geometry/location/lng/text()}</sch:Longitude>
	<sch:Latitude>{$body/GeocodeResponse/result/geometry/location/lat/text()}</sch:Latitude>
</sch:GetGeocodeResponse>

Now lets deploy and test the service.Lets use the previously used parameters for the call in the browser which where Koningsplein 1 in Amsterdam. You test in the webconsole should look something like this:

As you can see we receive the latitude and logitude for the address. As we look deeper into the Route we can see how the $outbound is transformed:

So now you know how you can consume a REST service using the OSB.

btw: You can make a maximum of 2500 calls per day using this service. If you want to make more calls, you have to get a business account.

 
Leave a comment

Posted by on October 25, 2012 in OSB

 

Tags: , ,

Leave a comment