Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PI-1991: Handle 500s from Arns and give error message #29

Merged
merged 3 commits into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
18 changes: 18 additions & 0 deletions integration_tests/e2e/overview.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,22 @@ context('Overview', () => {
.should('contain.text', 'Previous concerns about coping in a hostel setting')
page.getRowData('risk', 'riskFlags', 'Value').should('contain.text', 'Risk to Known Adult')
})
it('Risk information is not provided due to 500 from ARNS', () => {
cy.visit('/case/X000002')
const page = Page.verifyOnPage(OverviewPage)
page.headerCrn().should('contain.text', 'X000002')
page.headerName().should('contain.text', 'Caroline Wolff')
page.pageHeading().should('contain.text', 'Overview')
page.getTab('overview').should('contain.text', 'Overview')
page.getTab('personalDetails').should('contain.text', 'Personal details')
page.getTab('risk').should('contain.text', 'Risk')
page.getTab('sentence').should('contain.text', 'Sentence')
page.getTab('activityLog').should('contain.text', 'Activity log')
page.getTab('compliance').should('contain.text', 'Compliance')
page.getCardHeader('schedule').should('contain.text', 'Schedule')
cy.get(`[data-qa=riskErrors]`).should(
'contain.text',
'OAsys is experiencing technical difficulties. It has not been possible to provide the Risk information held in OASys',
)
})
})
17 changes: 13 additions & 4 deletions server/data/arnsApiClient.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import config from '../config'
// eslint-disable-next-line import/no-cycle
import RestClient from './restClient'
import { ErrorSummary, ErrorSummaryItem } from './model/common'

