Skip to content

Commit 8259508

Browse files
committed
Add executeGraphqlRead()
1 parent 66e4030 commit 8259508

File tree

4 files changed

+63
-10
lines changed

4 files changed

+63
-10
lines changed

etc/firebase-admin.data-connect.api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export class DataConnect {
2525
// (undocumented)
2626
readonly connectorConfig: ConnectorConfig;
2727
executeGraphql<GraphqlResponse, Variables>(query: string, options?: GraphqlOptions<Variables>): Promise<ExecuteGraphqlResponse<GraphqlResponse>>;
28+
executeGraphqlRead<GraphqlResponse, Variables>(query: string, options?: GraphqlOptions<Variables>): Promise<ExecuteGraphqlResponse<GraphqlResponse>>;
2829
}
2930

3031
// @public (undocumented)

src/data-connect/data-connect-api-client-internal.ts

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const DATA_CONNECT_API_URL_FORMAT =
3232
'{host}/v1alpha/projects/{projectId}/locations/{locationId}/services/{serviceId}:{endpointId}';
3333

3434
const EXECUTE_GRAPH_QL_ENDPOINT = 'executeGraphql';
35-
//const EXECUTE_GRAPH_QL_READ_ENDPOINT = 'executeGraphqlRead';
35+
const EXECUTE_GRAPH_QL_READ_ENDPOINT = 'executeGraphqlRead';
3636

3737
const DATA_CONNECT_CONFIG_HEADERS = {
3838
'X-Firebase-Client': `fire-admin-node/${utils.getSdkVersion()}`
@@ -66,6 +66,29 @@ export class DataConnectApiClient {
6666
public async executeGraphql<GraphqlResponse, Variables>(
6767
query: string,
6868
options?: GraphqlOptions<Variables>,
69+
): Promise<ExecuteGraphqlResponse<GraphqlResponse>> {
70+
return this.executeGraphqlHelper(query, EXECUTE_GRAPH_QL_ENDPOINT, options);
71+
}
72+
73+
/**
74+
* Execute arbitrary read-only GraphQL queries
75+
*
76+
* @param query - The GraphQL (read-only) string to be executed.
77+
* @param options - Options
78+
* @returns A promise that fulfills with a `ExecuteGraphqlResponse`.
79+
* @throws FirebaseDataConnectError
80+
*/
81+
public async executeGraphqlRead<GraphqlResponse, Variables>(
82+
query: string,
83+
options?: GraphqlOptions<Variables>,
84+
): Promise<ExecuteGraphqlResponse<GraphqlResponse>> {
85+
return this.executeGraphqlHelper(query, EXECUTE_GRAPH_QL_READ_ENDPOINT, options);
86+
}
87+
88+
private async executeGraphqlHelper<GraphqlResponse, Variables>(
89+
query: string,
90+
endpoint: string,
91+
options?: GraphqlOptions<Variables>,
6992
): Promise<ExecuteGraphqlResponse<GraphqlResponse>> {
7093
if (!validator.isNonEmptyString(query)) {
7194
throw new FirebaseDataConnectError(
@@ -79,16 +102,17 @@ export class DataConnectApiClient {
79102
}
80103
}
81104
const host = (process.env.DATA_CONNECT_EMULATOR_HOST || DATA_CONNECT_HOST);
82-
return this.getUrl(host, this.connectorConfig.location, this.connectorConfig.serviceId, EXECUTE_GRAPH_QL_ENDPOINT)
105+
const data = {
106+
query,
107+
...(options?.variables && { variables: options?.variables }),
108+
};
109+
return this.getUrl(host, this.connectorConfig.location, this.connectorConfig.serviceId, endpoint)
83110
.then(async (url) => {
84111
const request: HttpRequestConfig = {
85112
method: 'POST',
86113
url,
87114
headers: DATA_CONNECT_CONFIG_HEADERS,
88-
data: {
89-
query,
90-
...(options?.variables && { variables: options?.variables }),
91-
}
115+
data,
92116
};
93117
const resp = await this.httpClient.send(request);
94118
return Promise.resolve({
@@ -103,7 +127,7 @@ export class DataConnectApiClient {
103127
});
104128
}
105129

106-
private getUrl(host: string, locationId: string, serviceId: string, endpointId: string): Promise<string> {
130+
private async getUrl(host: string, locationId: string, serviceId: string, endpointId: string): Promise<string> {
107131
return this.getProjectId()
108132
.then((projectId) => {
109133
const urlParams = {

src/data-connect/data-connect.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,19 @@ export class DataConnect {
8888
): Promise<ExecuteGraphqlResponse<GraphqlResponse>> {
8989
return this.client.executeGraphql(query, options);
9090
}
91+
92+
/**
93+
* Execute an arbitrary read-only GraphQL query
94+
*
95+
* @param query - The GraphQL read-only query.
96+
* @param options - Optional options object when creating a new App Check Token.
97+
*
98+
* @returns A promise that fulfills with a `Something`.
99+
*/
100+
public executeGraphqlRead<GraphqlResponse, Variables>(
101+
query: string,
102+
options?: GraphqlOptions<Variables>,
103+
): Promise<ExecuteGraphqlResponse<GraphqlResponse>> {
104+
return this.client.executeGraphqlRead(query, options);
105+
}
91106
}

test/integration/data-connect.spec.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,29 @@ const connectorConfig: ConnectorConfig = {
4545
describe('getDataConnect()', () => {
4646

4747
const query = 'query ListUsers @auth(level: PUBLIC) { users { uid, name, address } }';
48-
49-
//const mutation = 'mutation user { user_insert(data: {uid: "QVBJcy5ndXJ2", address: "Address", name: "Name"}) }'
48+
const mutation = 'mutation user { user_insert(data: {uid: "QVBJcy5ndXJ2", address: "Address", name: "Name"}) }'
5049

5150
describe('executeGraphql()', () => {
52-
it('successfully executes a GraphQL', async () => {
51+
it('executeGraphql() successfully executes a GraphQL', async () => {
5352
const resp = await getDataConnect(connectorConfig).executeGraphql<UserResponse, UserVariables>(query, {});
5453
//console.dir(resp.data.users);
5554
expect(resp.data.users).to.be.not.empty;
5655
expect(resp.data.users[0].name).to.be.not.undefined;
5756
expect(resp.data.users[0].address).to.be.not.undefined;
5857
});
5958
});
59+
60+
describe('executeGraphqlRead()', () => {
61+
it('executeGraphqlRead() successfully executes a read-only GraphQL', async () => {
62+
const resp = await getDataConnect(connectorConfig).executeGraphqlRead<UserResponse, UserVariables>(query, {});
63+
expect(resp.data.users).to.be.not.empty;
64+
expect(resp.data.users[0].name).to.be.not.undefined;
65+
expect(resp.data.users[0].address).to.be.not.undefined;
66+
});
67+
68+
it('executeGraphqlRead() should throw for a GraphQL mutation', async () => {
69+
return getDataConnect(connectorConfig).executeGraphqlRead<UserResponse, UserVariables>(mutation, {})
70+
.should.eventually.be.rejected.and.have.property('code', 'data-connect/permission-denied');
71+
});
72+
});
6073
});

0 commit comments

Comments
 (0)