diff --git a/tsp-typescript-client/src/models/error-response.ts b/tsp-typescript-client/src/models/error-response.ts new file mode 100644 index 0000000..9ed4a9a --- /dev/null +++ b/tsp-typescript-client/src/models/error-response.ts @@ -0,0 +1,14 @@ +/** + * Model of an error response + */ +export interface ErrorResponse { + /** + * The short, human-readable description of the error. + */ + title: string; + + /** + * The optional human-readable explanation of the error with details helping the client to correct the error. + */ + details?: string; +} diff --git a/tsp-typescript-client/src/models/experiment-error-response.ts b/tsp-typescript-client/src/models/experiment-error-response.ts new file mode 100644 index 0000000..32c095b --- /dev/null +++ b/tsp-typescript-client/src/models/experiment-error-response.ts @@ -0,0 +1,12 @@ +import { ErrorResponse } from "./error-response"; +import { Experiment } from "./experiment"; + +/** + * Model of an error response + */ +export interface TraceErrorResponse extends ErrorResponse { + /** + * The experiment that this error corresponds to. + */ + experiment: Experiment; +} diff --git a/tsp-typescript-client/src/models/trace-error-response.ts b/tsp-typescript-client/src/models/trace-error-response.ts new file mode 100644 index 0000000..3dcc686 --- /dev/null +++ b/tsp-typescript-client/src/models/trace-error-response.ts @@ -0,0 +1,12 @@ +import { ErrorResponse } from "./error-response"; +import { Trace } from "./trace"; + +/** + * Model of an error response + */ +export interface TraceErrorResponse extends ErrorResponse { + /** + * The trace that this error corresponds to. + */ + trace: Trace; +} diff --git a/tsp-typescript-client/src/protocol/rest-client.ts b/tsp-typescript-client/src/protocol/rest-client.ts index c231638..6111b7a 100644 --- a/tsp-typescript-client/src/protocol/rest-client.ts +++ b/tsp-typescript-client/src/protocol/rest-client.ts @@ -103,7 +103,7 @@ export class RestClient { url: string, body?: any, normalizer?: Normalizer, - ): Promise>> { + ): Promise>> { let response: HttpResponse; try { response = await this.httpRequest({ @@ -125,6 +125,11 @@ export class RestClient { if (response.headers?.get('Content-Type') === 'application/json') { try { const parsed = this.jsonParse(response.text); + + // Check if the server sent an error + if (response.status >= 400) { + return new TspClientResponse(response.text, response.status, response.statusText, undefined, parsed); + } try { const responseModel = normalizer ? normalizer(parsed) : parsed; return new TspClientResponse(response.text, response.status, response.statusText, responseModel); diff --git a/tsp-typescript-client/src/protocol/tsp-client-response.ts b/tsp-typescript-client/src/protocol/tsp-client-response.ts index 908b5c3..67b9e04 100644 --- a/tsp-typescript-client/src/protocol/tsp-client-response.ts +++ b/tsp-typescript-client/src/protocol/tsp-client-response.ts @@ -1,3 +1,5 @@ +import { ErrorResponse } from "../models/error-response"; + /** * Trace Server Protocol response. * The response includes the response model from the server if available, @@ -17,6 +19,7 @@ export class TspClientResponse { private readonly statusCode: number, private readonly statusMessage: string, private readonly responseModel?: T, + private readonly errorResponse?: ErrorResponse ) {} /** @@ -47,6 +50,13 @@ export class TspClientResponse { return this.text; } + /** + * Returns the error response from the server in an error case + */ + public getErrorResponse(): ErrorResponse | undefined { + return this.errorResponse; + } + /** * Check if the status code is 200 */ diff --git a/tsp-typescript-client/src/protocol/tsp-client.test.ts b/tsp-typescript-client/src/protocol/tsp-client.test.ts index a0bbbe2..5239674 100644 --- a/tsp-typescript-client/src/protocol/tsp-client.test.ts +++ b/tsp-typescript-client/src/protocol/tsp-client.test.ts @@ -574,4 +574,15 @@ describe('HttpTspClient Deserialization', () => { const output = response.getModel()!; expect(output).toBeDefined(); }); + + it('postTrace-failure', async () => { + httpRequestMock.mockResolvedValueOnce({ status: 404, statusText: 'Not Found', text: '{"title": "No trace at /some/path"}', headers: new Headers({ 'Content-Type': 'application/json' }) }); + const response = await client.openTrace(new Query({})); + + expect(response.getStatusCode()).toEqual(404); + expect(response.getStatusMessage()).toEqual('Not Found'); + expect(response.getText()).toEqual('{"title": "No trace at /some/path"}'); + expect(response.getModel()).toBeUndefined(); + expect(response.getErrorResponse()).toEqual({ title: 'No trace at /some/path' }); + }); });