Skip to content

Commit 861889d

Browse files
Merge pull request #516 from Opteo/v20
v20 update
2 parents 5d3553e + fbb2dbb commit 861889d

21 files changed

Lines changed: 2730 additions & 1310 deletions

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,7 @@ typings/
7979
*.tsbuildinfo
8080

8181
# Library build folder
82-
build
82+
build
83+
84+
# Temporary compilation files
85+
fields.json

CHANGELOG.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,26 @@
11
# Changelog
22

3-
### Upcoming Breaking Changes
3+
### 20.0.1
44

5-
From v20 onwards this library will use the REST api for report, reportStream, search and searchStream. This will result in minor breaking changes to reporting calls:
5+
### Version Upgrade
6+
7+
- Upgraded google-ads-api version to v20. Refer to Google ads release notes [here](https://developers.google.com/google-ads/api/docs/release-notes) for changes.
8+
9+
### REST API
10+
11+
- This library now uses the REST API for report, reportStream, search and searchStream. This will result in minor breaking changes to reporting calls:
612

713
- Fields with the enum value `0` will now be `undefined` instead
814
- Array-fields (such as `final_urls`) with the value `[]` will now be `undefined` instead
915

1016
While these changes are inconvenient, the performance of the REST api is significantly better than the gRPC api, particularly for responses with many rows.
1117

12-
To prepare for this change, we recommend you use the install the `19.0.0-rest-beta` version of this library and test your application with it.
13-
1418
### 19.1.0
1519

1620
### Version Upgrade
1721

1822
- Upgraded google-ads-api version to v19.1. Refer to Google ads release notes [here](https://developers.google.com/google-ads/api/docs/release-notes) for changes.
1923

20-
2124
### 19.0.2
2225

2326
- Fix issue with reportCount() not giving the correct total results count.

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
</p>
88
<p align="center">
99
<a href="https://developers.google.com/google-ads/api/docs/release-notes">
10-
<img src="https://img.shields.io/badge/google%20ads-v19.1.0-009688.svg?style=flat-square">
10+
<img src="https://img.shields.io/badge/google%20ads-v20.0.0-009688.svg?style=flat-square">
1111
</a>
1212
<a href="https://www.npmjs.com/package/google-ads-api">
1313
<img src="https://img.shields.io/npm/v/google-ads-api.svg?style=flat-square">
@@ -26,7 +26,7 @@
2626
# Features
2727

2828
- Simple and easy to use API
29-
- Uses [gRPC](https://grpc.io/) and [Protocol Buffers](https://developers.google.com/protocol-buffers/) internally (recommended by Google)
29+
- Uses [REST](https://developers.google.com/google-ads/api/rest/design/overview) and [Protocol Buffers](https://developers.google.com/protocol-buffers/) internally
3030
- Typescript definitions for all resources, enums, errors and services
3131
- Provides all API functionality
3232

@@ -93,7 +93,7 @@ const customer = client.Customer({
9393

9494
## List accessible customers
9595

96-
This is a special client method for listing the accessible customers for a given refresh token, and is equivalent to [CustomerService.listAccessibleCustomers](https://developers.google.com/google-ads/api/reference/rpc/v13/CustomerService#listaccessiblecustomers). It returns the resource names of available customer accounts.
96+
This is a special client method for listing the accessible customers for a given refresh token, and is equivalent to [CustomerService.listAccessibleCustomers](https://developers.google.com/google-ads/api/reference/rpc/v20/CustomerService#listaccessiblecustomers). It returns the resource names of available customer accounts.
9797

9898
```ts
9999
const client = new GoogleAdsApi({
@@ -385,7 +385,7 @@ const keyword = "24 hour locksmith harlem";
385385

386386
const operations: MutateOperation<
387387
resources.IAdGroupCriterion & {
388-
exempt_policy_violation_keys?: google.ads.googleads.v19.common.IPolicyViolationKey[];
388+
exempt_policy_violation_keys?: google.ads.googleads.v20.common.IPolicyViolationKey[];
389389
}
390390
>[] = [
391391
{
@@ -671,9 +671,9 @@ const customer = client.Customer(
671671

672672
## Error handling
673673

674-
All errors, apart from GRPC specific cases (such as a connection problem or timeout, [see more here](https://github.com/grpc/grpc/blob/master/doc/statuscodes.md)), are instances of a [GoogleAdsFailure](https://developers.google.com/google-ads/api/reference/rpc/v13/GoogleAdsFailure).
674+
All errors, apart from GRPC specific cases (such as a connection problem or timeout, [see more here](https://github.com/grpc/grpc/blob/master/doc/statuscodes.md)), are instances of a [GoogleAdsFailure](https://developers.google.com/google-ads/api/reference/rpc/v20/GoogleAdsFailure).
675675

676-
You can find a list of all error types for a specific version in [the official documentation](https://developers.google.com/google-ads/api/reference/rpc/v13/AccessInvitationErrorEnum.AccessInvitationError), as well as more information about [handling errors here](https://developers.google.com/google-ads/api/docs/best-practices/error-types).
676+
You can find a list of all error types for a specific version in [the official documentation](https://developers.google.com/google-ads/api/reference/rpc/v20/AccessInvitationErrorEnum.AccessInvitationError), as well as more information about [handling errors here](https://developers.google.com/google-ads/api/docs/best-practices/error-types).
677677

678678
```ts
679679
import { errors } from "google-ads-api";

jest.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module.exports = {
33
preset: "ts-jest",
44
testEnvironment: "node",
55
clearMocks: true,
6-
collectCoverage: true,
6+
//collectCoverage: true,
77
coveragePathIgnorePatterns: ["/node_modules/", "jest.config.js"],
88
resetMocks: true,
99
testMatch: [

package.json

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "google-ads-api",
3-
"version": "19.1.0",
3+
"version": "20.0.1",
44
"description": "Google Ads API Client Library for Node.js",
55
"repository": "https://github.com/Opteo/google-ads-api",
66
"main": "build/src/index.js",
@@ -11,30 +11,40 @@
1111
"test": "jest",
1212
"lint": "eslint . --ext .ts",
1313
"build": "tsc",
14-
"compile": "tsc && node build/scripts/index.js",
14+
"compile": "esbuild --bundle --platform=node ./scripts/index.ts --outfile=./build/scripts/index.js && node ./build/scripts/index.js",
1515
"prepare": "rm -rf build && npm run build",
1616
"node": "tsx"
1717
},
1818
"author": "Opteo",
1919
"license": "MIT",
2020
"dependencies": {
2121
"@isaacs/ttlcache": "^1.2.2",
22-
"google-ads-node": "16.0.0",
22+
"axios": "^1.6.7",
23+
"circ-json": "^1.0.4",
24+
"google-ads-node": "17.0.1",
2325
"google-auth-library": "^9.15.1",
24-
"google-gax": "^5.1.0-rc.1",
25-
"long": "^4.0.0"
26+
"google-gax": "^5.1.1-rc.1",
27+
"long": "^4.0.0",
28+
"map-obj": "^4.0.0",
29+
"stream-json": "^1.8.0"
2630
},
2731
"devDependencies": {
2832
"@types/jest": "^29.0.1",
2933
"@types/long": "^4.0.0",
34+
"@types/lodash": "^4.14.202",
3035
"@types/node": "^22.5.4",
3136
"@types/pluralize": "^0.0.29",
37+
"@types/stream-json": "^1.7.7",
3238
"@typescript-eslint/eslint-plugin": "^4.8.2",
3339
"@typescript-eslint/parser": "^4.8.2",
40+
"axios-mock-adapter": "^1.22.0",
41+
"esbuild": "^0.20.1",
3442
"eslint": "^7.14.0",
35-
"jest": "^29.0.3",
43+
"jest": "^29.7.0",
44+
"lodash": "^4.17.21",
3645
"pluralize": "^8.0.0",
37-
"ts-jest": "^29.0.0",
46+
"protobufjs": "^7.2.6",
47+
"ts-jest": "^29.1.2",
3848
"tsx": "^4.19.3",
3949
"typescript": "^5.5.4"
4050
},

scripts/fields.ts

Lines changed: 104 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,24 @@
11
import fs from "fs";
22
import { FILES } from "./path";
3-
import { GoogleAdsApi, services, resources, enums } from "../src";
3+
import { GoogleAdsApi, resources, enums, services } from "../src";
44
import { capitaliseFirstLetter, toCamelCase } from "../src/utils";
5-
5+
import _ from "lodash";
6+
import protosJson from "google-ads-node/build/protos/protos.json";
7+
import { stringify } from "circ-json";
8+
9+
import protobuf from "protobufjs";
10+
const root = protobuf.Root.fromJSON(protosJson);
11+
12+
const primitiveTypes = [
13+
"string",
14+
"number",
15+
"bool",
16+
"int64",
17+
"int32",
18+
"double",
19+
"float",
20+
"bytes",
21+
];
622
// Types
723
interface Resource {
824
attributes: string[];
@@ -34,7 +50,7 @@ export async function compileFields(): Promise<void> {
3450
login_customer_id: LOGIN_CUSTOMER_ID,
3551
});
3652

37-
// @ts-ignore
53+
//@ts-ignore
3854
const [fields]: resources.GoogleAdsField[][] =
3955
// @ts-expect-error Protected usage is fine here
4056
await cus.googleAdsFields.searchGoogleAdsFields(
@@ -55,6 +71,12 @@ export async function compileFields(): Promise<void> {
5571
})
5672
);
5773

74+
// fs.writeFileSync("fields.json", JSON.stringify(fields));
75+
76+
// const fields: resources.GoogleAdsField[] = JSON.parse(
77+
// fs.readFileSync("fields.json").toString()
78+
// );
79+
5880
const resourceConstructs: { [resourceName: string]: Resource } = {};
5981
const enumFields: { [fieldName: string]: string } = {};
6082
const resourceNames: string[] = [];
@@ -158,6 +180,85 @@ export async function compileFields(): Promise<void> {
158180
});
159181

160182
stream.write(`}`);
183+
184+
stream.write(
185+
`\n\n/* -- Field types (represented as circular JSON, used in REST parsing) -- */`
186+
);
187+
stream.write(`\nexport const fieldDataTypes = \``);
188+
189+
/*
190+
Assemble a mega object that represents all the fields and their types,
191+
recursively. This is used in the REST parsing to determine the type of
192+
each field. This is a circular object, so it can't be stringified
193+
normally. We'll use the circ-json package to stringify it.
194+
195+
See fieldDataTypes in autogen/fields.ts for an idea of the final product.
196+
*/
197+
let mega: any = {};
198+
function assembleMega(typeForLookup: string) {
199+
if (typeForLookup.startsWith("com.")) {
200+
typeForLookup = typeForLookup.replace("com.", "");
201+
}
202+
const foundMessage = root.lookupTypeOrEnum(typeForLookup);
203+
204+
if (mega[foundMessage.name]) {
205+
return mega[foundMessage.name];
206+
}
207+
208+
// @ts-ignore
209+
if (foundMessage.valuesById) {
210+
// @ts-ignore
211+
return foundMessage.values;
212+
}
213+
const fields = foundMessage.fields;
214+
215+
const o: any = {};
216+
mega[foundMessage.name] = o;
217+
for (const fieldKey in fields) {
218+
const fieldKeyType = fields[fieldKey].type;
219+
if (primitiveTypes.includes(fieldKeyType)) {
220+
o[fieldKey] = fieldKeyType.toUpperCase();
221+
continue;
222+
}
223+
224+
const parsedRef = assembleMega(fields[fieldKey].type);
225+
o[fieldKey] = parsedRef;
226+
}
227+
228+
mega[foundMessage.name] = o;
229+
230+
return o;
231+
}
232+
233+
// Start by adding GoogleAdsFailure to the mega object. It's a special case that
234+
// Doesn't exist the same way as other fields.
235+
assembleMega("GoogleAdsFailure");
236+
237+
mega = {
238+
...mega,
239+
...mega.GoogleAdsFailure,
240+
};
241+
242+
delete mega.GoogleAdsFailure;
243+
244+
// Now, loop through all the reporting fields and add them to the mega object
245+
// Messages are the main challenge here, as they can contain other messages,
246+
// Sometimes with infite recursion.
247+
for (const field of fields.filter((field) => field.data_type === "MESSAGE")) {
248+
_.set(mega, field.name!, assembleMega(field.type_url as string));
249+
}
250+
for (const field of fields.filter((field) => field.data_type !== "MESSAGE")) {
251+
if (!_.get(mega, field.name!)) {
252+
_.set(
253+
mega,
254+
field.name!,
255+
(field.data_type as string).toUpperCase() as string
256+
);
257+
}
258+
}
259+
260+
stream.write(stringify(mega));
261+
stream.write(`\``);
161262
stream.end();
162263
}
163264

src/client.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export interface ClientOptions {
99
client_secret: string;
1010
developer_token: string;
1111
disable_parsing?: boolean;
12+
max_reporting_rows?: number;
1213
}
1314

1415
export class Client {

0 commit comments

Comments
 (0)