Use the API Client Library for Python to send requests

This quickstart shows how to solve the VRP example by sending a gRPC request to the Cloud Fleet Routing service using the Cloud Client Libraries for Python. This example uses the Distance Matrix API.

Before you begin

To send requests to the API using the Python Client, you need to download the Cloud Fleet Routing Python Client from Cloud Storage. To do so, enter the following command:

gsutil cp gs://api-client-staging/cloudoptimization-python-v1-20211110.tar.gz SAVE_TO_LOCATION

Please change SAVE_TO_LOCATION to the location where you'd like to put your SDK in.

Install pip

Install pip, the Python package installer:

sudo apt-get install python-pip
python3 -m pip install --user --upgrade pip
pip install --upgrade pip

Make sure your pip version is at least pip-21:

pip --version

Install the Cloud Fleet Routing API Client Library

After you have downloaded the API client tarball, install the API client with the following commands:

python3 -m venv fleet-env
source fleet-env/bin/activate
pip install cloudoptimization-python-v1-20211110.tar.gz

Synchronous API requests

The following script sends an API request to the Cloud Fleet Routing service to synchronously generate routes.

Python script
import json
import sys

from google.cloud.optimization_v1.services.fleet_routing.client import FleetRoutingClient
from google.cloud.optimization_v1.types.fleet_routing import OptimizeToursRequest

def main(request_file_name):
  # Use the default credentials for the environment.
  fleet_routing_client = FleetRoutingClient()

  # Get the data.
  with open(request_file_name, 'r') as f:
    # The request must include the `parent` field with the value set to
    # 'projects/{YOUR_GCP_PROJECT_ID}'.
    fleet_routing_request = OptimizeToursRequest.from_json(f.read())
    # Send the request and print the response.
    # Cloud Fleet Routing will return a response by the earliest of the `timeout` field
    # in the request payload and the gRPC timeout specified below.
    fleet_routing_response = fleet_routing_client.optimize_tours(
        fleet_routing_request, timeout=100)
    print(fleet_routing_response)
    # If you want to format the response to JSON, you can do the following:
    # from google.protobuf.json_format import MessageToJson
    # json_obj = MessageToJson(fleet_routing_response._pb)

if __name__ == '__main__':
  if len(sys.argv) > 1:
    main(sys.argv[1])
  else:
    print('You must include the request file as an argument.')
request.json
{
  "parent": "projects/${YOUR_GCP_PROJECT_ID}",
  "model": {
    "shipments": [
      {
        "deliveries": [
          {
            "arrivalLocation": {
              "latitude": 48.880942,
              "longitude": 2.323866
            },
            "duration": "250s",
            "timeWindows": [
              {
                "endTime": "1970-01-01T01:06:40Z",
                "startTime": "1970-01-01T00:50:00Z"
              }
            ]
          }
        ],
        "loadDemands": {
          "weight": {
            "amount": "10"
          }
        },
        "pickups": [
          {
            "arrivalLocation": {
              "latitude": 48.874507,
              "longitude": 2.30361
            },
            "duration": "150s",
            "timeWindows": [
              {
                "endTime": "1970-01-01T00:33:20Z",
                "startTime": "1970-01-01T00:16:40Z"
              }
            ]
          }
        ]
      },
      {
        "deliveries": [
          {
            "arrivalLocation": {
              "latitude": 48.88094,
              "longitude": 2.323844
            },
            "duration": "251s",
            "timeWindows": [
              {
                "endTime": "1970-01-01T01:06:41Z",
                "startTime": "1970-01-01T00:50:01Z"
              }
            ]
          }
        ],
        "loadDemands": {
          "weight": {
            "amount": "20"
          }
        },
        "pickups": [
          {
            "arrivalLocation": {
              "latitude": 48.880943,
              "longitude": 2.323867
            },
            "duration": "151s",
            "timeWindows": [
              {
                "endTime": "1970-01-01T00:33:21Z",
                "startTime": "1970-01-01T00:16:41Z"
              }
            ]
          }
        ]
      }
    ],
    "vehicles": [
      {
        "loadLimits": {
          "weight": {
            "maxLoad": 50
          }
        },
        "endLocation": {
          "latitude": 48.86311,
          "longitude": 2.341205
        },
        "startLocation": {
          "latitude": 48.863102,
          "longitude": 2.341204
        },
        "costPerTraveledHour": 3600
      },
      {
        "loadLimits": {
          "weight": {
            "maxLoad": 60
          }
        },
        "endLocation": {
          "latitude": 48.86312,
          "longitude": 2.341215
        },
        "startLocation": {
          "latitude": 48.863112,
          "longitude": 2.341214
        },
        "costPerTraveledHour": 3600
      }
    ]
  }
}

