Skip to content

Commit

Permalink
Add executeGraphqlRead()
Browse files Browse the repository at this point in the history
  • Loading branch information
lahirumaramba committed Sep 11, 2024
1 parent 66e4030 commit dbe66d8
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 10 deletions.
38 changes: 31 additions & 7 deletions src/data-connect/data-connect-api-client-internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const DATA_CONNECT_API_URL_FORMAT =
'{host}/v1alpha/projects/{projectId}/locations/{locationId}/services/{serviceId}:{endpointId}';

const EXECUTE_GRAPH_QL_ENDPOINT = 'executeGraphql';
//const EXECUTE_GRAPH_QL_READ_ENDPOINT = 'executeGraphqlRead';
const EXECUTE_GRAPH_QL_READ_ENDPOINT = 'executeGraphqlRead';

const DATA_CONNECT_CONFIG_HEADERS = {
'X-Firebase-Client': `fire-admin-node/${utils.getSdkVersion()}`
Expand Down Expand Up @@ -66,6 +66,29 @@ export class DataConnectApiClient {
public async executeGraphql<GraphqlResponse, Variables>(
query: string,
options?: GraphqlOptions<Variables>,
): Promise<ExecuteGraphqlResponse<GraphqlResponse>> {
return this.executeGraphqlHelper(query, EXECUTE_GRAPH_QL_ENDPOINT, options);
}

/**
* Execute arbitrary read-only GraphQL queries
*
* @param query - The GraphQL (read-only) string to be executed.
* @param options - Options
* @returns A promise that fulfills with a `ExecuteGraphqlResponse`.
* @throws FirebaseDataConnectError
*/
public async executeGraphqlRead<GraphqlResponse, Variables>(
query: string,
options?: GraphqlOptions<Variables>,
): Promise<ExecuteGraphqlResponse<GraphqlResponse>> {
return this.executeGraphqlHelper(query, EXECUTE_GRAPH_QL_READ_ENDPOINT, options);
}

private async executeGraphqlHelper<GraphqlResponse, Variables>(
query: string,
endpoint: string,
options?: GraphqlOptions<Variables>,
): Promise<ExecuteGraphqlResponse<GraphqlResponse>> {
if (!validator.isNonEmptyString(query)) {
throw new FirebaseDataConnectError(
Expand All @@ -79,16 +102,17 @@ export class DataConnectApiClient {
}
}
const host = (process.env.DATA_CONNECT_EMULATOR_HOST || DATA_CONNECT_HOST);
return this.getUrl(host, this.connectorConfig.location, this.connectorConfig.serviceId, EXECUTE_GRAPH_QL_ENDPOINT)
const data = {
query,
...(options?.variables && { variables: options?.variables }),
};
return this.getUrl(host, this.connectorConfig.location, this.connectorConfig.serviceId, endpoint)
.then(async (url) => {
const request: HttpRequestConfig = {
method: 'POST',
url,
headers: DATA_CONNECT_CONFIG_HEADERS,
data: {
query,
...(options?.variables && { variables: options?.variables }),
}
data,
};
const resp = await this.httpClient.send(request);
return Promise.resolve({
Expand All @@ -103,7 +127,7 @@ export class DataConnectApiClient {
});
}

private getUrl(host: string, locationId: string, serviceId: string, endpointId: string): Promise<string> {
private async getUrl(host: string, locationId: string, serviceId: string, endpointId: string): Promise<string> {
return this.getProjectId()
.then((projectId) => {
const urlParams = {
Expand Down
15 changes: 15 additions & 0 deletions src/data-connect/data-connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,19 @@ export class DataConnect {
): Promise<ExecuteGraphqlResponse<GraphqlResponse>> {
return this.client.executeGraphql(query, options);
}

/**
* Execute an arbitrary read-only GraphQL query
*
* @param query - The GraphQL read-only query.
* @param options - Optional options object when creating a new App Check Token.
*
* @returns A promise that fulfills with a `Something`.
*/
public executeGraphqlRead<GraphqlResponse, Variables>(
query: string,
options?: GraphqlOptions<Variables>,
): Promise<ExecuteGraphqlResponse<GraphqlResponse>> {
return this.client.executeGraphqlRead(query, options);
}
}
19 changes: 16 additions & 3 deletions test/integration/data-connect.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,29 @@ const connectorConfig: ConnectorConfig = {
describe('getDataConnect()', () => {

const query = 'query ListUsers @auth(level: PUBLIC) { users { uid, name, address } }';

//const mutation = 'mutation user { user_insert(data: {uid: "QVBJcy5ndXJ2", address: "Address", name: "Name"}) }'
const mutation = 'mutation user { user_insert(data: {uid: "QVBJcy5ndXJ2", address: "Address", name: "Name"}) }'

describe('executeGraphql()', () => {
it('successfully executes a GraphQL', async () => {
it('executeGraphql() successfully executes a GraphQL', async () => {
const resp = await getDataConnect(connectorConfig).executeGraphql<UserResponse, UserVariables>(query, {});
//console.dir(resp.data.users);
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;
});
});

describe('executeGraphqlRead()', () => {
it('executeGraphqlRead() successfully executes a read-only GraphQL', async () => {
const resp = await getDataConnect(connectorConfig).executeGraphqlRead<UserResponse, UserVariables>(query, {});
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;
});

it('executeGraphqlRead() should throw for a GraphQL mutation', async () => {
return getDataConnect(connectorConfig).executeGraphqlRead<UserResponse, UserVariables>(mutation, {})
.should.eventually.be.rejected.and.have.property('code', 'data-connect/permission-denied');
});
});
});

0 comments on commit dbe66d8

Please sign in to comment.