Service Wrapper Sample¶
Prior to running this sample make sure you have completed the samples configuration step (Samples Configuration).
This sample demonstrates how simple it is to wrap an existing service and expose it on the DXL fabric.
In this particular case, the OpenWeatherMap "current weather" data is exposed as a DXL service. This service wrapper delegates to the OpenWeatherMap REST API.
OpenWeather API key¶
Before running this sample you must obtain an "API key" from OpenWeatherMap:
Once you receive the API key, you must replace it in the openweather_common.py
file as shown below:
# The API key for invoking the weather service API_KEY = "01234567890123456789012345678901"
Service Wrapper¶
The first step is to start the "service wrapper". This script will remain running and receive
dxlclient.message.Request
messages from clients that are querying weather information.
To start the "service wrapper", execute the sample\servicewrapper\openweather_service_wrapper.py
script as follows:
c:\dxlclient-python-sdk-5.6.0.4>python sample\servicewrapper\openweather_service_wrapper.py
The output should appear similar to the following:
2016-10-11 12:58:43,065 dxlclient.client - INFO - Waiting for broker list... 2016-10-11 12:58:43,065 dxlclient.client - INFO - Checking brokers... 2016-10-11 12:58:43,066 dxlclient.client - INFO - Trying to connect... 2016-10-11 12:58:43,066 dxlclient.client - INFO - Trying to connect to broker {Unique id: {284bca2e-79e1-11e6-159d-005056812aa3}, Host name: 10.84.200.124, Port: 8883}... 2016-10-11 12:58:43,315 dxlclient.client - INFO - Connected to broker {284bca2e-79e1-11e6-159d-005056812aa3} 2016-10-11 12:58:43,315 dxlclient.client - INFO - Launching event loop... 2016-10-11 12:58:43,316 dxlclient.client - INFO - Connected with result code 0 2016-10-11 12:58:43,316 dxlclient.client - INFO - Subscribing to /mcafee/client/{5b18f1cc-adac-4f20-88d9-c23d9c531ada} 2016-10-11 12:58:43,329 dxlclient.client - INFO - Message received for topic /mcafee/client/{5b18f1cc-adac-4f20-88d9-c23d9c531ada} 2016-10-11 12:58:43,335 __main__ - INFO - Weather service is running...
The majority of code for the service wrapper is shown below:
# The OpenWeatherMap "Current Weather" URL (see http://openweathermap.org/current) CURRENT_WEATHER_URL = "http://api.openweathermap.org/data/2.5/weather?{0}&APPID={1}" # The "current weather" topic SERVICE_CURRENT_WEATHER_TOPIC = "/openweathermap/service/openweathermap/current" # Create the client with DxlClient(config) as client: # Connect to the fabric client.connect() # # Register the service # # Create "Current Weather" incoming request callback class CurrentWeatherCallback(RequestCallback): def on_request(self, request): try: # Extract information from request query = request.payload.decode(encoding="UTF-8") logger.info("Service received request payload: " + query) # Send HTTP request to OpenWeatherMap req = URLRequest( CURRENT_WEATHER_URL.format(query, API_KEY), None, {'Content-Type': 'text/json'}) f = urlopen(req) weather_response = f.read() f.close() # Create the response message response = Response(request) # Populate the response payload response.payload = weather_response # Send the response client.send_response(response) except Exception as ex: print str(ex) # Send error response client.send_response(ErrorResponse( request, error_message=str(ex).encode(encoding="UTF-8"))) # Create service registration object info = ServiceRegistrationInfo(client, SERVICE_NAME) # Add a topic for the service to respond to info.add_topic(SERVICE_CURRENT_WEATHER_TOPIC, CurrentWeatherCallback()) # Register the service with the fabric (wait up to 10 seconds for registration to complete) client.register_service_sync(info, 10) logger.info("Weather service is running...") # Wait forever while True: time.sleep(60)
The service wrapper registers a dxlclient.callbacks.RequestCallback
that will be invoked when
"current weather" query dxlclient.message.Request
messages are received.
The actual query (which can be weather by zip code, location, city, etc.) is extracted from the dxlclient.message.Request
message's dxlclient.message.Message.payload
attribute.
The OpenWeatherMap REST API is invoked via HTTP with the query that was received in the DXL request message's payload.
A DXL dxlclient.message.Response
message is created with a payload containing the result of invoking the
OpenWeatherMap REST API and sent back to the invoking DXL client via
the dxlclient.client.DxlClient.send_response()
method of the dxlclient.client.DxlClient
instance.
Service Invoker¶
The next step is to execute the "service invoker". This script must be executed in a separate command prompt (or shell), leaving the "service wrapper" running.
To start the "service invoker", execute the sample\servicewrapper\openweather_service_invoker.py
script as follows:
c:\dxlclient-python-sdk-5.6.0.4>python sample\servicewrapper\openweather_service_invoker.py
The output should appear similar to the following (query for the current weather for zip code 97140):
2016-10-11 13:20:50,565 dxlclient.client - INFO - Waiting for broker list... 2016-10-11 13:20:50,566 dxlclient.client - INFO - Checking brokers... 2016-10-11 13:20:50,568 dxlclient.client - INFO - Trying to connect... 2016-10-11 13:20:50,569 dxlclient.client - INFO - Trying to connect to broker {Unique id: {284bca2e-79e1-11e6-159d-005056812aa3}, Host name: 10.84.200.124, Port: 8883}... 2016-10-11 13:20:50,808 dxlclient.client - INFO - Connected to broker {284bca2e-79e1-11e6-159d-005056812aa3} 2016-10-11 13:20:50,808 dxlclient.client - INFO - Launching event loop... 2016-10-11 13:20:50,809 dxlclient.client - INFO - Connected with result code 0 2016-10-11 13:20:50,809 dxlclient.client - INFO - Subscribing to /mcafee/client/{383105c5-17f7-4b40-bb90-7ed17bf3f315} 2016-10-11 13:20:51,336 dxlclient.client - INFO - Message received for topic /mcafee/client/{383105c5-17f7-4b40-bb90-7ed17bf3f315} Client received response payload: { "base": "stations", "clouds": { "all": 0 }, "cod": 200, "coord": { "lat": 45.36, "lon": -122.84 }, "dt": 1476216689, "id": 5751632, "main": { "grnd_level": 1010.59, "humidity": 66, "pressure": 1010.59, "sea_level": 1034.15, "temp": 287.158, "temp_max": 287.158, "temp_min": 287.158 }, "name": "Sherwood", "sys": { "country": "US", "message": 0.171, "sunrise": 1476195849, "sunset": 1476235829 }, "weather": [ { "description": "clear sky", "icon": "01d", "id": 800, "main": "Clear" } ], "wind": { "deg": 83.0013, "speed": 3.1 } }
The majority of code for the service invoker is shown below:
# The "current weather" topic SERVICE_CURRENT_WEATHER_TOPIC = "/openweathermap/service/openweathermap/current" # Create the "Current Weather" request req = Request(SERVICE_CURRENT_WEATHER_TOPIC) # Populate the request payload # Examples include: # By ZIP code: zip=97140,us # By geographic coordinates: lat=35&lon=139 # By city name: q=London,uk req.payload = "zip=97140,us".encode() # Send the request and wait for a response (synchronous) res = client.sync_request(req) # Extract information from the response (if an error did not occur) if res.message_type != Message.MESSAGE_TYPE_ERROR: response_dict = json.loads(res.payload.decode(encoding="UTF-8")) print("Client received response payload: \n" + \ json.dumps(response_dict, sort_keys=True, indent=4, separators=(',', ': '))) else: logger.error("Error: %s (%s)", res.error_message, res.error_code)
A DXL dxlclient.message.Request
message is created and its payload is set to the query (zip code,
location, city, etc.) to perform against the OpenWeatherMap REST API.
A synchronous request is sent to the DXL service via the dxlclient.client.DxlClient.sync_request()
method of
the dxlclient.client.DxlClient
instance.
The results of the query are extracted from the dxlclient.message.Response
that was received and displayed.