Run the code

To run the Python code for synchronous requests:

  1. Save the code sample as api_client_send_request.py, and save the JSON file as request.json in the same directory.
  2. Authenticate your environment using the instructions in the "Before you begin" page.
  3. Replace ${YOUR_GCP_PROJECT_ID} with your Google Cloud project ID in the request.json file.
  4. Replace ${YOUR_MAPS_API_KEY} in the request.json file with your API key for Google Maps Platform that you generated in the "Before you begin" section.
  5. At the command line, navigate to the directory containing the files and enter
      python api_client_send_request.py request.json
    Note that the command passes the name of the request file as an argument.

Response

The following is the response to the request.

routes {
  vehicle_start_time {
    seconds: 35
  }
  vehicle_end_time {
    seconds: 4302
  }
  visits {
    is_pickup: true
    start_time {
      seconds: 1000
    }
    demands {
      type: "weight"
      value: 10
    }
    detour {
    }
    arrival_loads {
      type: "weight"
    }
    load_demands {
      key: "weight"
      value {
        amount: 10
      }
    }
  }
  visits {
    shipment_index: 1
    is_pickup: true
    start_time {
      seconds: 1660
    }
    demands {
      type: "weight"
      value: 20
    }
    detour {
      seconds: 756
    }
    arrival_loads {
      type: "weight"
      value: 10
    }
    load_demands {
      key: "weight"
      value {
        amount: 20
      }
    }
  }
  visits {
    start_time {
      seconds: 3000
    }
    demands {
      type: "weight"
      value: -10
    }
    detour {
      seconds: 1340
    }
    arrival_loads {
      type: "weight"
      value: 30
    }
    load_demands {
      key: "weight"
      value {
        amount: -10
      }
    }
  }
  visits {
    shipment_index: 1
    start_time {
      seconds: 3250
    }
    demands {
      type: "weight"
      value: -20
    }
    detour {
      seconds: 1439
    }
    arrival_loads {
      type: "weight"
      value: 20
    }
    load_demands {
      key: "weight"
      value {
        amount: -20
      }
    }
  }
  transitions {
    travel_duration {
      seconds: 965
    }
    travel_distance_meters: 4244.0
    total_duration {
      seconds: 965
    }
    start_time {
      seconds: 35
    }
    vehicle_loads {
      key: "weight"
      value {
      }
    }
  }
  transitions {
    travel_duration {
      seconds: 510
    }
    travel_distance_meters: 2479.0
    total_duration {
      seconds: 510
    }
    start_time {
      seconds: 1150
    }
    vehicle_loads {
      key: "weight"
      value {
        amount: 10
      }
    }
  }
  transitions {
    travel_duration {
    }
    wait_duration {
      seconds: 1189
    }
    total_duration {
      seconds: 1189
    }
    start_time {
      seconds: 1811
    }
    vehicle_loads {
      key: "weight"
      value {
        amount: 30
      }
    }
  }
  transitions {
    travel_duration {
    }
    total_duration {
    }
    start_time {
      seconds: 3250
    }
    vehicle_loads {
      key: "weight"
      value {
        amount: 20
      }
    }
  }
  transitions {
    travel_duration {
      seconds: 801
    }
    travel_distance_meters: 3111.0
    total_duration {
      seconds: 801
    }
    start_time {
      seconds: 3501
    }
    vehicle_loads {
      key: "weight"
      value {
      }
    }
  }
  metrics {
    performed_shipment_count: 2
    travel_duration {
      seconds: 2276
    }
    wait_duration {
      seconds: 1189
    }
    delay_duration {
    }
    break_duration {
    }
    visit_duration {
      seconds: 802
    }
    total_duration {
      seconds: 4267
    }
    travel_distance_meters: 9834.0
    max_loads {
      key: "weight"
      value {
        amount: 30
      }
    }
  }
  end_loads {
    type: "weight"
  }
  travel_steps {
    duration {
      seconds: 965
    }
    distance_meters: 4244.0
  }
  travel_steps {
    duration {
      seconds: 510
    }
    distance_meters: 2479.0
  }
  travel_steps {
    duration {
    }
  }
  travel_steps {
    duration {
    }
  }
  travel_steps {
    duration {
      seconds: 801
    }
    distance_meters: 3111.0
  }
  vehicle_detour {
    seconds: 4267
  }
}
routes {
  vehicle_index: 1
}
metrics {
  aggregated_route_metrics {
    performed_shipment_count: 2
    travel_duration {
      seconds: 2276
    }
    wait_duration {
      seconds: 1189
    }
    delay_duration {
    }
    break_duration {
    }
    visit_duration {
      seconds: 802
    }
    total_duration {
      seconds: 4267
    }
    travel_distance_meters: 9834.0
    max_loads {
      key: "weight"
      value {
        amount: 30
      }
    }
  }
  used_vehicle_count: 1
  earliest_vehicle_start_time {
    seconds: 35
  }
  latest_vehicle_end_time {
    seconds: 4302
  }
}

