Skip to content

Commit b3bd761

Browse files
committed
fix(google-api): address PR review comments for validation and API compliance
Resolves review threads from PR #552: Google client improvements: - Add fieldMask validation to postComputeRoutes and postComputeRouteMatrix - Remove unnecessary Content-Type header from GET requests (getGeocode, getReverseGeocode, getTimezone) - Add dimension validation to getPlacePhoto - require maxWidthPx or maxHeightPx per Google Places Photo API requirements Test updates: - Add dimension parameters to getPlacePhoto tests - Add test for missing dimension validation error - Fix postNearbySearch test body order expectation
1 parent e6831a8 commit b3bd761

2 files changed

Lines changed: 42 additions & 25 deletions

File tree

src/lib/google/__tests__/client.test.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ describe("Google API Client", () => {
281281
it("should construct correct URL with photo name", async () => {
282282
await getPlacePhoto({
283283
apiKey: "test-key",
284+
maxWidthPx: 400,
284285
photoName: "places/ABC123/photos/XYZ789",
285286
});
286287

@@ -325,10 +326,20 @@ describe("Google API Client", () => {
325326
await expect(
326327
getPlacePhoto({
327328
apiKey: "test-key",
329+
maxWidthPx: 400,
328330
photoName: "invalid-photo-name",
329331
})
330332
).rejects.toThrow("Invalid photoName");
331333
});
334+
335+
it("should throw error when no dimension parameter provided", async () => {
336+
await expect(
337+
getPlacePhoto({
338+
apiKey: "test-key",
339+
photoName: "places/ABC123/photos/XYZ789",
340+
})
341+
).rejects.toThrow("Either maxWidthPx or maxHeightPx must be provided");
342+
});
332343
});
333344

334345
describe("postNearbySearch", () => {
@@ -355,14 +366,14 @@ describe("Google API Client", () => {
355366
expect.objectContaining({
356367
// Body order matches implementation: locationRestriction, maxResultCount, then includedTypes (added conditionally)
357368
body: JSON.stringify({
358-
includedTypes: ["restaurant", "cafe"],
359369
locationRestriction: {
360370
circle: {
361371
center: { latitude: 40.7128, longitude: -74.006 },
362372
radius: 2000,
363373
},
364374
},
365375
maxResultCount: 15,
376+
includedTypes: ["restaurant", "cafe"],
366377
}),
367378
method: "POST",
368379
})
@@ -451,6 +462,7 @@ describe("Google API Client", () => {
451462
it("should include skipHttpRedirect parameter when true", async () => {
452463
await getPlacePhoto({
453464
apiKey: "test-key",
465+
maxWidthPx: 400,
454466
photoName: "places/ABC123/photos/XYZ789",
455467
skipHttpRedirect: true,
456468
});
@@ -471,6 +483,7 @@ describe("Google API Client", () => {
471483
it("should not include skipHttpRedirect when not provided", async () => {
472484
await getPlacePhoto({
473485
apiKey: "test-key",
486+
maxWidthPx: 400,
474487
photoName: "places/ABC123/photos/XYZ789",
475488
});
476489

src/lib/google/client.ts

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,10 @@ type ComputeRoutesParams = {
198198
export async function postComputeRoutes(
199199
params: ComputeRoutesParams
200200
): Promise<Response> {
201+
if (!params.fieldMask || params.fieldMask.trim().length === 0) {
202+
throw new Error("fieldMask is required for computeRoutes");
203+
}
204+
201205
return await retryWithBackoff(
202206
() =>
203207
fetch("https://routes.googleapis.com/directions/v2:computeRoutes", {
@@ -235,6 +239,10 @@ type ComputeRouteMatrixParams = {
235239
export async function postComputeRouteMatrix(
236240
params: ComputeRouteMatrixParams
237241
): Promise<Response> {
242+
if (!params.fieldMask || params.fieldMask.trim().length === 0) {
243+
throw new Error("fieldMask is required for computeRouteMatrix");
244+
}
245+
238246
return await retryWithBackoff(
239247
() =>
240248
fetch("https://routes.googleapis.com/distanceMatrix/v2:computeRouteMatrix", {
@@ -282,14 +290,11 @@ export async function getGeocode(params: GeocodeParams): Promise<Response> {
282290
url.searchParams.set("address", trimmedAddress);
283291
url.searchParams.set("key", params.apiKey);
284292

285-
return await retryWithBackoff(
286-
() =>
287-
fetch(url.toString(), {
288-
headers: { "Content-Type": "application/json" },
289-
method: "GET",
290-
}),
291-
{ attempts: 3, baseDelayMs: 200, maxDelayMs: 1_000 }
292-
);
293+
return await retryWithBackoff(() => fetch(url.toString(), { method: "GET" }), {
294+
attempts: 3,
295+
baseDelayMs: 200,
296+
maxDelayMs: 1_000,
297+
});
293298
}
294299

295300
/**
@@ -320,14 +325,11 @@ export async function getReverseGeocode(
320325
url.searchParams.set("latlng", `${params.lat},${params.lng}`);
321326
url.searchParams.set("key", params.apiKey);
322327

323-
return await retryWithBackoff(
324-
() =>
325-
fetch(url.toString(), {
326-
headers: { "Content-Type": "application/json" },
327-
method: "GET",
328-
}),
329-
{ attempts: 3, baseDelayMs: 200, maxDelayMs: 1_000 }
330-
);
328+
return await retryWithBackoff(() => fetch(url.toString(), { method: "GET" }), {
329+
attempts: 3,
330+
baseDelayMs: 200,
331+
maxDelayMs: 1_000,
332+
});
331333
}
332334

333335
// === Legacy Timezone API ===
@@ -364,14 +366,11 @@ export async function getTimezone(params: TimezoneParams): Promise<Response> {
364366
);
365367
url.searchParams.set("key", params.apiKey);
366368

367-
return await retryWithBackoff(
368-
() =>
369-
fetch(url.toString(), {
370-
headers: { "Content-Type": "application/json" },
371-
method: "GET",
372-
}),
373-
{ attempts: 3, baseDelayMs: 200, maxDelayMs: 1_000 }
374-
);
369+
return await retryWithBackoff(() => fetch(url.toString(), { method: "GET" }), {
370+
attempts: 3,
371+
baseDelayMs: 200,
372+
maxDelayMs: 1_000,
373+
});
375374
}
376375

377376
// === Places Photo API ===
@@ -407,6 +406,11 @@ export async function getPlacePhoto(params: PlacePhotoParams): Promise<Response>
407406
);
408407
}
409408

409+
// Google Places Photo API requires at least one dimension parameter
410+
if (params.maxWidthPx === undefined && params.maxHeightPx === undefined) {
411+
throw new Error("Either maxWidthPx or maxHeightPx must be provided");
412+
}
413+
410414
// Validate photo dimensions if provided
411415
const maxDimension = 2048;
412416
if (params.maxWidthPx !== undefined) {

0 commit comments

Comments
 (0)