Skip to content

Commit

Permalink
fix: Passthrough original error details from nitric plugin errors. (#207
Browse files Browse the repository at this point in the history
)
  • Loading branch information
tjholm committed Oct 24, 2023
2 parents 92b7266 + b717248 commit 4d87da8
Show file tree
Hide file tree
Showing 30 changed files with 177 additions and 76 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
],
"dependencies": {
"@grpc/grpc-js": "1.8.1",
"@nitric/grpc-error-status": "^0.0.2",
"@opentelemetry/api": "^1.4.1",
"@opentelemetry/exporter-trace-otlp-http": "^0.36.1",
"@opentelemetry/instrumentation": "^0.36.1",
Expand Down
2 changes: 1 addition & 1 deletion src/api/documents/v0/collection-group-ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export class CollectionGroupRef<T extends DocumentStructure> {
name: string
): CollectionGroupRef<T> {
if (this.depth() >= MAX_COLLECTION_DEPTH) {
throw new InvalidArgumentError(
throw new Error(
`Maximum collection depth ${MAX_COLLECTION_DEPTH} exceeded`
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/api/documents/v0/document-ref.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ describe('Document Ref Tests', () => {
const testNestedAgain = () => nestedCollection.collection('nested-again');

expect(testNestedAgain).toThrow(
new InvalidArgumentError('Maximum collection depth 1 exceeded')
new Error('Maximum collection depth 1 exceeded')
);
});
});
Expand Down
2 changes: 1 addition & 1 deletion src/api/documents/v0/document-ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export class DocumentRef<T extends DocumentStructure> {
name: string
): CollectionRef<T> {
if (this.depth() >= MAX_COLLECTION_DEPTH) {
throw new InvalidArgumentError(
throw new Error(
`Maximum collection depth ${MAX_COLLECTION_DEPTH} exceeded`
);
}
Expand Down
4 changes: 2 additions & 2 deletions src/api/documents/v0/query.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,8 @@ describe('Query Tests', () => {

q.pagingFrom('test' as any);

await expect(q.fetch()).rejects.toStrictEqual(
new InvalidArgumentError('Invalid paging token provided!')
await expect(q.fetch()).rejects.toEqual(
new Error('Invalid paging token provided!')
);
});
});
Expand Down
6 changes: 2 additions & 4 deletions src/api/documents/v0/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,7 @@ export class Query<T extends DocumentStructure> {
*/
public limit(limit: number): Query<T> {
if (typeof limit !== 'number' || limit < 0) {
throw new InvalidArgumentError(
'limit must be a positive integer or 0 for unlimited.'
);
throw new Error('limit must be a positive integer or 0 for unlimited.');
}

this.fetchLimit = limit;
Expand All @@ -160,7 +158,7 @@ export class Query<T extends DocumentStructure> {

if (this.pagingToken != null) {
if (!(this.pagingToken instanceof Map)) {
throw new InvalidArgumentError('Invalid paging token provided!');
throw new Error('Invalid paging token provided!');
}

const map = request.getPagingTokenMap();
Expand Down
9 changes: 5 additions & 4 deletions src/api/errors/aborted.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import { ErrorDetails } from '@nitric/sdk/gen/proto/error/v1/error_pb';
import { NitricPluginError } from './plugin-error';
/**
* AbortedError
*
* The operation was aborted
*/
export class AbortedError extends Error {
constructor(message: string) {
super(message);
export class AbortedError extends NitricPluginError {
constructor(message: string, details: ErrorDetails) {
super(message, details);
Object.setPrototypeOf(this, AbortedError.prototype);
}
}
9 changes: 6 additions & 3 deletions src/api/errors/already-exists.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { ErrorDetails } from '@nitric/sdk/gen/proto/error/v1/error_pb';
import { NitricPluginError } from './plugin-error';

/**
* AlreadyExistsError
*
* Client attempted to illegally create an entity that already exists
*/
export class AlreadyExistsError extends Error {
constructor(message: string) {
super(message);
export class AlreadyExistsError extends NitricPluginError {
constructor(message: string, details: ErrorDetails) {
super(message, details);
Object.setPrototypeOf(this, AlreadyExistsError.prototype);
}
}
12 changes: 9 additions & 3 deletions src/api/errors/cancelled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,20 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import {
ErrorDetails,
ErrorScope,
} from '@nitric/sdk/gen/proto/error/v1/error_pb';
import { NitricPluginError } from './plugin-error';

/**
* CancelledError
*
* Operation was cancelled (typically occurs client side)
*/
export class CancelledError extends Error {
constructor(message: string) {
super(message);
export class CancelledError extends NitricPluginError {
constructor(message: string, details: ErrorDetails) {
super(message, details);
Object.setPrototypeOf(this, CancelledError.prototype);
}
}
9 changes: 6 additions & 3 deletions src/api/errors/data-loss.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { ErrorDetails } from '@nitric/sdk/gen/proto/error/v1/error_pb';
import { NitricPluginError } from './plugin-error';

/**
* DataLossError
*
* Unrecoverable data loss or corruption
*/
export class DataLossError extends Error {
constructor(message: string) {
super(message);
export class DataLossError extends NitricPluginError {
constructor(message: string, details: ErrorDetails) {
super(message, details);
Object.setPrototypeOf(this, DataLossError.prototype);
}
}
9 changes: 6 additions & 3 deletions src/api/errors/deadline-exceeded.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { ErrorDetails } from '@nitric/sdk/gen/proto/error/v1/error_pb';
import { NitricPluginError } from './plugin-error';

/**
* DeadlineExceededError
*
* Specified deadline was exceeded before the operation could complete
*/
export class DeadlineExceededError extends Error {
constructor(message: string) {
super(message);
export class DeadlineExceededError extends NitricPluginError {
constructor(message: string, details: ErrorDetails) {
super(message, details);
Object.setPrototypeOf(this, DeadlineExceededError.prototype);
}
}
9 changes: 6 additions & 3 deletions src/api/errors/failed-precondition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { ErrorDetails } from '@nitric/sdk/gen/proto/error/v1/error_pb';
import { NitricPluginError } from './plugin-error';

/**
* FailedPreconditionError
*
* Operation was rejected due to the system being not being
* in a state required for the requested operation.
*/
export class FailedPreconditionError extends Error {
constructor(message: string) {
super(message);
export class FailedPreconditionError extends NitricPluginError {
constructor(message: string, details: ErrorDetails) {
super(message, details);
Object.setPrototypeOf(this, FailedPreconditionError.prototype);
}
}
23 changes: 20 additions & 3 deletions src/api/errors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,16 @@ import { UnauthenticatedError } from './unauthenticated';
import { UnavailableError } from './unavailable';
import { UnimplementedError } from './unimplemented';
import { UnknownError } from './unknown';
import { parse } from '@nitric/grpc-error-status';
import { ErrorDetails } from '@nitric/api/proto/error/v1/error_pb';

// Accept all codes except Status OK
type codes = Exclude<status, status.OK>;

const STATUS_CODE_MAP: Record<codes, new (message: string) => Error> = {
const STATUS_CODE_MAP: Record<
codes,
new (message: string, details: ErrorDetails) => Error
> = {
[status.CANCELLED]: CancelledError,
[status.UNKNOWN]: UnknownError,
[status.INVALID_ARGUMENT]: InvalidArgumentError,
Expand Down Expand Up @@ -61,11 +66,23 @@ const STATUS_CODE_MAP: Record<codes, new (message: string) => Error> = {
export const fromGrpcError = (error: ServiceError): Error => {
const construct = STATUS_CODE_MAP[error.code];

const errorStatus = parse(error);

let errorDetails: ErrorDetails | undefined = undefined;

if (errorStatus) {
const allDetails = errorStatus.parseDetails(ErrorDetails);

if (allDetails.length > 0) {
errorDetails = allDetails[0];
}
}

if (construct) {
return new construct(error.message);
return new construct(error.message, errorDetails);
}

return new UnknownError(error.message);
return new UnknownError(error.message, errorDetails);
};

// Re-export errors
Expand Down
9 changes: 6 additions & 3 deletions src/api/errors/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { ErrorDetails } from '@nitric/sdk/gen/proto/error/v1/error_pb';
import { NitricPluginError } from './plugin-error';

/**
* InternalError
*
* Some invariant error has incurred internally
*/
export class InternalError extends Error {
constructor(message: string) {
super(message);
export class InternalError extends NitricPluginError {
constructor(message: string, details: ErrorDetails) {
super(message, details);
Object.setPrototypeOf(this, InternalError.prototype);
}
}
9 changes: 6 additions & 3 deletions src/api/errors/invalid-argument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { ErrorDetails } from '@nitric/sdk/gen/proto/error/v1/error_pb';
import { NitricPluginError } from './plugin-error';

/**
* InvalidArgumentError
*
* Invalid argument was provided by the client
*/
export class InvalidArgumentError extends Error {
constructor(message: string) {
super(message);
export class InvalidArgumentError extends NitricPluginError {
constructor(message: string, details: ErrorDetails) {
super(message, details);
Object.setPrototypeOf(this, InvalidArgumentError.prototype);
}
}
9 changes: 6 additions & 3 deletions src/api/errors/not-found.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { ErrorDetails } from '@nitric/sdk/gen/proto/error/v1/error_pb';
import { NitricPluginError } from './plugin-error';

/**
* NotFoundError
*
* Requested resource was not found
*/
export class NotFoundError extends Error {
constructor(message: string) {
super(message);
export class NotFoundError extends NitricPluginError {
constructor(message: string, details: ErrorDetails) {
super(message, details);
Object.setPrototypeOf(this, NotFoundError.prototype);
}
}
9 changes: 6 additions & 3 deletions src/api/errors/out-of-range.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { ErrorDetails } from '@nitric/sdk/gen/proto/error/v1/error_pb';
import { NitricPluginError } from './plugin-error';

/**
* OutOfRangeError
*
* The operation was attempted outside of valid range
* e.g. seeking past the end of a file or array, or specifying invalid offsets
*/
export class OutOfRangeError extends Error {
constructor(message: string) {
super(message);
export class OutOfRangeError extends NitricPluginError {
constructor(message: string, details: ErrorDetails) {
super(message, details);
Object.setPrototypeOf(this, OutOfRangeError.prototype);
}
}
9 changes: 6 additions & 3 deletions src/api/errors/permission-denied.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { ErrorDetails } from '@nitric/sdk/gen/proto/error/v1/error_pb';
import { NitricPluginError } from './plugin-error';

/**
* PermissionDeniedError
*
* The client is authenticated but does not have permission to
* perform the requested operation
*/
export class PermissionDeniedError extends Error {
constructor(message: string) {
super(message);
export class PermissionDeniedError extends NitricPluginError {
constructor(message: string, details: ErrorDetails) {
super(message, details);
Object.setPrototypeOf(this, PermissionDeniedError.prototype);
}
}
36 changes: 36 additions & 0 deletions src/api/errors/plugin-error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2021, Nitric Technologies Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import { ErrorDetails } from '@nitric/sdk/gen/proto/error/v1/error_pb';

/**
* CancelledError
*
* Operation was cancelled (typically occurs client side)
*/
export class NitricPluginError extends Error {
constructor(message: string, details?: ErrorDetails) {
let errorMessage = message;
if (details) {
errorMessage = `${message};
Nitric Plugin Error: ${details.getScope().getPlugin()}.${details
.getScope()
.getService()}
Message: ${details.getMessage()}
Caused By: ${details.getCause()}`;
}

super(errorMessage);
}
}
Loading

0 comments on commit 4d87da8

Please sign in to comment.