Skip to content

Commit

Permalink
Adds an error catch for null responses
Browse files Browse the repository at this point in the history
  • Loading branch information
lomky authored Oct 13, 2021
2 parents 62bfe42 + f3faf46 commit 97c30f3
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 8 deletions.
33 changes: 26 additions & 7 deletions tests/utils/queryApiGateway.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,18 +189,34 @@ describe('Querying the API Gateway', () => {
restore()
})

it('handles null unique number response mismatch', async () => {
it('handles nullish with unique number response', async () => {
// Mock process.env
const restore = mockEnv({
API_URL: goodUrl,
})

const mismatchedResponse = { hasPendingWeeks: false, uniqueNumber: null }
const mismatchedResponse = {
claimDetails: {
programType: '',
benefitYearStartDate: null,
benefitYearEndDate: null,
claimBalance: null,
weeklyBenefitAmount: null,
lastPaymentIssued: null,
lastPaymentAmount: null,
monetaryStatus: '',
},
uniqueNumber: '12345',
hasCertificationWeeksAvailable: false,
hasPendingWeeks: false,
pendingDetermination: [],
}

/* eslint-disable @typescript-eslint/no-unsafe-call */
fetch.mockResolvedValue(new Response(JSON.stringify(mismatchedResponse)))
/* eslint-enable @typescript-eslint/no-unsafe-call */
await expect(queryApiGateway(goodRequest, goodUniqueNumber)).rejects.toThrow(
'Mismatched API response and Header unique number (null and 12345)',
'API responded with a null response (queried with 12345, responded with 12345)',
)

expect(fetch).toHaveBeenCalledTimes(1)
Expand All @@ -210,15 +226,18 @@ describe('Querying the API Gateway', () => {
restore()
})

it('handles null unique number request mismatch', async () => {
it('handles null unique number response', async () => {
// Mock process.env
const restore = mockEnv({
API_URL: goodUrl,
})

const mismatchedUniqueNumber = null
await expect(queryApiGateway(goodRequest, mismatchedUniqueNumber)).rejects.toThrow(
'Mismatched API response and Header unique number (12345 and null)',
const mismatchedResponse = { hasPendingWeeks: false, uniqueNumber: null }
/* eslint-disable @typescript-eslint/no-unsafe-call */
fetch.mockResolvedValue(new Response(JSON.stringify(mismatchedResponse)))
/* eslint-enable @typescript-eslint/no-unsafe-call */
await expect(queryApiGateway(goodRequest, goodUniqueNumber)).rejects.toThrow(
'API responded with a null response (queried with 12345, responded with null)',
)

expect(fetch).toHaveBeenCalledTimes(1)
Expand Down
56 changes: 55 additions & 1 deletion utils/queryApiGateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import path from 'path'
import fs from 'fs'
import https from 'https'
import assert from 'assert'
import { IncomingMessage } from 'http'
import { Claim } from '../types/common'
import { Logger } from './logger'
Expand Down Expand Up @@ -112,6 +113,46 @@ export function getUniqueNumber(req: IncomingMessage): string {
return req.headers[idHeaderName.toLowerCase()] as string
}

/**
* Check if the API responded with a null response body
*
* We do not expect any of these in production, in theory.
*/
export function reponseIsNullish(apiBody: Claim): boolean {
// This is a trick to make a deep-copy of a JSON object
const response: Claim = JSON.parse(JSON.stringify(apiBody)) as Claim
const responseUniqueNumber = response.uniqueNumber
delete response.uniqueNumber

// This is an unexpected null response we are seeing in production
// where the API responses with a matching UniqueNumber we asked for,
// but no claim data
const nullishResponse = {
claimDetails: {
programType: '',
benefitYearStartDate: null,
benefitYearEndDate: null,
claimBalance: null,
weeklyBenefitAmount: null,
lastPaymentIssued: null,
lastPaymentAmount: null,
monetaryStatus: '',
},
hasCertificationWeeksAvailable: false,
hasPendingWeeks: false,
pendingDetermination: [],
}

try {
assert.notStrictEqual(responseUniqueNumber, null, 'Response is null')
assert.notDeepStrictEqual(response, nullishResponse, 'Response is null')
} catch {
return true
}

return false
}

/**
* Returns results from API Gateway
*/
Expand Down Expand Up @@ -180,7 +221,8 @@ export default async function queryApiGateway(req: IncomingMessage, uniqueNumber
throw error
}

if (apiData?.uniqueNumber !== uniqueNumber) {
// Yell real loud if the API returns a different, non-null uniqueNumber
if (apiData?.uniqueNumber && apiData?.uniqueNumber !== uniqueNumber) {
const mismatchError = new Error(
`Mismatched API response and Header unique number (${apiData.uniqueNumber || 'null'} and ${uniqueNumber})`,
)
Expand All @@ -189,5 +231,17 @@ export default async function queryApiGateway(req: IncomingMessage, uniqueNumber
throw mismatchError
}

// Yell if the API returns a null or null-ish response
if (reponseIsNullish(apiData)) {
const nullResponseError = new Error(
`API responded with a null response (queried with ${uniqueNumber}, responded with ${
apiData.uniqueNumber || 'null'
})`,
)
const logger: Logger = Logger.getInstance()
logger.log('error', nullResponseError, 'Unexpected API gateway response')
throw nullResponseError
}

return apiData
}

0 comments on commit 97c30f3

Please sign in to comment.