Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions modules/express/src/clientRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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!',
};
Expand Down Expand Up @@ -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)]);
Expand Down
19 changes: 0 additions & 19 deletions modules/express/src/typedRoutes/api/common/pingExpress.ts

This file was deleted.

10 changes: 7 additions & 3 deletions modules/express/src/typedRoutes/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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,
},
});

Expand Down
22 changes: 22 additions & 0 deletions modules/express/src/typedRoutes/api/v1/pingExpress.ts
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a minimal test that both GET /api/v1/pingexpress and GET /api/v2/pingexpress resolve and return the expected payload

Original file line number Diff line number Diff line change
@@ -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,
},
});
22 changes: 22 additions & 0 deletions modules/express/src/typedRoutes/api/v2/pingExpress.ts
Original file line number Diff line number Diff line change
@@ -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',
Comment on lines +6 to +15
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Ping BitGo Express
*
* @operationId express.pingExpress
* @tag express
* Ping bitgo express to ensure that it is still running. Unlike /ping, this does not try connecting to bitgo.com.
*
* @operationId express.pingexpress
* @tag Express
* @public
*/
export const GetPingExpress = httpRoute({
path: '/api/v[12]/pingexpress',
export const GetV2PingExpress = httpRoute({
path: '/api/v2/pingexpress',
* Ping BitGo Express
*
* Ping BitGo Express to ensure that it's still running. Unlike [Ping](/reference/expressping), this endpoint doesn't connect to bitgo.com.
*
* @operationId express.pingexpress
* @tag Express
* @public
*/
export const GetV2PingExpress = httpRoute({
path: '/api/v2/pingexpress',

I'm still not sure how does this endpoint differs from /api/v2/ping that we currently instruct clients to use. How does it tell if Express is running?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/api/v2/ping checks if both Express and BitGo servers are reachable — if BitGo is down, it fails even though Express is fine.

/api/v2/pingexpress only checks if Express itself is running — it never contacts BitGo, so it always returns 200 as long as the Express process is alive.

So when pingexpress returns 200 { "status": "express server is ok!" }, that itself is the proof — the fact that the request was received and responded to means Express is alive and handling requests.

method: 'GET',
request: httpRequest({}),
response: {
200: t.type({ status: t.string }),
404: BitgoExpressError,
},
});
67 changes: 67 additions & 0 deletions modules/express/test/unit/typedRoutes/pingExpress.ts
Original file line number Diff line number Diff line change
@@ -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);
});
});
});
Loading