Skip to content

Commit d220ca7

Browse files
author
Anonymous Committer
committed
feat: return raw JSON from high-level client
1 parent e3d8288 commit d220ca7

File tree

8 files changed

+94
-134
lines changed

8 files changed

+94
-134
lines changed

README.md

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ with Client(api_key="YOUR_API_KEY") as client:
3838
location="New York, NY",
3939
language="en",
4040
)
41-
print(response.organic_results)
41+
print(response)
42+
print(response["data"])
4243
```
4344

4445
## Promoted High-Level API
@@ -57,17 +58,12 @@ images = client.google.images.search(query="espresso machine")
5758
shopping = client.google.shopping.search(query="espresso tamper")
5859
overview = client.google.ai.overview(url="https://example.com/ai-overview")
5960

61+
print(search["data"])
62+
6063
client.close()
6164
```
6265

63-
Promoted high-level responses are parsed into Pydantic models:
64-
65-
- `GoogleSearchResponse`
66-
- `GoogleMapsSearchResponse`
67-
- `GoogleNewsSearchResponse`
68-
- `GoogleImagesSearchResponse`
69-
- `GoogleShoppingSearchResponse`
70-
- `GoogleAIOverviewResponse`
66+
Promoted high-level responses are plain Python dictionaries that mirror the API's JSON response envelope. The SDK does not auto-unpack `data`.
7167

7268
## Configuration
7369

justserpapi/__init__.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,6 @@
1616
"ApiKeyError",
1717
"ApiAttributeError",
1818
"ApiException",
19-
"GoogleSearchResponse",
20-
"GoogleMapsSearchResponse",
21-
"GoogleNewsSearchResponse",
22-
"GoogleImagesSearchResponse",
23-
"GoogleShoppingSearchResponse",
24-
"GoogleAIOverviewResponse",
25-
"GoogleAutocompleteResponse",
2619
]
2720

2821
# import high-level client
@@ -35,12 +28,3 @@
3528
from justserpapi.exceptions import ApiKeyError as ApiKeyError
3629
from justserpapi.exceptions import ApiAttributeError as ApiAttributeError
3730
from justserpapi.exceptions import ApiException as ApiException
38-
39-
# import models into sdk package
40-
from justserpapi.models import GoogleAIOverviewResponse as GoogleAIOverviewResponse
41-
from justserpapi.models import GoogleAutocompleteResponse as GoogleAutocompleteResponse
42-
from justserpapi.models import GoogleImagesSearchResponse as GoogleImagesSearchResponse
43-
from justserpapi.models import GoogleMapsSearchResponse as GoogleMapsSearchResponse
44-
from justserpapi.models import GoogleNewsSearchResponse as GoogleNewsSearchResponse
45-
from justserpapi.models import GoogleSearchResponse as GoogleSearchResponse
46-
from justserpapi.models import GoogleShoppingSearchResponse as GoogleShoppingSearchResponse

justserpapi/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
"""Package version."""
22

3-
__version__ = "2.0.0"
3+
__version__ = "3.0.0"

justserpapi/client.py

Lines changed: 24 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,16 @@
22

33
from __future__ import annotations
44

5-
from typing import Any, Optional, Tuple, Type, TypeVar, Union
5+
from typing import Any, Dict, Optional, Tuple, Union
66

77
from urllib3.util.retry import Retry
88

99
from justserpapi.api.google_api_api import GoogleAPIApi
1010
from justserpapi.api_client import ApiClient
1111
from justserpapi.configuration import Configuration
12-
from justserpapi.models.responses import (
13-
BasePayloadModel,
14-
GoogleAIOverviewResponse,
15-
GoogleAutocompleteResponse,
16-
GoogleImagesSearchResponse,
17-
GoogleMapsSearchResponse,
18-
GoogleNewsSearchResponse,
19-
GoogleSearchResponse,
20-
GoogleShoppingSearchResponse,
21-
)
2212

2313
TimeoutValue = Optional[Union[float, Tuple[float, float]]]
24-
T = TypeVar("T", bound=BasePayloadModel)
14+
JSONDict = Dict[str, Any]
2515

