Skip to content

Commit c00855b

Browse files
committed
initial fix
1 parent 9f3d986 commit c00855b

4 files changed

Lines changed: 64 additions & 9 deletions

File tree

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,7 @@ firebase-admin-*.tgz
2222
docgen/markdown/
2323

2424
# Dataconnect integration test artifacts should not be checked in
25-
test/integration/dataconnect/dataconnect/.dataconnect
25+
test/integration/dataconnect/dataconnect/.dataconnect
26+
test/integration/dataconnect/dataconnect-debug.log
27+
test/integration/dataconnect/firebase-debug.log
28+
test/integration/dataconnect/pglite-debug.log

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

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,12 @@ import {
2121
HttpRequestConfig, HttpClient, RequestResponseError, AuthorizedHttpClient
2222
} from '../utils/api-request';
2323
import { FirebaseError, toHttpResponse } from '../utils/error';
24-
import { FirebaseDataConnectError, DataConnectErrorCode, DATA_CONNECT_ERROR_CODE_MAPPING } from './error';
24+
import {
25+
FirebaseDataConnectError,
26+
DataConnectErrorCode,
27+
DATA_CONNECT_ERROR_CODE_MAPPING,
28+
GRPC_STATUS_CODE_TO_STRING
29+
} from './error';
2530
import * as utils from '../utils/index';
2631
import * as validator from '../utils/validator';
2732
import { ConnectorConfig, ExecuteGraphqlResponse, GraphqlOptions, OperationOptions } from './data-connect-api';
@@ -409,10 +414,17 @@ export class DataConnectApiClient {
409414
});
410415
}
411416

412-
const error: ServerError = (response.data as ErrorResponse).error || {};
417+
const data = response.data as any;
418+
const error: ServerError = (validator.isNonNullObject(data) && 'error' in data) ? data.error : data || {};
419+
420+
let status = error.status;
421+
if (!status && validator.isNumber(error.code)) {
422+
status = GRPC_STATUS_CODE_TO_STRING[error.code as number];
423+
}
424+
413425
let code: DataConnectErrorCode = DATA_CONNECT_ERROR_CODE_MAPPING.UNKNOWN;
414-
if (error.status && error.status in DATA_CONNECT_ERROR_CODE_MAPPING) {
415-
code = DATA_CONNECT_ERROR_CODE_MAPPING[error.status];
426+
if (status && status in DATA_CONNECT_ERROR_CODE_MAPPING) {
427+
code = DATA_CONNECT_ERROR_CODE_MAPPING[status];
416428
}
417429
const message = error.message || 'Unknown server error';
418430
return new FirebaseDataConnectError({
@@ -670,10 +682,6 @@ export function useEmulator(): boolean {
670682
return !!emulatorHost();
671683
}
672684

673-
interface ErrorResponse {
674-
error?: ServerError;
675-
}
676-
677685
interface ServerError {
678686
code?: number;
679687
message?: string;

src/data-connect/error.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,26 @@ export class FirebaseDataConnectError extends FirebaseError {
6969
});
7070
}
7171
}
72+
73+
/**
74+
* Mappings from gRPC status codes to their string equivalents.
75+
* @internal
76+
*/
77+
export const GRPC_STATUS_CODE_TO_STRING: Record<number, string> = {
78+
1: 'CANCELLED',
79+
2: 'UNKNOWN',
80+
3: 'INVALID_ARGUMENT',
81+
4: 'DEADLINE_EXCEEDED',
82+
5: 'NOT_FOUND',
83+
6: 'ALREADY_EXISTS',
84+
7: 'PERMISSION_DENIED',
85+
8: 'RESOURCE_EXHAUSTED',
86+
9: 'FAILED_PRECONDITION',
87+
10: 'ABORTED',
88+
11: 'OUT_OF_RANGE',
89+
12: 'UNIMPLEMENTED',
90+
13: 'INTERNAL',
91+
14: 'UNAVAILABLE',
92+
15: 'DATA_LOSS',
93+
16: 'UNAUTHENTICATED',
94+
};

test/unit/data-connect/data-connect-api-client-internal.spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,27 @@ describe('DataConnectApiClient', () => {
179179
.and.have.property('cause', expected.cause);
180180
});
181181

182+
it('should reject when a gRPC-to-HTTP transcoded error response is received', () => {
183+
const grpcError = {
184+
code: 7,
185+
message: 'Permission denied',
186+
};
187+
const mockErr = utils.errorFrom(grpcError, 403);
188+
sandbox
189+
.stub(HttpClient.prototype, 'send')
190+
.rejects(mockErr);
191+
const expected = new FirebaseDataConnectError({
192+
code: 'permission-denied',
193+
message: 'Permission denied',
194+
httpResponse: toHttpResponse(mockErr.response),
195+
cause: mockErr
196+
});
197+
return apiClient.executeGraphql('query', {})
198+
.should.eventually.be.rejected
199+
.and.deep.include(expected)
200+
.and.have.property('cause', expected.cause);
201+
});
202+
182203
it('should reject with unknown-error when error code is not present', () => {
183204
const mockErr = utils.errorFrom({}, 404);
184205
sandbox

0 commit comments

Comments
 (0)