-
Notifications
You must be signed in to change notification settings - Fork 0
Tutorial Part 4: Create Client Wrapper
The previous portion of this tutorial ("Create Application") walked through the steps necessary to create an application that exposes a Geolocation DXL service through the use of OpenDXL Bootstrap.
Additionally, the basic sample included with the generated application was updated to invoke the Geolocation service. The majority of code in the updated sample is shown below:
request_topic = "/mycompany/service/geolocation/host_lookup"
req = Request(request_topic)
# Create dictionary with host to lookup and response format
req_dict = {"format": "json", "host": "mcafee.com"}
# Convert dictionary to JSON and set as DXL request payload
MessageUtils.dict_to_json_payload(req, req_dict)
res = client.sync_request(req, timeout=30)
if res.message_type is not Message.MESSAGE_TYPE_ERROR:
print("Response for geolocation_service_hostlookup: '{0}'".format(MessageUtils.decode_payload(res)))
else:
print("Error invoking service with topic '{0}': {1} ({2})".format(
request_topic, res.error_message, res.error_code))While not overly complex, there are several aspects of this code worth noting:
- ~8 lines are required to invoke the service (with error checking)
- The invoker must have knowledge of the DXL topic associated with the service (
/mycompany/service/geolocation/host_lookup) - The invoker must have knowledge of the payload format for the DXL request message associated with the service (JSON format, the fields, values associated with fields, etc.)
- Field values are not validated prior to sending to the server (valid output formats, etc.)
- When invoking the service a reasonable timeout must be specified (based on the service being invoked)
- Any errors resulting from the service invocation must be handled
- The invoker must have knowledge of the payload format for the DXL response message
All of the items listed above can be eliminated through the use of a client wrapper. The purpose of a client wrapper is to allow users to access the features of a DXL fabric (services and events) without having to focus on lower-level details such as message topics, message formats, etc.
The remainder of this portion of the tutorial will focus on creating a client wrapper for the Geolocation service.
NOTE: The
MessageUtilsclass which is included in the OpenDXL Bootstrap library is used throughout the code presented in this portion of the tutorial.MessageUtilsprovides several convenience methods for setting and retrieving the payload on DXL messages (Python dictionary to JSON payload, etc.).For complete details of the
MessageUtilsclass please refer to the Message Utilities Class Documentation.
The first step is to open a command prompt/shell in the workspace directory that was created in the previous portion of this tutorial (See, "Create Workspace Directory")
At this point the contents of the opendxl-geolocation directory should appear as follows:
opendxl-geolocation\
app\
application-template.config
In this step the client wrapper will be generated by using the OpenDXL Bootstrap client template (client-template).
The Bootstrap application requires a configuration file that defines the properties of the client that is going to be generated. The properties for the client generated in this tutorial are shown below.
[Client]
name=geolocationclient
fullName=Geolocation Client
clientClassName=GeolocationClient
copyright=Copyright 2018
includeExampleMethod=yes
For complete details about the client-template configuration file and its related properties refer to this page.
In this particular case, a client class named GeoLocationClient will be generated. Additionally, the includeExampleMethod property is set to yes which will result in an example method being generated. This method will be modified later to include Geolocation-specific functionality.
Create a file in the opendxl-geolocation directory named client-template.config. Paste the contents of the configuration listed above into this file and save it.
At this point the contents of the opendxl-geolocation directory should appear as follows:
opendxl-geolocation\
app\
application-template.config
client-template.config
At this point the OpenDXL Bootstrap application will be executed resulting in the Geolocation client being created.
To generate the client, execute the following command from the opendxl-geolocation directory.
python -m dxlbootstrap client-template client-template.config client
The command above creates a project using the client-template with the properties in the configuration file created previously (client-template.config). The output of the generation is placed in the client output directory. For complete details about the Bootstrap application command line and its related arguments refer to this page.
If the generation is successful, the message Generation succeeded will be displayed. The contents of the opendxl-geolocation directory should now appear as follows:
opendxl-geolocation\
app\
client\
application-template.config
client-template.config
In this step the Geolocation functionality will be integrated into the generated client.
At this point change to the generated client directory:
cd client
The contents of the client directory should appear as follows:
opendxl-geolocation\
client\
dist.py
doc\
geolocationclient\
LICENSE
MANIFEST.in
README
README.md
sample\
setup.py
The geolocationclient directory contains the Python code for the generated client.
In this step the Geolocation client class (GeolocationClient) will be modified to invoke the Geolocation DXL service (created in the previous section of this tutorial).
NOTE: The generated
GeolocationClientclass derives from theClientclass that is included in the OpenDXL Bootstrap library. Some of the methods from this base class will be utilized in the following steps.For complete details of the base
Clientclass please refer to the Base Client Class Documentation.
Open the client.py file within the geolocationclient directory for editing. This file contains the GeolocationClient class.
Add the list of valid output formats to the top of the class definition as shown below:
class GeolocationClient(Client):
"""
The "Geolocation Client" client wrapper class.
"""
# The valid output formats
OUT_FORMATS = ["json", "csv", "xml", "dict"]
...This allows users of the client to determine the list of output formats that are supported by its methods.
The dict output format has been added to the list of formats supported by the Geolocation web service (json, csv, and xml). The dict output format will result in a Python dictionary being returned from the invoked method.
Replace the entire my_example_method implementation:
def my_example_method(self):
...
return MessageUtils.json_payload_to_dict(response) With the following method (host_lookup):
def host_lookup(self, host, out_format="dict"):
"""
Performs Geolocation lookup for specified host
:param host: The host to lookup
:param out_format: The output format
:return: The result of the lookup
"""
# Validate specified output format
if out_format not in GeolocationClient.OUT_FORMATS:
raise Exception("Unknown format: {0}".format(out_format))
# Create the DXL request message
request = Request("/mycompany/service/geolocation/host_lookup")
# Set the payload on the request message (Python dictionary to JSON payload)
MessageUtils.dict_to_json_payload(
request,
{
"host": host,
"format": ("json" if out_format is "dict" else out_format)
})
# Perform a synchronous DXL request
response = self._dxl_sync_request(request)
if out_format is "dict":
return MessageUtils.json_payload_to_dict(response)
else:
return MessageUtils.decode_payload(response)Details regarding the host_lookup method are listed below:
- The method has two parameters:
-
host: The host or IP address for which to lookup Geolocation information. -
out_format: The output format to return from the method. TheOUT_FORMATSlist contains the possible values for this parameter. The default output format isdictwhich results in a Python dictionary being returned.
-
- The specified
out_formatis validated against the list of supportedOUT_FORMATS. If an invalid output format is specified anExceptionis raised. - A DXL request message is created with the topic associated with the Geolocation DXL service (
/mycompany/service/geolocation/host_lookup). - A Python dictionary (
dict) is created and with thehostandout_formatspecified. This dictionary is passed to theMessageUtilsutility class which converts the Python dictionary to JSON and sets it on the payload of the DXL request message. If theout_formatspecified isdictthe output format sent to the Geolocation DXL service isjson(the JSON output will be converted to a Python dictionary within the client prior to returning). - The Geolocation DXL service is invoked by calling the
_dxl_sync_requestmethod which is defined in the baseClientclass (see Base Client Class Documentation). The_dxl_sync_requestmethod contains the details for checking whether an error has occurred and raising an appropriateException. It also utilizes theresponse_timeoutthat is associated with the client instance when making the request. - The payload of the received DXL response message is decoded and returned to the invoker of the
host_lookupmethod. If the output format isdictthe payload is converted from JSON to a Python dictionary (dict) and returned.
The important point to note about this method is that it hides the lower-level DXL details such as message topics, message formats, etc. from the user of the method in addition to providing client-side validation of parameters.
In this step the Geolocation functionality will be integrated into the basic sample that is included with the generated client.
Open the basic_sample.py file within the sample\basic directory for editing.
Change the following code in the sample from:
# Invoke the example method
resp_dict = client.my_example_method()To the following:
host = "mcafee.com"
resp_dict = client.host_lookup(host)The changes above achieve the following:
- The
host_lookupmethod is invoked with the hostmcafee.com. Since anout_formatis not specified, the output format will default to a Python dictionary (dict).
Next, after the statement that prints out the response from the initial host_lookup invocation:
# Print out the response (convert dictionary to JSON for pretty printing)
print("Response:\n{0}".format(
MessageUtils.dict_to_json(resp_dict, pretty_print=True)))Add the following lines:
print("\nCSV:\n{0}".format(client.host_lookup(host, out_format="csv")))
print("\nXML:\n{0}".format(client.host_lookup(host, out_format="xml")))
print("\nJSON:\n{0}".format(client.host_lookup(host, out_format="json")))The changes above achieve the following:
- The
host_lookupmethod is invoked with the hostmcafee.comfor each possible output format (csv, xml, and json). The results for each of these lookup invocations is displayed.
In this step, the Geolocation client basic sample will be executed.
Ensure the application that exposes the Geolocation service is running (see "Run Application", above).
A new command prompt/shell will need to be opened for executing the sample.
Prior to running the sample, the dxlclient.config file located in the sample directory of the client must be modified to include the information necessary to connect to the DXL fabric.
The steps to populate this configuration file are the same as those documented in the OpenDXL Python SDK, see the OpenDXL Python SDK Samples Configuration page for more information.
To run the basic sample, execute the following command from within the client directory (opendxl-geolocation\client):
python sample\basic\basic_sample.py
The output should appear similar to the following:
Response:
{
"city": "Santa Clara",
"country_code": "US",
"country_name": "United States",
"ip": "161.69.29.243",
"latitude": 37.3961,
"longitude": -121.9617,
"metro_code": 807,
"region_code": "CA",
"region_name": "California",
"time_zone": "America/Los_Angeles",
"zip_code": "95054"
}
CSV:
161.69.29.243,US,United States,CA,California,Santa Clara,95054,America/Los_Angeles,37.3961,-121.9617,807
XML:
<Response>
<IP>161.69.29.243</IP>
<CountryCode>US</CountryCode>
<CountryName>United States</CountryName>
<RegionCode>CA</RegionCode>
<RegionName>California</RegionName>
<City>Santa Clara</City>
<ZipCode>95054</ZipCode>
<TimeZone>America/Los_Angeles</TimeZone>
<Latitude>37.3961</Latitude>
<Longitude>-121.9617</Longitude>
<MetroCode>807</MetroCode>
</Response>
JSON:
{"ip":"161.69.29.243","country_code":"US","country_name":"United States",
"region_code":"CA","region_name":"California","city":"Santa Clara",
"zip_code":"95054","time_zone":"America/Los_Angeles","latitude":37.3961,"longitude":-121.9617,"metro_code":807}The output above contains the response for each of the four invocations of the Geolocation DXL service. The first invocation is the JSON representation of the dictionary (dict) that was returned from the host_lookup method.
In summary, the client wrapper has reduced the approximately eight lines of code required to make a Geolocation DXL service invocation to one. Additionally, the users of this client are not exposed to the lower-level details of Geolocation service-specific DXL topics and message formats.
OpenDXL Bootstrap Application
Tutorial (Service Creation)
- Part 1 - Overview
- Part 2 - Installation
- Part 3 - Create Application
- Part 4 - Create Client Wrapper
- Part 5 - Package Distributions
Usage
Templates
Supporting Classes
Documentation