Skip to content

Commit 1ceaa19

Browse files
[merchant-api] Initial commit for garf-merchant-api
1 parent 2ea0073 commit 1ceaa19

File tree

7 files changed

+265
-0
lines changed

7 files changed

+265
-0
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# `garf` for Merchant API
2+
3+
[![PyPI](https://img.shields.io/pypi/v/garf-merchant-api?logo=pypi&logoColor=white&style=flat-square)](https://pypi.org/project/garf-merchant-api)
4+
[![Downloads PyPI](https://img.shields.io/pypi/dw/garf-merchant-api?logo=pypi)](https://pypi.org/project/garf-merchant-api/)
5+
6+
`garf-merchant-api` simplifies fetching data from Merchant API using SQL-like queries.
7+
8+
## Prerequisites
9+
10+
* [Merchant API](https://console.cloud.google.com/apis/library/merchantapi.googleapis.com) enabled.
11+
12+
## Installation
13+
14+
`pip install garf-merchant-api`
15+
16+
## Usage
17+
18+
### Run as a library
19+
```
20+
from garf_merchant_api import report_fetcher
21+
from garf_io import writer
22+
23+
24+
# Specify query
25+
query = """
26+
SELECT
27+
date,
28+
clicks
29+
FROM product_performance_view
30+
WHERE date BETWEEN '2023-12-01' AND '2023-12-03'
31+
ORDER BY clicks DESC
32+
""
33+
34+
# Fetch report
35+
fetched_report = (
36+
report_fetcher.MerchantApiReportFetcher()
37+
.fetch(query, query="<YOUR_SEARCH_QUERY_HERE">, account=ACCOUNT_ID)
38+
)
39+
40+
# Write report to console
41+
console_writer = writer.create_writer('console')
42+
console_writer.write(fetched_report, 'output')
43+
```
44+
45+
### Run via CLI
46+
47+
> Install `garf-executors` package to run queries via CLI (`pip install garf-executors`).
48+
49+
```
50+
garf <PATH_TO_QUERIES> --source merchant-api \
51+
--output <OUTPUT_TYPE> \
52+
--source.<SOURCE_PARAMETER=VALUE>
53+
```
54+
55+
where:
56+
57+
* `<PATH_TO_QUERIES>` - local or remove files containing queries
58+
* `<OUTPUT_TYPE>` - output supported by [`garf-io` library](../garf_io/README.md).
59+
* `<SOURCE_PARAMETER=VALUE` - key-value pairs to refine fetching, check [available source parameters](#available-source-parameters).
60+
61+
## Available source parameters
62+
63+
| name | values| comments |
64+
|----- | ----- | -------- |
65+
| `account` | Account(s) to get data to | Multiple accounts are supported, should be comma-separated|
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Copyright 2024 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Defines simplified imports."""
16+
17+
from __future__ import annotations
18+
19+
from garf_merchant_api.api_clients import MerchantApiClient
20+
from garf_merchant_api.report_fetcher import (
21+
MerchantApiReportFetcher,
22+
)
23+
24+
__all__ = [
25+
'MerchantApiClient',
26+
'MerchantApiReportFetcher',
27+
]
28+
29+
__version__ = '0.0.1'
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
"""Creates API client for Merchant API."""
15+
16+
from google.shopping import merchant_reports_v1beta
17+
from typing_extensions import override
18+
19+
from garf_core import api_clients, query_editor
20+
from garf_merchant_api import exceptions
21+
22+
23+
class MerchantApiError(exceptions.GarfMerchantApiError):
24+
"""API specific error."""
25+
26+
27+
class MerchantApiClient(api_clients.BaseClient):
28+
def __init__(
29+
self,
30+
**kwargs: str,
31+
) -> None:
32+
"""Initializes MerchantClient."""
33+
self.query_args = kwargs
34+
35+
@override
36+
def get_response(
37+
self, request: query_editor.BaseQueryElements, **kwargs: str
38+
) -> api_clients.GarfApiResponse:
39+
if not (account := kwargs.get('account')):
40+
raise MerchantApiError('Missing account parameter')
41+
client = merchant_reports_v1beta.ReportServiceClient()
42+
merchant_request = merchant_reports_v1beta.SearchRequest(
43+
parent=f'accounts/{account}',
44+
query=request.text,
45+
)
46+
response = client.search(request=merchant_request)
47+
results = []
48+
for page in response:
49+
for result in page.get('results'):
50+
results.append(result)
51+
return api_clients.GarfApiResponse(results=results)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from garf_core import exceptions
16+
17+
18+
class GarfMerchantApiError(exceptions.GarfError):
19+
"""Base class for all library exceptions."""
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
"""Defines MerchantQuery."""
15+
16+
from garf_core import query_editor
17+
18+
19+
class MerchantApiQuery(query_editor.QuerySpecification):
20+
"""Query to Knowledge Graph Search api."""
21+
22+
def __init__(
23+
self,
24+
text: str,
25+
title: str | None = None,
26+
args: dict[str, str] | None = None,
27+
**kwargs,
28+
) -> None:
29+
"""Initializes MerchantApiQuery."""
30+
super().__init__(text, title, args, **kwargs)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Defines report fetcher."""
16+
17+
from garf_core import parsers, report_fetcher
18+
from garf_merchant_api import MerchantApiClient, query_editor
19+
20+
21+
class MerchantApiReportFetcher(report_fetcher.ApiReportFetcher):
22+
"""Defines report fetcher."""
23+
24+
def __init__(
25+
self,
26+
api_client: MerchantApiClient = MerchantApiClient(),
27+
parser: parsers.BaseParser = parsers.NumericConverterDictParser,
28+
query_spec: query_editor.MerchantApiQuery = query_editor.MerchantApiQuery,
29+
**kwargs: str,
30+
) -> None:
31+
"""Initializes MerchantApiReportFetcher."""
32+
super().__init__(api_client, parser, query_spec, **kwargs)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
[build-system]
2+
requires = ["setuptools >= 61.0"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "garf-merchat-api"
7+
dependencies = [
8+
"garf-core",
9+
"garf-io",
10+
"google-shopping-merchant-reports",
11+
]
12+
authors = [
13+
{name = "Google Inc. (gTech gPS CSE team)", email = "no-reply@google.com"},
14+
]
15+
license = {text = "Apache 2.0"}
16+
requires-python = ">=3.8"
17+
description = "Garf implementation for Google Merchant API"
18+
readme = "README.md"
19+
classifiers = [
20+
"Development Status :: 4 - Beta",
21+
"Programming Language :: Python"
22+
]
23+
24+
dynamic=["version"]
25+
26+
[tool.setuptools.dynamic]
27+
version = {attr = "garf_merchant_api.__version__"}
28+
29+
[project.entry-points.garf]
30+
merchant-api = "garf_merchant_api.report_fetcher"
31+
32+
[options.extras_require]
33+
test = [
34+
"pytest",
35+
"pytest-cov",
36+
"python-dotenv",
37+
]
38+
39+
[project.scripts]

0 commit comments

Comments
 (0)