diff --git a/modules/express/src/clientRoutes.ts b/modules/express/src/clientRoutes.ts index 0ae3d95021..6e81519bbf 100755 --- a/modules/express/src/clientRoutes.ts +++ b/modules/express/src/clientRoutes.ts @@ -83,7 +83,7 @@ function handlePing( return req.bitgo.ping(); } -function handlePingExpress(req: ExpressApiRouteRequest<'express.pingExpress', 'get'>) { +function handlePingExpress(req: ExpressApiRouteRequest<'express.v1.pingexpress' | 'express.pingexpress', 'get'>) { return { status: 'express server is ok!', }; @@ -1689,14 +1689,15 @@ export function setupAPIRoutes(app: express.Application, config: Config): void { // V2 routes should be added to www/config/routesV2.js // ping - // /api/v[12]/pingexpress is the only exception to the rule above, as it explicitly checks the health of the - // express server without running into rate limiting with the BitGo server. + // /api/v1/pingexpress and /api/v2/pingexpress are the only exceptions to the rule above, as they explicitly check + // the health of the express server without running into rate limiting with the BitGo server. const router = createExpressRouter(); app.use(router); router.get('express.v1.ping', [prepareBitGo(config), typedPromiseWrapper(handlePing)]); router.get('express.ping', [prepareBitGo(config), typedPromiseWrapper(handlePing)]); - router.get('express.pingExpress', [typedPromiseWrapper(handlePingExpress)]); + router.get('express.v1.pingexpress', [typedPromiseWrapper(handlePingExpress)]); + router.get('express.pingexpress', [typedPromiseWrapper(handlePingExpress)]); // auth router.post('express.login', [prepareBitGo(config), typedPromiseWrapper(handleLogin)]); diff --git a/modules/express/src/typedRoutes/api/common/pingExpress.ts b/modules/express/src/typedRoutes/api/common/pingExpress.ts deleted file mode 100644 index 3b3e80ccf3..0000000000 --- a/modules/express/src/typedRoutes/api/common/pingExpress.ts +++ /dev/null @@ -1,19 +0,0 @@ -import * as t from 'io-ts'; -import { httpRoute, httpRequest } from '@api-ts/io-ts-http'; -import { BitgoExpressError } from '../../schemas/error'; - -/** - * Ping Express - * - * @operationId express.pingExpress - * @tag express - */ -export const GetPingExpress = httpRoute({ - path: '/api/v[12]/pingexpress', - method: 'GET', - request: httpRequest({}), - response: { - 200: t.type({ status: t.string }), - 404: BitgoExpressError, - }, -}); diff --git a/modules/express/src/typedRoutes/api/index.ts b/modules/express/src/typedRoutes/api/index.ts index e465e75ead..eac24075c5 100644 --- a/modules/express/src/typedRoutes/api/index.ts +++ b/modules/express/src/typedRoutes/api/index.ts @@ -4,7 +4,8 @@ import * as express from 'express'; import { GetV1Ping } from './v1/ping'; import { GetV2Ping } from './v2/ping'; -import { GetPingExpress } from './common/pingExpress'; +import { GetV1PingExpress } from './v1/pingExpress'; +import { GetV2PingExpress } from './v2/pingExpress'; import { PostLogin } from './common/login'; import { PostV1Decrypt } from './v1/decrypt'; import { PostV2Decrypt } from './v2/decrypt'; @@ -76,8 +77,11 @@ export const ExpressPingApiSpec = apiSpec({ }); export const ExpressPingExpressApiSpec = apiSpec({ - 'express.pingExpress': { - get: GetPingExpress, + 'express.v1.pingexpress': { + get: GetV1PingExpress, + }, + 'express.pingexpress': { + get: GetV2PingExpress, }, }); diff --git a/modules/express/src/typedRoutes/api/v1/pingExpress.ts b/modules/express/src/typedRoutes/api/v1/pingExpress.ts new file mode 100644 index 0000000000..40fbe8ec86 --- /dev/null +++ b/modules/express/src/typedRoutes/api/v1/pingExpress.ts @@ -0,0 +1,22 @@ +import * as t from 'io-ts'; +import { httpRoute, httpRequest } from '@api-ts/io-ts-http'; +import { BitgoExpressError } from '../../schemas/error'; + +/** + * Ping BitGo Express (v1) + * + * Use this endpoint to check whether your local BitGo Express server is up and reachable. It returns immediately without contacting bitgo.com, so it succeeds even when BitGo's servers are unavailable. Use [Ping](/reference/expressping) instead if you also need to confirm connectivity to BitGo. + * + * @operationId express.v1.pingexpress + * @tag Express + * @private + */ +export const GetV1PingExpress = httpRoute({ + path: '/api/v1/pingexpress', + method: 'GET', + request: httpRequest({}), + response: { + 200: t.type({ status: t.string }), + 404: BitgoExpressError, + }, +}); diff --git a/modules/express/src/typedRoutes/api/v2/pingExpress.ts b/modules/express/src/typedRoutes/api/v2/pingExpress.ts new file mode 100644 index 0000000000..0bc3c846aa --- /dev/null +++ b/modules/express/src/typedRoutes/api/v2/pingExpress.ts @@ -0,0 +1,22 @@ +import * as t from 'io-ts'; +import { httpRoute, httpRequest } from '@api-ts/io-ts-http'; +import { BitgoExpressError } from '../../schemas/error'; + +/** + * Ping BitGo Express + * + * Use this endpoint to check whether your local BitGo Express server is up and reachable. It returns immediately without contacting bitgo.com, so it succeeds even when BitGo's servers are unavailable. Use [Ping](/reference/expressping) instead if you also need to confirm connectivity to BitGo. + * + * @operationId express.pingexpress + * @tag Express + * @public + */ +export const GetV2PingExpress = httpRoute({ + path: '/api/v2/pingexpress', + method: 'GET', + request: httpRequest({}), + response: { + 200: t.type({ status: t.string }), + 404: BitgoExpressError, + }, +}); diff --git a/modules/express/test/unit/typedRoutes/pingExpress.ts b/modules/express/test/unit/typedRoutes/pingExpress.ts new file mode 100644 index 0000000000..6ff8625f1c --- /dev/null +++ b/modules/express/test/unit/typedRoutes/pingExpress.ts @@ -0,0 +1,67 @@ +import * as assert from 'assert'; +import { GetV1PingExpress } from '../../../src/typedRoutes/api/v1/pingExpress'; +import { GetV2PingExpress } from '../../../src/typedRoutes/api/v2/pingExpress'; +import { assertDecode } from './common'; +import 'should'; +import 'should-http'; +import { setupAgent } from '../../lib/testutil'; + +describe('PingExpress route tests', function () { + describe('PostV1PingExpress route definition', function () { + it('should have the correct path', function () { + assert.strictEqual(GetV1PingExpress.path, '/api/v1/pingexpress'); + }); + + it('should have the correct HTTP method', function () { + assert.strictEqual(GetV1PingExpress.method, 'GET'); + }); + + it('should have the correct response types', function () { + assert.ok(GetV1PingExpress.response[200]); + assert.ok(GetV1PingExpress.response[404]); + }); + }); + + describe('PostV2PingExpress route definition', function () { + it('should have the correct path', function () { + assert.strictEqual(GetV2PingExpress.path, '/api/v2/pingexpress'); + }); + + it('should have the correct HTTP method', function () { + assert.strictEqual(GetV2PingExpress.method, 'GET'); + }); + + it('should have the correct response types', function () { + assert.ok(GetV2PingExpress.response[200]); + assert.ok(GetV2PingExpress.response[404]); + }); + }); + + describe('Supertest Integration Tests', function () { + const agent = setupAgent(); + + const expectedStatus = 'express server is ok!'; + + it('should resolve GET /api/v1/pingexpress with the expected payload', async function () { + const result = await agent.get('/api/v1/pingexpress'); + + assert.strictEqual(result.status, 200); + result.body.should.have.property('status'); + assert.strictEqual(result.body.status, expectedStatus); + + const decodedResponse = assertDecode(GetV1PingExpress.response[200], result.body); + assert.strictEqual(decodedResponse.status, expectedStatus); + }); + + it('should resolve GET /api/v2/pingexpress with the expected payload', async function () { + const result = await agent.get('/api/v2/pingexpress'); + + assert.strictEqual(result.status, 200); + result.body.should.have.property('status'); + assert.strictEqual(result.body.status, expectedStatus); + + const decodedResponse = assertDecode(GetV2PingExpress.response[200], result.body); + assert.strictEqual(decodedResponse.status, expectedStatus); + }); + }); +});