|
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | 16 |
|
17 | | -// Note: This Routes API implementation is meant to be used only to |
18 | | -// support the example app, and only includes the bare minimum to get |
19 | | -// the route tokens. |
| 17 | +// Minimal Routes API implementation for fetching route tokens. |
| 18 | +// Route tokens are currently only supported for DRIVE travel mode. |
| 19 | +// See: https://developers.google.com/maps/documentation/routes/route_token |
20 | 20 |
|
21 | | -import type { LatLng, Waypoint } from '@googlemaps/react-native-navigation-sdk'; |
| 21 | +import type { LatLng } from '@googlemaps/react-native-navigation-sdk'; |
22 | 22 |
|
23 | | -const ROUTES_API_URL = 'https://routes.googleapis.com'; |
24 | | -const COMPUTE_ROUTES_URL = `${ROUTES_API_URL}/directions/v2:computeRoutes`; |
| 23 | +const COMPUTE_ROUTES_URL = |
| 24 | + 'https://routes.googleapis.com/directions/v2:computeRoutes'; |
25 | 25 |
|
26 | 26 | /** |
27 | | - * Travel modes supported by the Routes API. |
28 | | - */ |
29 | | -export type RoutesApiTravelMode = 'DRIVE' | 'BICYCLE' | 'WALK' | 'TWO_WHEELER'; |
30 | | - |
31 | | -/** |
32 | | - * Routing preference options for the Routes API. |
33 | | - */ |
34 | | -export type RoutingPreference = 'TRAFFIC_AWARE' | 'TRAFFIC_AWARE_OPTIMAL'; |
35 | | - |
36 | | -/** |
37 | | - * Options for the Routes API request. |
38 | | - */ |
39 | | -export interface RoutesApiOptions { |
40 | | - /** The travel mode for the route. Defaults to 'DRIVE'. */ |
41 | | - travelMode?: RoutesApiTravelMode; |
42 | | - /** The routing preference. Defaults to 'TRAFFIC_AWARE'. */ |
43 | | - routingPreference?: RoutingPreference; |
44 | | -} |
45 | | - |
46 | | -/** |
47 | | - * Response from the Routes API containing route tokens. |
48 | | - */ |
49 | | -export interface RoutesApiResponse { |
50 | | - /** List of route tokens returned by the API. */ |
51 | | - routeTokens: string[]; |
52 | | -} |
53 | | - |
54 | | -/** |
55 | | - * Converts a Waypoint to the Routes API waypoint format. |
56 | | - */ |
57 | | -function toRoutesApiWaypoint( |
58 | | - waypoint: Waypoint | LatLng, |
59 | | - via: boolean = false |
60 | | -): Record<string, unknown> { |
61 | | - const output: Record<string, unknown> = { via }; |
62 | | - |
63 | | - // Check if it's a Waypoint with placeId |
64 | | - if ('placeId' in waypoint && waypoint.placeId) { |
65 | | - output.placeId = waypoint.placeId; |
66 | | - } else { |
67 | | - // Handle LatLng or Waypoint with position |
68 | | - let lat: number; |
69 | | - let lng: number; |
70 | | - |
71 | | - if ('position' in waypoint && waypoint.position) { |
72 | | - lat = waypoint.position.lat; |
73 | | - lng = waypoint.position.lng; |
74 | | - } else if ('lat' in waypoint && 'lng' in waypoint) { |
75 | | - lat = waypoint.lat; |
76 | | - lng = waypoint.lng; |
77 | | - } else { |
78 | | - throw new Error( |
79 | | - 'Invalid waypoint: Either position or placeId must be provided.' |
80 | | - ); |
81 | | - } |
82 | | - |
83 | | - const location: Record<string, unknown> = { |
84 | | - latLng: { |
85 | | - latitude: lat, |
86 | | - longitude: lng, |
87 | | - }, |
88 | | - }; |
89 | | - |
90 | | - // Add preferred heading if available |
91 | | - if ('preferredHeading' in waypoint && waypoint.preferredHeading != null) { |
92 | | - location.heading = waypoint.preferredHeading; |
93 | | - } |
94 | | - |
95 | | - output.location = location; |
96 | | - } |
97 | | - |
98 | | - return output; |
99 | | -} |
100 | | - |
101 | | -/** |
102 | | - * Queries the Google Maps Routes API and returns a list of route tokens. |
| 27 | + * Fetches a route token from the Google Maps Routes API. |
| 28 | + * Route tokens are only supported for DRIVE travel mode. |
103 | 29 | * |
104 | | - * @param apiKey - The Google Maps API key with Routes API enabled. |
105 | | - * @param waypoints - A list of waypoints representing the route (minimum 2: origin and destination). |
106 | | - * @param options - Optional configuration for the route request. |
107 | | - * @returns A promise that resolves to a list of route tokens. |
108 | | - * @throws Error if the request fails or returns no route tokens. |
| 30 | + * @param apiKey - Google Maps API key with Routes API enabled. |
| 31 | + * @param origin - Starting location. |
| 32 | + * @param destination - Ending location. |
| 33 | + * @returns The route token string. |
109 | 34 | * |
110 | | - * @example |
111 | | - * ```typescript |
112 | | - * const tokens = await getRouteToken( |
113 | | - * 'YOUR_API_KEY', |
114 | | - * [ |
115 | | - * { lat: 37.7749, lng: -122.4194 }, // Origin |
116 | | - * { lat: 37.3382, lng: -121.8863 }, // Destination |
117 | | - * ], |
118 | | - * { travelMode: 'DRIVE' } |
119 | | - * ); |
120 | | - * ``` |
| 35 | + * @see https://developers.google.com/maps/documentation/routes/route_token |
121 | 36 | */ |
122 | 37 | export async function getRouteToken( |
123 | 38 | apiKey: string, |
124 | | - waypoints: (Waypoint | LatLng)[], |
125 | | - options: RoutesApiOptions = {} |
126 | | -): Promise<string[]> { |
| 39 | + origin: LatLng, |
| 40 | + destination: LatLng |
| 41 | +): Promise<string> { |
127 | 42 | if (!apiKey || apiKey.trim() === '') { |
128 | | - throw new Error( |
129 | | - 'API key is required. Please provide a valid Google Maps API key.' |
130 | | - ); |
131 | | - } |
132 | | - |
133 | | - if (waypoints.length < 2) { |
134 | | - throw new Error( |
135 | | - 'At least two waypoints (origin and destination) are required.' |
136 | | - ); |
| 43 | + throw new Error('API key is required.'); |
137 | 44 | } |
138 | 45 |
|
139 | | - const { travelMode = 'DRIVE', routingPreference = 'TRAFFIC_AWARE' } = options; |
140 | | - |
141 | | - const origin = waypoints[0]!; |
142 | | - const destination = waypoints[waypoints.length - 1]!; |
143 | | - const intermediates = waypoints.slice(1, -1); |
144 | | - |
145 | | - const requestBody: Record<string, unknown> = { |
146 | | - origin: toRoutesApiWaypoint(origin), |
147 | | - destination: toRoutesApiWaypoint(destination), |
148 | | - intermediates: intermediates.map(wp => toRoutesApiWaypoint(wp, true)), |
149 | | - travelMode, |
150 | | - routingPreference, |
151 | | - }; |
152 | | - |
153 | | - const headers: Record<string, string> = { |
154 | | - 'X-Goog-Api-Key': apiKey, |
155 | | - 'X-Goog-FieldMask': 'routes.routeToken', |
156 | | - 'Content-Type': 'application/json', |
157 | | - }; |
158 | | - |
159 | 46 | const response = await fetch(COMPUTE_ROUTES_URL, { |
160 | 47 | method: 'POST', |
161 | | - headers, |
162 | | - body: JSON.stringify(requestBody), |
| 48 | + headers: { |
| 49 | + 'X-Goog-Api-Key': apiKey, |
| 50 | + 'X-Goog-FieldMask': 'routes.routeToken', |
| 51 | + 'Content-Type': 'application/json', |
| 52 | + }, |
| 53 | + body: JSON.stringify({ |
| 54 | + origin: { |
| 55 | + location: { |
| 56 | + latLng: { latitude: origin.lat, longitude: origin.lng }, |
| 57 | + }, |
| 58 | + }, |
| 59 | + destination: { |
| 60 | + location: { |
| 61 | + latLng: { latitude: destination.lat, longitude: destination.lng }, |
| 62 | + }, |
| 63 | + }, |
| 64 | + travelMode: 'DRIVE', |
| 65 | + routingPreference: 'TRAFFIC_AWARE', |
| 66 | + }), |
163 | 67 | }); |
164 | 68 |
|
165 | 69 | if (!response.ok) { |
166 | 70 | const errorText = await response.text(); |
167 | | - throw new Error( |
168 | | - `Failed to get route tokens: ${response.statusText}\n${errorText}` |
169 | | - ); |
| 71 | + throw new Error(`Routes API error: ${response.statusText}\n${errorText}`); |
170 | 72 | } |
171 | 73 |
|
172 | | - const responseData = (await response.json()) as { |
173 | | - routes?: { routeToken: string }[]; |
| 74 | + const data = (await response.json()) as { |
| 75 | + routes?: { routeToken?: string }[]; |
174 | 76 | }; |
175 | | - const routes = responseData.routes; |
176 | 77 |
|
177 | | - if (!routes || routes.length === 0) { |
178 | | - throw new Error('No routes returned from the Routes API.'); |
| 78 | + const routeToken = data.routes?.[0]?.routeToken; |
| 79 | + if (!routeToken) { |
| 80 | + throw new Error('No route token returned from the Routes API.'); |
179 | 81 | } |
180 | 82 |
|
181 | | - return routes.map(route => route.routeToken); |
| 83 | + return routeToken; |
182 | 84 | } |
0 commit comments