Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions src/main/java/serpapi/SerpApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,12 @@ public JsonObject search(Map<String, String> parameter) throws SerpApiException
* @throws SerpApiException wraps backend error message
*/
public JsonArray location(Map<String, String> parameter) throws SerpApiException {
String content = get("/locations.json", "json", parameter);
String content = get("/locations.json", "json", parameter);
JsonElement element = gson.fromJson(content, JsonElement.class);
// An error is reported as an object, where a successful call returns an array.
if (element.isJsonObject() && element.getAsJsonObject().has("error")) {
this.client.triggerSerpApiException(content);
}
return element.getAsJsonArray();
}

Expand Down Expand Up @@ -125,9 +129,15 @@ public JsonObject account() throws SerpApiException {
* @return JsonObject created by gson parser
*/
private JsonObject json(String endpoint, Map<String, String> parameter) throws SerpApiException {
String content = get(endpoint, "json", parameter);
String content = get(endpoint, "json", parameter);
JsonElement element = gson.fromJson(content, JsonElement.class);
return element.getAsJsonObject();
JsonObject result = element.getAsJsonObject();
// SerpApi reports some failures in the body of an HTTP 200 response, so the
// status code alone is not enough to tell success from failure.
if (result.has("error")) {
this.client.triggerSerpApiException(content);
}
return result;
}

/***
Expand Down
91 changes: 91 additions & 0 deletions src/test/java/serpapi/ErrorResponseTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package serpapi;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import org.junit.Test;

import java.util.HashMap;
import java.util.Map;

import static org.junit.Assert.*;

/**
* Test that an error reported in the body of an HTTP 200 response is raised as
* a SerpApiException rather than handed back to the caller as a result.
*/
public class ErrorResponseTest {

/**
* Stubbed HTTP client returning a canned body, so these tests never reach the network.
*/
private static class StubHttp extends SerpApiHttp {
private final String body;

StubHttp(String body) {
super("/search");
this.body = body;
}

@Override
public String get(Map<String, String> parameter) {
return body;
}
}

// Recorded from the google_events engine: HTTP 200, status "Success", no results.
private static final String EMPTY_EVENTS = "{"
+ "\"search_metadata\":{\"status\":\"Success\"},"
+ "\"search_information\":{\"events_results_state\":\"Fully empty\"},"
+ "\"error\":\"Google hasn't returned any results for this query.\"}";

private static final String ORGANIC_RESULTS =
"{\"search_metadata\":{\"status\":\"Success\"},\"organic_results\":[{\"position\":1}]}";

private static SerpApi clientReturning(String body) {
SerpApi serpapi = new SerpApi(new HashMap<>());
serpapi.client = new StubHttp(body);
return serpapi;
}

@Test
public void searchRaisesOnErrorInBody() {
try {
clientReturning(EMPTY_EVENTS).search(new HashMap<>());
fail("expected SerpApiException for a 200 response carrying an error field");
} catch (SerpApiException e) {
assertEquals("Google hasn't returned any results for this query.", e.getMessage());
}
}

@Test
public void searchReturnsResultsWhenBodyHasNoError() throws SerpApiException {
JsonObject results = clientReturning(ORGANIC_RESULTS).search(new HashMap<>());
assertEquals(1, results.getAsJsonArray("organic_results").size());
}

@Test
public void accountRaisesOnErrorInBody() {
try {
clientReturning("{\"error\":\"Invalid API key.\"}").account();
fail("expected SerpApiException for a 200 response carrying an error field");
} catch (SerpApiException e) {
assertEquals("Invalid API key.", e.getMessage());
}
}

@Test
public void locationRaisesOnErrorInBody() {
try {
clientReturning("{\"error\":\"Invalid API key.\"}").location(new HashMap<>());
fail("expected SerpApiException instead of a cast failure on the error object");
} catch (SerpApiException e) {
assertEquals("Invalid API key.", e.getMessage());
}
}

@Test
public void locationReturnsArrayWhenBodyHasNoError() throws SerpApiException {
JsonArray locations = clientReturning("[{\"id\":\"austin\"}]").location(new HashMap<>());
assertEquals(1, locations.size());
}
}
Loading