2616
DEFAULT_HOST = "https://api.justserpapi.com"
2717
DEFAULT_TIMEOUT: TimeoutValue = 30.0
@@ -52,41 +42,42 @@ def _with_timeout(self, kwargs: dict[str, Any]) -> dict[str, Any]:
5242
kwargs["_request_timeout"] = self._timeout
5343
return kwargs
5444

55-
def _typed_call(self, method_name: str, response_model: Type[T], **kwargs: Any) -> T:
45+
def _json_call(self, method_name: str, **kwargs: Any) -> JSONDict:
5646
payload = getattr(self._api, method_name)(**self._with_timeout(kwargs))
57-
if isinstance(payload, response_model):
58-
return payload
5947
if isinstance(payload, dict):
60-
return response_model.model_validate(payload)
61-
return response_model.model_validate({"payload": payload})
48+
return payload
49+
raise TypeError(
50+
"%s returned %s instead of a JSON object."
51+
% (method_name, type(payload).__name__)
52+
)
6253

6354

6455
class GoogleMapsResource(_GoogleBaseResource):
65-
def search(self, *, query: str, **kwargs: Any) -> GoogleMapsSearchResponse:
66-
return self._typed_call("maps_search", GoogleMapsSearchResponse, query=query, **kwargs)
56+
def search(self, *, query: str, **kwargs: Any) -> JSONDict:
57+
return self._json_call("maps_search", query=query, **kwargs)
6758

6859

6960
class GoogleNewsResource(_GoogleBaseResource):
70-
def search(self, *, query: str, **kwargs: Any) -> GoogleNewsSearchResponse:
71-
return self._typed_call("news_search", GoogleNewsSearchResponse, query=query, **kwargs)
61+
def search(self, *, query: str, **kwargs: Any) -> JSONDict:
62+
return self._json_call("news_search", query=query, **kwargs)
7263

7364

7465
class GoogleImagesResource(_GoogleBaseResource):
75-
def search(self, *, query: str, **kwargs: Any) -> GoogleImagesSearchResponse:
76-
return self._typed_call("images_search", GoogleImagesSearchResponse, query=query, **kwargs)
66+
def search(self, *, query: str, **kwargs: Any) -> JSONDict:
67+
return self._json_call("images_search", query=query, **kwargs)
7768

7869

7970
class GoogleShoppingResource(_GoogleBaseResource):
80-
def search(self, *, query: str, **kwargs: Any) -> GoogleShoppingSearchResponse:
81-
return self._typed_call("shopping_search", GoogleShoppingSearchResponse, query=query, **kwargs)
71+
def search(self, *, query: str, **kwargs: Any) -> JSONDict:
72+
return self._json_call("shopping_search", query=query, **kwargs)
8273

8374

8475
class GoogleAIResource(_GoogleBaseResource):
85-
def overview(self, *, url: str, **kwargs: Any) -> GoogleAIOverviewResponse:
86-
return self._typed_call("ai_overview", GoogleAIOverviewResponse, url=url, **kwargs)
76+
def overview(self, *, url: str, **kwargs: Any) -> JSONDict:
77+
return self._json_call("ai_overview", url=url, **kwargs)
8778

88-
def mode(self, *, query: str, **kwargs: Any) -> GoogleAIOverviewResponse:
89-
return self._typed_call("ai_mode", GoogleAIOverviewResponse, query=query, **kwargs)
79+
def mode(self, *, query: str, **kwargs: Any) -> JSONDict:
80+
return self._json_call("ai_mode", query=query, **kwargs)
9081

9182

9283
class GoogleResource(_GoogleBaseResource):
@@ -101,11 +92,11 @@ def __init__(self, api_client: ApiClient, timeout: TimeoutValue) -> None:
10192
self.shopping = GoogleShoppingResource(api, timeout)
10293
self.ai = GoogleAIResource(api, timeout)
10394

104-
def search(self, *, query: str, **kwargs: Any) -> GoogleSearchResponse:
105-
return self._typed_call("search", GoogleSearchResponse, query=query, **kwargs)
95+
def search(self, *, query: str, **kwargs: Any) -> JSONDict:
96+
return self._json_call("search", query=query, **kwargs)
10697

