Skip to content

Service Wrapper

Jeremy Barlow edited this page Mar 27, 2018 · 8 revisions

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.

The code for the sample is broken into two main sections.

Service Wrapper

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 RequestCallback that will be invoked when "current weather" query Request messages are received.

The actual query (which can be weather by zip code, location, city, etc.) is extracted from the Request message's 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 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 send_response() method of the DxlClient instance.

Service Invoker

The following sample shows how the service shown above can be invoked over DXL.

# 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 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 sync_request() method of the DxlClient instance.

The results of the query are extracted from the Response that was received and displayed.

Output

The output should appear similar to the following (query for the current weather for zip code 97140):

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
    }
}