For a description of the response, see Response to the request.

Asynchronous API requests

The asynchronous method performs the same operations as the synchronous version, except it immediately returns an asynchronous object that you can use to get the status of the operation. If a route request results is unsuccessful, the status of the operation will include the error. Upon task completion, the model solution is uploaded to Cloud Storage for each successful route. One or more routes can be optimized in a single asynchronous request.

The following script sends an API request to the Cloud Fleet Routing service to asynchronously generate routes.

Python script
import json
import sys

from google.cloud.optimization_v1.services.fleet_routing.client import FleetRoutingClient
from google.cloud.optimization_v1.types.fleet_routing import BatchOptimizeToursRequest


def main(request_file_name):
    # Use the default credentials for the environment to authenticate the client.
    fleet_routing_client = FleetRoutingClient()

    # Get the data.
    with open(request_file_name, 'r') as f:
        # The request must include the "parent" field with the value set to
        # "projects/{YOUR_GCP_PROJECT_ID}".
        fleet_routing_request = BatchOptimizeToursRequest.from_json(f.read())
        # The timeout argument for the gRPC call is independent from the `timeout`
        # field in the request's OptimizeToursRequest message(s).
        print(fleet_routing_request)
        operation = fleet_routing_client.batch_optimize_tours(fleet_routing_request)

        try:
            # Block to wait for the job to finish.
            result = operation.result()
            # Do you stuff.
        except GoogleAPICallError:
            print(operation.operation.error)


if __name__ == '__main__':
  if len(sys.argv) > 1:
    main(sys.argv[1])
  else:
    print('You must include the request file as an argument.')