107-
def autocomplete(self, *, query: str, **kwargs: Any) -> GoogleAutocompleteResponse:
108-
return self._typed_call("autocomplete", GoogleAutocompleteResponse, query=query, **kwargs)
98+
def autocomplete(self, *, query: str, **kwargs: Any) -> JSONDict:
99+
return self._json_call("autocomplete", query=query, **kwargs)
109100

110101

111102
class Client:

overlays/python/README.md.tmpl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ from {{PACKAGE_NAME}} import Client
1515
1616
with Client(api_key="YOUR_API_KEY", base_url="{{DEFAULT_SERVER_URL}}") as client:
1717
response = client.google.search(query="coffee shops", language="en")
18-
print(response.organic_results)
18+
print(response)
19+
print(response["data"])
1920
```
2021

2122
## Release contract

overlays/python/justserpapi/__init__.py.tmpl

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,6 @@ __all__ = [
1515
"ApiKeyError",
1616
"ApiAttributeError",
1717
"ApiException",
18-
"GoogleSearchResponse",
19-
"GoogleMapsSearchResponse",
20-
"GoogleNewsSearchResponse",
21-
"GoogleImagesSearchResponse",
22-
"GoogleShoppingSearchResponse",
23-
"GoogleAIOverviewResponse",
24-
"GoogleAutocompleteResponse",
2518
]
2619

2720
from justserpapi.client import Client as Client
@@ -32,10 +25,3 @@ from justserpapi.exceptions import ApiValueError as ApiValueError
3225
from justserpapi.exceptions import ApiKeyError as ApiKeyError
3326
from justserpapi.exceptions import ApiAttributeError as ApiAttributeError
3427
from justserpapi.exceptions import ApiException as ApiException
35-
from justserpapi.models import GoogleAIOverviewResponse as GoogleAIOverviewResponse
36-
from justserpapi.models import GoogleAutocompleteResponse as GoogleAutocompleteResponse
37-
from justserpapi.models import GoogleImagesSearchResponse as GoogleImagesSearchResponse
38-
from justserpapi.models import GoogleMapsSearchResponse as GoogleMapsSearchResponse
39-
from justserpapi.models import GoogleNewsSearchResponse as GoogleNewsSearchResponse
40-
from justserpapi.models import GoogleSearchResponse as GoogleSearchResponse
41-
from justserpapi.models import GoogleShoppingSearchResponse as GoogleShoppingSearchResponse

overlays/python/justserpapi/client.py

Lines changed: 24 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,16 @@
22

33
from __future__ import annotations
44

5-
from typing import Any, Optional, Tuple, Type, TypeVar, Union
5+
from typing import Any, Dict, Optional, Tuple, Union
66

77
from urllib3.util.retry import Retry
88

99
from justserpapi.api.google_api_api import GoogleAPIApi
1010
from justserpapi.api_client import ApiClient
1111
from justserpapi.configuration import Configuration
12-
from justserpapi.models.responses import (
13-
BasePayloadModel,
14-
GoogleAIOverviewResponse,
15-
GoogleAutocompleteResponse,
16-
GoogleImagesSearchResponse,
17-
GoogleMapsSearchResponse,
18-
GoogleNewsSearchResponse,
19-
GoogleSearchResponse,
20-
GoogleShoppingSearchResponse,
21-
)
2212

2313
TimeoutValue = Optional[Union[float, Tuple[float, float]]]
24-
T = TypeVar("T", bound=BasePayloadModel)
14+
JSONDict = Dict[str, Any]
2515

2616
DEFAULT_HOST = "https://api.justserpapi.com"
2717
DEFAULT_TIMEOUT: TimeoutValue = 30.0
@@ -52,41 +42,42 @@ def _with_timeout(self, kwargs: dict[str, Any]) -> dict[str, Any]:
5242
kwargs["_request_timeout"] = self._timeout
5343
return kwargs
5444

55-
def _typed_call(self, method_name: str, response_model: Type[T], **kwargs: Any) -> T:
45+
def _json_call(self, method_name: str, **kwargs: Any) -> JSONDict:
5646
payload = getattr(self._api, method_name)(**self._with_timeout(kwargs))
57-
if isinstance(payload, response_model):
58-
return payload
5947
if isinstance(payload, dict):
60-
return response_model.model_validate(payload)
61-
return response_model.model_validate({"payload": payload})
48+
return payload
49+
raise TypeError(
50+
"%s returned %s instead of a JSON object."
51+
% (method_name, type(payload).__name__)
52+
)
6253

6354

6455
class GoogleMapsResource(_GoogleBaseResource):
65-
def search(self, *, query: str, **kwargs: Any) -> GoogleMapsSearchResponse:
66-
return self._typed_call("maps_search", GoogleMapsSearchResponse, query=query, **kwargs)
56+
def search(self, *, query: str, **kwargs: Any) -> JSONDict:
57+
return self._json_call("maps_search", query=query, **kwargs)
6758

6859

6960
class GoogleNewsResource(_GoogleBaseResource):
70-
def search(self, *, query: str, **kwargs: Any) -> GoogleNewsSearchResponse:
71-
return self._typed_call("news_search", GoogleNewsSearchResponse, query=query, **kwargs)
61+
def search(self, *, query: str, **kwargs: Any) -> JSONDict:
62+
return self._json_call("news_search", query=query, **kwargs)
7263

7364

7465
class GoogleImagesResource(_GoogleBaseResource):
75-
def search(self, *, query: str, **kwargs: Any) -> GoogleImagesSearchResponse:
76-
return self._typed_call("images_search", GoogleImagesSearchResponse, query=query, **kwargs)
66+
def search(self, *, query: str, **kwargs: Any) -> JSONDict:
67+
return self._json_call("images_search", query=query, **kwargs)
7768

7869

7970
class GoogleShoppingResource(_GoogleBaseResource):
80-
def search(self, *, query: str, **kwargs: Any) -> GoogleShoppingSearchResponse:
81-
return self._typed_call("shopping_search", GoogleShoppingSearchResponse, query=query, **kwargs)
71+
def search(self, *, query: str, **kwargs: Any) -> JSONDict:
72+
return self._json_call("shopping_search", query=query, **kwargs)
8273

8374

8475
class GoogleAIResource(_GoogleBaseResource):
85-
def overview(self, *, url: str, **kwargs: Any) -> GoogleAIOverviewResponse:
86-
return self._typed_call("ai_overview", GoogleAIOverviewResponse, url=url, **kwargs)
76+
def overview(self, *, url: str, **kwargs: Any) -> JSONDict:
77+
return self._json_call("ai_overview", url=url, **kwargs)
8778

88-
def mode(self, *, query: str, **kwargs: Any) -> GoogleAIOverviewResponse:
89-
return self._typed_call("ai_mode", GoogleAIOverviewResponse, query=query, **kwargs)
79+
def mode(self, *, query: str, **kwargs: Any) -> JSONDict:
80+
return self._json_call("ai_mode", query=query, **kwargs)
9081

9182

9283
class GoogleResource(_GoogleBaseResource):
@@ -101,11 +92,11 @@ def __init__(self, api_client: ApiClient, timeout: TimeoutValue) -> None:
10192
self.shopping = GoogleShoppingResource(api, timeout)
10293
self.ai = GoogleAIResource(api, timeout)
10394

104-
def search(self, *, query: str, **kwargs: Any) -> GoogleSearchResponse:
105-
return self._typed_call("search", GoogleSearchResponse, query=query, **kwargs)
95+
def search(self, *, query: str, **kwargs: Any) -> JSONDict:
96+
return self._json_call("search", query=query, **kwargs)
10697

107-
def autocomplete(self, *, query: str, **kwargs: Any) -> GoogleAutocompleteResponse:
108-
return self._typed_call("autocomplete", GoogleAutocompleteResponse, query=query, **kwargs)
98+
def autocomplete(self, *, query: str, **kwargs: Any) -> JSONDict:
99+
return self._json_call("autocomplete", query=query, **kwargs)
109100

110101

111102
class Client:

0 commit comments

Comments
 (0)