From 77dd5c5349002bc1a5335abb066702f288bf8301 Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Mon, 15 Jul 2024 11:01:01 -0400 Subject: [PATCH 1/2] fix: parse from HTTP errors and prefer that as the cannonical error code when it is provided --- gax/src/googleError.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/gax/src/googleError.ts b/gax/src/googleError.ts index 5a80391f3..e9070b68f 100644 --- a/gax/src/googleError.ts +++ b/gax/src/googleError.ts @@ -90,8 +90,14 @@ export class GoogleError extends Error { new GoogleError(json['error']['message']), proto3Error ); - // Map Http Status Code to gRPC Status Code - if (json['error']['code']) { + // Get gRPC Status Code + if ( + json['error']['status'] && + Status[json['error']['status'] as keyof typeof Status] + ) { + error.code = Status[json['error']['status'] as keyof typeof Status]; + } else if (json['error']['code']) { + // Map Http Status Code to gRPC Status Code error.code = rpcCodeFromHttpStatusCode(json['error']['code']); } else { // If error code is absent, proto3 message default value is 0. We should From e699ee414cef14c8093d4c5d50a87e92baf4db2d Mon Sep 17 00:00:00 2001 From: Mark Duckworth <1124037+MarkDuckworth@users.noreply.github.com> Date: Mon, 15 Jul 2024 11:23:45 -0400 Subject: [PATCH 2/2] New tests. --- gax/test/unit/googleError.ts | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/gax/test/unit/googleError.ts b/gax/test/unit/googleError.ts index 2e85863ec..a4bc7bd1d 100644 --- a/gax/test/unit/googleError.ts +++ b/gax/test/unit/googleError.ts @@ -22,7 +22,7 @@ import * as protobuf from 'protobufjs'; import * as path from 'path'; import {GoogleError, GoogleErrorDecoder} from '../../src/googleError'; import {Metadata} from '@grpc/grpc-js'; -import {rpcCodeFromHttpStatusCode} from '../../src/status'; +import {rpcCodeFromHttpStatusCode, Status} from '../../src/status'; interface MyObj { type: string; @@ -291,17 +291,39 @@ describe('map http status code to gRPC status code', () => { assert.deepStrictEqual(error.code, rpcCodeFromHttpStatusCode(403)); }); - it('error without http status code', () => { + it('error without http error code or status', () => { const json = { error: { message: 'Cloud Translation API has not been used in project 123 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/translate.googleapis.com/overview?project=455411330361 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.', - status: 'PERMISSION_DENIED', }, }; const error = GoogleError.parseHttpError(json); assert.deepStrictEqual(error.code, undefined); }); + + it('prefers http error status over error code', () => { + const errorJsonAborted = { + error: { + code: 409, + message: 'This is a placeholder message.', + status: 'ABORTED', + }, + }; + const errorAborted = GoogleError.parseHttpError(errorJsonAborted); + const errorJsonAlreadyExistss = { + error: { + code: 409, + message: 'This is a placeholder message.', + status: 'ALREADY_EXISTS', + }, + }; + const errorAlreadyExists = GoogleError.parseHttpError( + errorJsonAlreadyExistss + ); + assert.deepStrictEqual(errorAborted.code, Status.ABORTED); + assert.deepStrictEqual(errorAlreadyExists.code, Status.ALREADY_EXISTS); + }); }); describe('http error decoding', () => {