request.json
{
  "parent": "projects/${YOUR_GCP_PROJECT_ID}",
  "model_configs":[
      {
         "input_config":{
            "gcs_source":{
               "uri":"${REQUEST_MODEL_GCS_PATH}"
            },
            "data_format":"JSON"
         },
         "output_config":{
            "gcs_destination":{
               "uri":"${MODEL_SOLUTION_GCS_PATH}"
            },
            "data_format":"JSON"
         }
      },
      {
         "input_config":{
            "gcs_source":{
               "uri":"${REQUEST_MODEL_GCS_PATH}"
            },
            "data_format":"JSON"
         },
         "output_config":{
            "gcs_destination":{
               "uri":"${MODEL_SOLUTION_GCS_PATH}"
            },
            "data_format":"JSON"
         }
      },
      {
         "input_config":{
            "gcs_source":{
               "uri":"${REQUEST_MODEL_GCS_PATH}"
            },
            "data_format":"JSON"
         },
         "output_config":{
            "gcs_destination":{
               "uri":"${MODEL_SOLUTION_GCS_PATH}"
            },
            "data_format":"JSON"
         }
      }
   ]
}
request_model.json
{
   "parent":"${YOUR_GCP_PROJECT_ID}",
   "allowLargeDeadlineDespiteInterruptionRisk":true,
   "model":{
      "shipments":[
         {
            "deliveries":[
               {
                  "arrivalLocation":{
                     "latitude":48.880941999999997,
                     "longitude":2.3238660000000002
                  },
                  "duration":"250s",
                  "timeWindows":[
                     {
                        "endTime":"1970-01-01T01:06:40Z",
                        "startTime":"1970-01-01T00:50:00Z"
                     }
                  ]
               }
            ],
            "loadDemands": {
              "weight": {
                "amount": "10"
              }
            },
            "pickups":[
               {
                  "arrivalLocation":{
                     "latitude":48.874507000000001,
                     "longitude":2.3036099999999999
                  },
                  "duration":"150s",
                  "timeWindows":[
                     {
                        "endTime":"1970-01-01T00:33:20Z",
                        "startTime":"1970-01-01T00:16:40Z"
                     }
                  ]
               }
            ]
         },
         {
            "deliveries":[
               {
                  "arrivalLocation":{
                     "latitude":48.880940000000002,
                     "longitude":2.3238439999999998
                  },
                  "duration":"251s",
                  "timeWindows":[
                     {
                        "endTime":"1970-01-01T01:06:41Z",
                        "startTime":"1970-01-01T00:50:01Z"
                     }
                  ]
               }
            ],
            "loadDemands": {
              "weight": {
                "amount": "20"
              }
            },
            "pickups":[
               {
                  "arrivalLocation":{
                     "latitude":48.880943000000002,
                     "longitude":2.3238669999999999
                  },
                  "duration":"151s",
                  "timeWindows":[
                     {
                        "endTime":"1970-01-01T00:33:21Z",
                        "startTime":"1970-01-01T00:16:41Z"
                     }
                  ]
               }
            ]
         }
      ],
      "vehicles":[
         {
            "loadLimits": {
               "weight": {
                 "maxLoad": 50
               }
            },
            "endLocation":{
               "latitude":48.863109999999999,
               "longitude":2.341205
            },
            "startLocation":{
               "latitude":48.863101999999998,
               "longitude":2.3412039999999998
            }
         },
         {
            "loadLimits": {
               "weight": {
                 "maxLoad": 60
               }
            },
            "endLocation":{
               "latitude":48.863120000000002,
               "longitude":2.341215
            },
            "startLocation":{
               "latitude":48.863112000000001,
               "longitude":2.3412139999999999
            }
         }
      ]
   }
}

Run the code

To run the Python code:

  1. Save the script as api_client_send_request.py
  2. Authenticate your environment using the instructions in "Before you begin".
  3. Create three files in a Cloud Storage bucket with each one containing the content of request_model.json above. Replace ${YOUR_GCP_PROJECT_NAME} in that file with your Google Cloud project name.
  4. Create a JSON file called request.json in the same directory as api_client_send_request.py. Replace ${REQUEST_MODEL_GCS_PATH} with paths of files you just created on Cloud Storage. Replace ${MODEL_SOLUTION_GCS_PATH} with the three different paths for the three model solutions.
  5. At the command line, navigate to the directory containing the files and type the following command:
    python api_client_send_request.py request.json
    Note that the command passes the name of the request file as an argument.

Response

Long-running operations return a JSON with an operation ID that you can use to get the status of the operation.

After each route is optimized, the solutions are uploaded to the Cloud Storage paths that you specified in the BatchOptimizeRequest request payload. If at least one of BatchOptimizeRequest inputs results in an error, it is returned directly in a JSON response for the operation's status.

For example, you should see an operation status similar to the following JSON for a completed successful :batchOptimizeTours request.

    name: "projects/${YOUR_GCP_PROJECT_NAME}/operations/${OPERATION_ID}"
    done: true
    response {
      type_url: "type.googleapis.com/google.cloud.optimization.v1.BatchOptimizeToursResponse"
    }
    

For a description of the response, see Response to the request in the VRP example page.