export default class ArnsApiClient extends RestClient {
constructor(token: string) {
super('Assess Risks and Needs API', config.apis.arnsApi, token)
}

async getRisks(crn: string): Promise<RiskSummary | null> {
return this.get({ path: `/risks/crn/${crn}`, handle404: true })
async getRisks(crn: string): Promise<RiskSummary | ErrorSummary | null> {
return this.get({
path: `/risks/crn/${crn}`,
handle404: true,
handle500: true,
errorMessageFor500:
'OAsys is experiencing technical difficulties. It has not been possible to provide the Risk information held in OASys',
})
}
}

Expand All @@ -34,8 +42,9 @@ export interface RiskToSelf {
}

export interface RiskSummary {
riskToSelf: RiskToSelf
summary: {
errors?: ErrorSummaryItem[]
riskToSelf?: RiskToSelf
summary?: {
whoIsAtRisk?: string | null
natureOfRisk?: string | null
riskImminence?: string | null
Expand Down
40 changes: 20 additions & 20 deletions server/data/masApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,59 +9,59 @@ import {
PersonalDetails,
ProvisionOverview,
} from './model/personalDetails'
import { AddressOverview, PersonSummary } from './model/common'
import { AddressOverview, ErrorSummary, PersonSummary } from './model/common'
import { SentenceDetails } from './model/sentenceDetails'

export default class MasApiClient extends RestClient {
constructor(token: string) {
super('Manage a Supervision API', config.apis.masApi, token)
}

async getOverview(crn: string): Promise<Overview | null> {
return this.get({ path: `/overview/${crn}`, handle404: true })
async getOverview(crn: string): Promise<Overview | ErrorSummary | null> {
return this.get({ path: `/overview/${crn}`, handle404: false })
}

async getSentenceDetails(crn: string): Promise<SentenceDetails | null> {
return this.get({ path: `/sentence/${crn}`, handle404: true })
async getSentenceDetails(crn: string): Promise<SentenceDetails | ErrorSummary | null> {
return this.get({ path: `/sentence/${crn}`, handle404: false })
}

async getPersonalDetails(crn: string): Promise<PersonalDetails | null> {
return this.get({ path: `/personal-details/${crn}`, handle404: true })
async getPersonalDetails(crn: string): Promise<PersonalDetails | ErrorSummary | null> {
return this.get({ path: `/personal-details/${crn}`, handle404: false })
}

async getPersonalContact(crn: string, id: string): Promise<PersonalContact | null> {
return this.get({ path: `/personal-details/${crn}/personal-contact/${id}`, handle404: true })
async getPersonalContact(crn: string, id: string): Promise<PersonalContact | ErrorSummary | null> {
return this.get({ path: `/personal-details/${crn}/personal-contact/${id}`, handle404: false })
}

async getPersonalAddresses(crn: string): Promise<AddressOverview | null> {
return this.get({ path: `/personal-details/${crn}/addresses`, handle404: true })
async getPersonalAddresses(crn: string): Promise<AddressOverview | ErrorSummary | null> {
return this.get({ path: `/personal-details/${crn}/addresses`, handle404: false })
}

async getPersonSummary(crn: string): Promise<PersonSummary | null> {
return this.get({ path: `/personal-details/${crn}/summary`, handle404: true })
async getPersonSummary(crn: string): Promise<PersonSummary | ErrorSummary | null> {
return this.get({ path: `/personal-details/${crn}/summary`, handle404: false })
}

async getPersonDisabilities(crn: string): Promise<DisabilityOverview | null> {
return this.get({ path: `/personal-details/${crn}/disabilities`, handle404: true })
return this.get({ path: `/personal-details/${crn}/disabilities`, handle404: false })
}

async getPersonAdjustments(crn: string): Promise<ProvisionOverview | null> {
return this.get({ path: `/personal-details/${crn}/provisions`, handle404: true })
return this.get({ path: `/personal-details/${crn}/provisions`, handle404: false })
}

async getPersonCircumstances(crn: string): Promise<CircumstanceOverview | null> {
return this.get({ path: `/personal-details/${crn}/circumstances`, handle404: true })
return this.get({ path: `/personal-details/${crn}/circumstances`, handle404: false })
}

async downloadDocument(crn: string, documentId: string): Promise<Response> {
return this.get({ path: `/personal-details/${crn}/document/${documentId}`, raw: true, responseType: 'arrayBuffer' })
}

async getPersonSchedule(crn: string, type: string): Promise<Schedule | null> {
return this.get({ path: `/schedule/${crn}/${type}`, handle404: true })
async getPersonSchedule(crn: string, type: string): Promise<Schedule> {
return this.get({ path: `/schedule/${crn}/${type}`, handle404: false })
}

async getPersonAppointment(crn: string, appointmentId: string): Promise<PersonAppointment | null> {
return this.get({ path: `/schedule/${crn}/appointment/${appointmentId}`, handle404: true })
async getPersonAppointment(crn: string, appointmentId: string): Promise<PersonAppointment | ErrorSummary | null> {
return this.get({ path: `/schedule/${crn}/appointment/${appointmentId}`, handle404: false })
}
}
8 changes: 8 additions & 0 deletions server/data/model/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,11 @@ export interface PersonSummary {
pnc?: string
dateOfBirth: string
}

export interface ErrorSummary {
errors: ErrorSummaryItem[]
}
export interface ErrorSummaryItem {
text: string
href?: string
}
14 changes: 13 additions & 1 deletion server/data/restClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import Agent, { HttpsAgent } from 'agentkeepalive'
import superagent from 'superagent'

import logger from '../../logger'
import type { UnsanitisedError } from '../sanitisedError'
import sanitiseError from '../sanitisedError'
import type { ApiConfig } from '../config'
import type { UnsanitisedError } from '../sanitisedError'
import { restClientMetricsMiddleware } from './restClientMetricsMiddleware'
import { ErrorSummaryItem } from './model/common'

interface Request {
path: string
Expand All @@ -16,6 +17,8 @@ interface Request {
responseType?: string
raw?: boolean
handle404?: boolean
handle500?: boolean
errorMessageFor500?: string
}

interface RequestWithBody extends Request {
Expand Down Expand Up @@ -55,6 +58,8 @@ export default class RestClient {
responseType = '',
raw = false,
handle404 = false,
handle500 = false,
errorMessageFor500 = '',
}: Request): Promise<Response> {
logger.info(`${this.name} GET: ${path}`)
try {
Expand All @@ -74,6 +79,13 @@ export default class RestClient {

return raw ? result : result.body
} catch (error) {
if (handle500 && error.response?.status === 500) {
const warnings: ErrorSummaryItem[] = []
warnings.push({ text: errorMessageFor500 })
error.response.errors = warnings
logger.info('Handling 500 ')
return error.response
}
if (handle404 && error.response?.status === 404) return null
const sanitisedError = sanitiseError(error)
logger.warn({ ...sanitisedError }, `Error calling ${this.name}, path: '${path}', verb: 'GET'`)
Expand Down
2 changes: 1 addition & 1 deletion server/routes/case.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { type RequestHandler, Router } from 'express'
// eslint-disable-next-line import/no-extraneous-dependencies
import { auditService } from '@ministryofjustice/hmpps-audit-client'
import { v4 } from 'uuid'
import asyncMiddleware from '../middleware/asyncMiddleware'
Expand All @@ -26,6 +25,7 @@ export default function caseRoutes(router: Router, { hmppsAuthClient }: Services
})

const [overview, risks] = await Promise.all([masClient.getOverview(crn), arnsClient.getRisks(crn)])

res.render('pages/overview', {
overview,
risks,
Expand Down
4 changes: 2 additions & 2 deletions server/views/partials/case.njk
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
{% if currentSectionName %}
<h1 class="govuk-heading-l govuk-!-margin-bottom-7" data-qa="pageHeading">{{ currentSectionName }}</h1>
{% endif %}
{% if warnings.length %}
{{ govukErrorSummary({ titleText: "There is a problem", errorList: warnings }) }}
{% if risks.errors.length > 0 %}
<span data-qa="riskErrors">{{ govukErrorSummary({ titleText: "There is a problem", errorList: risks.errors }) }}</span>
{% endif %}
{% block pageContent %}{% endblock %}
{% endblock %}
Expand Down
Loading