diff --git a/src/OnspringClient.ts b/src/OnspringClient.ts index cbcaaa3..f424a98 100644 --- a/src/OnspringClient.ts +++ b/src/OnspringClient.ts @@ -73,9 +73,29 @@ export class OnspringClient { ); var apiResponse = await this.get(endpoint); + + if (apiResponse.isSuccessful === false) { + return apiResponse; + } + return apiResponse.AsGetPagedAppsResponseType(); } + public async getAppById(appId: number): Promise> { + const endpoint = EndpointFactory.getAppByIdEndpoint( + this._client.defaults.baseURL, + appId + ); + + var apiResponse = await this.get(endpoint); + + if (apiResponse.isSuccessful === false) { + return apiResponse; + } + + return apiResponse.AsAppType(); + } + /** * @method get - Makes a GET request to the specified endpoint. * @param {string} endpoint - The endpoint that will be used to make the request. diff --git a/src/models/ApiResponse.ts b/src/models/ApiResponse.ts index e615d2e..54a98b0 100644 --- a/src/models/ApiResponse.ts +++ b/src/models/ApiResponse.ts @@ -1,5 +1,5 @@ -import { App } from "./App"; -import { GetPagedAppsResponse } from "./GetPagedAppsResponse"; +import { App } from './App'; +import { GetPagedAppsResponse } from './GetPagedAppsResponse'; /** * @class ApiResponse - A generic response object for API requests. @@ -42,10 +42,10 @@ export class ApiResponse { /** * @method AsGetPagedAppsResponseType - Converts the ApiResponse to an ApiResponse. * @returns {ApiResponse} - An ApiResponse. - */ + */ public AsGetPagedAppsResponseType(): ApiResponse { var apiResponse = this as ApiResponse; - + var apps = apiResponse.data.items.map((item: any) => { return new App(item.href, item.id, item.name); }); @@ -64,4 +64,20 @@ export class ApiResponse { getAppsPagedResponse ); } + + AsAppType(): ApiResponse { + var apiResponse = this as ApiResponse; + + var app = new App( + apiResponse.data.href, + apiResponse.data.id, + apiResponse.data.name + ); + + return new ApiResponse( + apiResponse.statusCode, + apiResponse.message, + app + ); + } } diff --git a/tests/ApiResponse.spec.ts b/tests/ApiResponse.spec.ts index dc092be..479d029 100644 --- a/tests/ApiResponse.spec.ts +++ b/tests/ApiResponse.spec.ts @@ -141,4 +141,33 @@ describe('ApiResponse', function () { expect(appsPagedResponse.data.items).to.have.lengthOf(0); }); }); + + describe('AsAppType', function () { + it('should be defined', function () { + expect(ApiResponse.prototype.AsAppType).to.not.be.undefined; + }); + + it('should have no parameters', function () { + expect(ApiResponse.prototype.AsAppType).to.have.lengthOf(0); + }); + + it('should return an ApiResponse when data contain an app', function () { + var mockApiResponse = { + href: 'https://api.onspring.dev/apps/id/1', + id: 1, + name: 'Test App', + }; + + var apiResponse = new ApiResponse(200, 'OK', mockApiResponse); + var appResponse = apiResponse.AsAppType(); + + expect(appResponse).to.be.instanceOf(ApiResponse); + expect(appResponse.data).to.be.instanceOf(App); + expect(appResponse.data.id).to.equal(1); + expect(appResponse.data.name).to.equal('Test App'); + expect(appResponse.data.href).to.equal( + 'https://api.onspring.dev/apps/id/1' + ); + }); + }); }); diff --git a/tests/OnspringClient.spec.ts b/tests/OnspringClient.spec.ts index 7395989..7c91cf7 100644 --- a/tests/OnspringClient.spec.ts +++ b/tests/OnspringClient.spec.ts @@ -81,7 +81,9 @@ describe('OnspringClient', function () { }); it('should not throw an error when the baseUrl is a valid url', function () { - expect(() => new OnspringClient('http://api.onspring.com', apiKey)).to.not.throw(); + expect( + () => new OnspringClient('http://api.onspring.com', apiKey) + ).to.not.throw(); }); it('should not throw an error when the apiKey is a valid string', function () { @@ -94,24 +96,31 @@ describe('OnspringClient', function () { describe('canConnect', function () { it('should be defined', function () { - expect(new OnspringClient(baseUrl, apiKey).canConnect).to.not.be.undefined; + expect(new OnspringClient(baseUrl, apiKey).canConnect).to.not.be + .undefined; }); it('should be a function', function () { - expect(new OnspringClient(baseUrl, apiKey).canConnect).to.be.a('function'); + expect(new OnspringClient(baseUrl, apiKey).canConnect).to.be.a( + 'function' + ); }); it('should have 0 parameters', function () { - expect(new OnspringClient(baseUrl, apiKey).canConnect).to.have.lengthOf(0); + expect(new OnspringClient(baseUrl, apiKey).canConnect).to.have.lengthOf( + 0 + ); }); it('should return a promise', function () { - expect(new OnspringClient(baseUrl, apiKey).canConnect()).to.be.a('promise'); + expect(new OnspringClient(baseUrl, apiKey).canConnect()).to.be.a( + 'promise' + ); }); it('should return a promise that resolves to a boolean', async function () { const client = new OnspringClient(baseUrl, apiKey); - + const mockAxiosClient = axios.create({ baseURL: baseUrl, headers: { @@ -120,13 +129,15 @@ describe('OnspringClient', function () { }, }); - sinon.stub(mockAxiosClient, 'get').returns(Promise.resolve({ - status: 200, - statusText: 'OK', - data: null, - headers: {}, - config: {} as InternalAxiosRequestConfig, - } as AxiosResponse)); + sinon.stub(mockAxiosClient, 'get').returns( + Promise.resolve({ + status: 200, + statusText: 'OK', + data: null, + headers: {}, + config: {} as InternalAxiosRequestConfig, + } as AxiosResponse) + ); sinon.stub(client, '_client' as any).value(mockAxiosClient); @@ -144,14 +155,16 @@ describe('OnspringClient', function () { 'x-api-version': '2', }, }); - - sinon.stub(mockAxiosClient, 'get').returns(Promise.resolve({ - status: 200, - statusText: 'OK', - data: null, - headers: {}, - config: {} as InternalAxiosRequestConfig, - } as AxiosResponse)); + + sinon.stub(mockAxiosClient, 'get').returns( + Promise.resolve({ + status: 200, + statusText: 'OK', + data: null, + headers: {}, + config: {} as InternalAxiosRequestConfig, + } as AxiosResponse) + ); sinon.stub(client, '_client' as any).value(mockAxiosClient); @@ -170,16 +183,18 @@ describe('OnspringClient', function () { }, }); - sinon.stub(mockAxiosClient, 'get').returns(Promise.resolve({ - status: 500, - statusText: 'Internal Server Error', - data: null, - headers: {}, - config: {} as InternalAxiosRequestConfig, - } as AxiosResponse)); + sinon.stub(mockAxiosClient, 'get').returns( + Promise.resolve({ + status: 500, + statusText: 'Internal Server Error', + data: null, + headers: {}, + config: {} as InternalAxiosRequestConfig, + } as AxiosResponse) + ); sinon.stub(client, '_client' as any).value(mockAxiosClient); - + const result = await client.canConnect(); expect(result).to.be.false; }); @@ -189,7 +204,7 @@ describe('OnspringClient', function () { it('should be defined', function () { expect(new OnspringClient(baseUrl, apiKey).getApps).to.not.be.undefined; }); - + it('should be a function', function () { expect(new OnspringClient(baseUrl, apiKey).getApps).to.be.a('function'); }); @@ -259,5 +274,129 @@ describe('OnspringClient', function () { expect(result.data.items[0]).to.be.instanceOf(App); expect(result.data.items[1]).to.be.instanceOf(App); }); + + it('should return a promise that resolves to an api response when request returns a 400 status code', async function () { + const client = new OnspringClient(baseUrl, apiKey); + + const mockAxiosClient = axios.create({ + baseURL: baseUrl, + headers: { + 'x-apikey': apiKey, + 'x-api-version': '2', + }, + }); + + sinon.stub(mockAxiosClient, 'get').returns( + Promise.resolve({ + status: 400, + statusText: 'Bad Request', + data: { + PageSize: ['The field PageSize must be between 0 and 1000.'], + }, + headers: {}, + config: {} as InternalAxiosRequestConfig, + } as AxiosResponse) + ); + + sinon.stub(client, '_client' as any).value(mockAxiosClient); + + const result = await client.getApps(); + + expect(result).to.be.instanceOf(ApiResponse); + expect(result).to.have.property('statusCode', 400); + expect(result).to.have.property('isSuccessful', false); + expect(result).to.have.property('message', '{"PageSize":["The field PageSize must be between 0 and 1000."]}'); + expect(result).to.have.property('data'); + expect(result.data).to.be.null; + }); + + it('should return a promise that resolves to an api response when request returns a 401 status code', async function () { + const client = new OnspringClient(baseUrl, apiKey); + + const mockAxiosClient = axios.create({ + baseURL: baseUrl, + headers: { + 'x-apikey': apiKey, + 'x-api-version': '2', + }, + }); + + sinon.stub(mockAxiosClient, 'get').returns( + Promise.resolve({ + status: 401, + statusText: 'Unauthorized', + headers: {}, + config: {} as InternalAxiosRequestConfig, + } as AxiosResponse) + ); + + sinon.stub(client, '_client' as any).value(mockAxiosClient); + + const result = await client.getApps(); + + expect(result).to.be.instanceOf(ApiResponse); + expect(result).to.have.property('statusCode', 401); + expect(result).to.have.property('isSuccessful', false); + expect(result.message).to.be.undefined; + expect(result.data).to.be.null; + }); + }); + + describe('getAppById', function () { + it('should be defined', function () { + expect(new OnspringClient(baseUrl, apiKey).getAppById).to.not.be.undefined; + }); + + it('should be a function', function () { + expect(new OnspringClient(baseUrl, apiKey).getAppById).to.be.a('function'); + }); + + it('should have 1 parameter', function () { + expect(new OnspringClient(baseUrl, apiKey).getAppById).to.have.lengthOf(1); + }); + + it('should return a promise', function () { + expect(new OnspringClient(baseUrl, apiKey).getAppById(1)).to.be.a('promise'); + }); + + it('should return a promise that resolves to an api response of an app when request is successful', async function () { + const client = new OnspringClient(baseUrl, apiKey); + + const mockAxiosClient = axios.create({ + baseURL: baseUrl, + headers: { + 'x-apikey': apiKey, + 'x-api-version': '2', + }, + }); + + sinon.stub(mockAxiosClient, 'get').returns( + Promise.resolve({ + status: 200, + statusText: 'OK', + data: { + href: 'https://api.onspring.dev/Apps/id/1', + id: 1, + name: 'Test App 1', + }, + headers: {}, + config: {} as InternalAxiosRequestConfig, + } as AxiosResponse) + ); + + sinon.stub(client, '_client' as any).value(mockAxiosClient); + + const result = await client.getAppById(1); + expect(result).to.be.instanceOf(ApiResponse); + expect(result).to.have.property('statusCode', 200); + expect(result).to.have.property('isSuccessful', true); + expect(result).to.have.property('message', ''); + expect(result).to.have.property('data'); + expect(result.data).to.be.instanceOf(App); + expect(result.data).to.have.property('id', 1); + expect(result.data).to.have.property('name', 'Test App 1'); + }); + + // TODO: Add test cases for 401, 403, and 404 status codes }); });