This guide demonstrates how to efficiently retrieve a large batch of drives using the MileIQ External API, including handling rate limits. We’ll use Python to showcase the process, but the principles can be applied to any programming language.
Prerequisites
Before you begin, make sure you have:
- A MileIQ API key
- Python 3.9 or later installed
- The
requests
library installed (pip install requests
)
- The
pytz
library installed (pip install pytz
)
It’s important to note that the MileIQ External API doesn’t use traditional offset/limit pagination. Instead, it uses a timestamp-based pagination method. To paginate through the results, you need to use the modified_before
and modified_after
parameters in conjunction with the has_more
field in the response body.
Here’s how it works:
- In your initial request, you set
modified_after
to the start of your desired date range and modified_before
to the end of the range.
- The API returns a batch of results and a
has_more
boolean indicating if there are more results to fetch.
- If
has_more
is true, you make another request, but this time you set modified_before
to the modified
timestamp of the last drive in the previous batch.
- You repeat this process until
has_more
is false or you’ve retrieved all the drives you need.
This pagination method allows for efficient retrieval of large datasets while maintaining consistency even if new drives are added or modified during the pagination process.
Setting Up
First, let’s import the necessary libraries and set up our API configuration:
import requests
from datetime import datetime, timedelta
import pytz
import time
def make_api_request(url, params, headers):
response = requests.get(url, params=params, headers=headers)
if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', 60))
print(f"Rate limit exceeded. Waiting for {retry_after} seconds.")
time.sleep(retry_after)
return make_api_request(url, params, headers) # Retry the request
# Print rate limiting information
print(f"Rate Limit: {response.headers.get('X-RateLimit-Limit')}")
print(f"Remaining: {response.headers.get('X-RateLimit-Remaining')}")
print(f"Reset: {response.headers.get('X-RateLimit-Reset')}")
return response
API_BASE_URL = "https://api.mileiq.com/v1/drives"
API_KEY = "your_api_key_here"
# Set the date range for which you want to retrieve drives
end_date = datetime.now(pytz.utc)
start_date = end_date - timedelta(days=30) # Retrieve drives from the last 30 days
# Initialize variables
all_drives = []
has_more = True
modified_before = end_date.isoformat()
while has_more:
# Prepare the request parameters
params = {
"modified_after": start_date.isoformat(),
"modified_before": modified_before,
"limit": 1000 # Maximum allowed limit
}
# Make the API request
headers = {"Authorization": f"Bearer {API_KEY}"}
response = make_api_request(API_BASE_URL, params, headers)
if response.status_code == 200:
data = response.json()
drives = data["results"]
has_more = data["has_more"]
if drives:
all_drives.extend(drives)
# Update modified_before for the next iteration
modified_before = drives[-1]["modified"]
else:
# No more drives in this time range
has_more = False
else:
print(f"Error: {response.status_code} - {response.text}")
break
print(f"Retrieved {len(drives)} drives. Total drives: {len(all_drives)}")
# Check if we're close to the rate limit
remaining = int(response.headers.get('X-RateLimit-Remaining', 0))
if remaining < 5: # Arbitrary threshold, adjust as needed
reset_time = int(response.headers.get('X-RateLimit-Reset', 0))
wait_time = max(reset_time - int(time.time()), 0)
print(f"Close to rate limit. Waiting for {wait_time} seconds.")
time.sleep(wait_time)
print(f"Finished retrieving drives. Total drives retrieved: {len(all_drives)}")
## Process the retrieved drives
for drive in all_drives: # Here you can process each drive as needed
print(f"Drive ID: {drive['id']}, Modified: {drive['modified']}")
## Example of how to use the retrieved data
if all_drives:
print("\nExample of the first drive retrieved:")
first_drive = all_drives[0]
print(f"Driver: {first_drive['driver']['name']}")
print(f"Distance: {first_drive['details']['distance']['amount']} {first_drive['details']['distance']['units']}")
print(f"Value: {first_drive['details']['value']['amount']/100} {first_drive['details']['value']['currency']}")
print(f"Status: {first_drive['status']}")