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
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
"test:integration": "mocha test/integration/*.ts --slow 5000 --timeout 20000 --require ts-node/register",
"test:coverage": "nyc npm run test:unit",
"lint:src": "eslint src/ --ext .ts",
"lint:src:fix": "eslint src/ --ext .ts --fix",
"lint:test": "eslint test/ --ext .ts",
"lint:test:fix": "eslint test/ --ext .ts --fix",
"apidocs": "run-s api-extractor:local api-documenter",
"api-extractor": "node generate-reports.js",
"api-extractor:local": "npm run build && node generate-reports.js --local",
Expand Down
25 changes: 21 additions & 4 deletions src/data-connect/data-connect-api-client-internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,17 @@ const FIREBASE_DATA_CONNECT_EMULATOR_BASE_URL_FORMAT =
const EXECUTE_GRAPH_QL_ENDPOINT = 'executeGraphql';
const EXECUTE_GRAPH_QL_READ_ENDPOINT = 'executeGraphqlRead';

const DATA_CONNECT_CONFIG_HEADERS = {
'X-Firebase-Client': `fire-admin-node/${utils.getSdkVersion()}`
};

function getHeaders(isUsingGen: boolean): { [key: string]: string } {
const headerValue = {
'X-Firebase-Client': `fire-admin-node/${utils.getSdkVersion()}`,
'X-Goog-Api-Client': utils.getMetricsHeader(),
};
if (isUsingGen) {
headerValue['X-Goog-Api-Client'] += ' admin-js/gen';
}
return headerValue;
}

/**
* Class that facilitates sending requests to the Firebase Data Connect backend API.
Expand All @@ -50,6 +58,7 @@ const DATA_CONNECT_CONFIG_HEADERS = {
export class DataConnectApiClient {
private readonly httpClient: HttpClient;
private projectId?: string;
private isUsingGen = false;

constructor(private readonly connectorConfig: ConnectorConfig, private readonly app: App) {
if (!validator.isNonNullObject(app) || !('options' in app)) {
Expand All @@ -59,6 +68,14 @@ export class DataConnectApiClient {
}
this.httpClient = new DataConnectHttpClient(app as FirebaseApp);
}

/**
* Update whether the SDK is using a generated one or not.
* @param isUsingGen
*/
setIsUsingGen(isUsingGen: boolean): void {
this.isUsingGen = isUsingGen;
}

/**
* Execute arbitrary GraphQL, including both read and write queries
Expand Down Expand Up @@ -117,7 +134,7 @@ export class DataConnectApiClient {
const request: HttpRequestConfig = {
method: 'POST',
url,
headers: DATA_CONNECT_CONFIG_HEADERS,
headers: getHeaders(this.isUsingGen),
data,
};
const resp = await this.httpClient.send(request);
Expand Down
8 changes: 8 additions & 0 deletions src/data-connect/data-connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ export class DataConnect {
this.client = new DataConnectApiClient(connectorConfig, app);
}

/**
* @param isUsingGen
* @internal
*/
useGen(isUsingGen: boolean): void {
this.client.setIsUsingGen(isUsingGen);
}

/**
* Execute an arbitrary GraphQL query or mutation
*
Expand Down
8 changes: 6 additions & 2 deletions src/utils/api-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1092,7 +1092,9 @@ export class AuthorizedHttpClient extends HttpClient {
requestCopy.httpAgent = this.app.options.httpAgent;
}

requestCopy.headers['X-Goog-Api-Client'] = getMetricsHeader()
if (!requestCopy.headers['X-Goog-Api-Client']) {
requestCopy.headers['X-Goog-Api-Client'] = getMetricsHeader()
}

return super.send(requestCopy);
});
Expand Down Expand Up @@ -1126,7 +1128,9 @@ export class AuthorizedHttp2Client extends Http2Client {
requestCopy.headers['x-goog-user-project'] = quotaProjectId;
}

requestCopy.headers['X-Goog-Api-Client'] = getMetricsHeader()
if (!requestCopy.headers['X-Goog-Api-Client']) {
requestCopy.headers['X-Goog-Api-Client'] = getMetricsHeader()
}

return super.send(requestCopy);
});
Expand Down
35 changes: 35 additions & 0 deletions test/unit/data-connect/data-connect-api-client-internal.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ describe('DataConnectApiClient', () => {
'X-Goog-Api-Client': getMetricsHeader(),
};

const EXPECTED_HEADERS_WITH_GEN = {
'Authorization': 'Bearer mock-token',
'X-Firebase-Client': `fire-admin-node/${getSdkVersion()}`,
'X-Goog-Api-Client': getMetricsHeader() + ' admin-js/gen',
};

const EMULATOR_EXPECTED_HEADERS = {
'Authorization': 'Bearer owner',
'X-Firebase-Client': `fire-admin-node/${getSdkVersion()}`,
Expand Down Expand Up @@ -229,6 +235,35 @@ describe('DataConnectApiClient', () => {
});
});
});
it('should use gen headers if set on success', () => {
interface UsersResponse {
users: [
user: {
id: string;
name: string;
address: string;
}
];
}
apiClient.setIsUsingGen(true);
const stub = sandbox
.stub(HttpClient.prototype, 'send')
.resolves(utils.responseFrom(TEST_RESPONSE, 200));
return apiClient.executeGraphql<UsersResponse, unknown>('query', {})
.then((resp) => {
expect(resp.data.users).to.be.not.empty;
expect(resp.data.users[0].name).to.be.not.undefined;
expect(resp.data.users[0].address).to.be.not.undefined;
expect(resp.data.users).to.deep.equal(TEST_RESPONSE.data.users);
expect(stub).to.have.been.calledOnce.and.calledWith({
method: 'POST',
url: `https://firebasedataconnect.googleapis.com/v1/projects/test-project/locations/${connectorConfig.location}/services/${connectorConfig.serviceId}:executeGraphql`,
headers: EXPECTED_HEADERS_WITH_GEN,
data: { query: 'query' }
});
apiClient.setIsUsingGen(false);
});
});
});
});

Expand Down