Skip to content

Commit 3583ab2

Browse files
committed
Simplify error handling in imms api
Jira-Issue: MAV-1477
1 parent bbe2491 commit 3583ab2

2 files changed

Lines changed: 66 additions & 121 deletions

File tree

app/lib/nhs/immunisations_api.rb

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,35 @@
11
# frozen_string_literal: true
22

33
module NHS::ImmunisationsAPI
4-
class PatientNotFound < StandardError
5-
end
6-
74
class << self
85
def record_immunisation(vaccination_record)
96
NHS::API.connection.post(
107
"/immunisation-fhir-api/FHIR/R4/Immunization",
118
vaccination_record.fhir_record.to_json,
129
"Content-Type" => "application/fhir+json"
1310
)
14-
rescue Faraday::Error => e
15-
info = extract_error_info(e.response[:body])
16-
Rails.logger.error(
17-
"Error recording vaccination record (#{vaccination_record.id}):" \
18-
" [#{info[:code]}] #{info[:diagnostics]}"
19-
)
20-
raise e
11+
rescue Faraday::ClientError => e
12+
if (diagnostics = extract_error_diagnostics(e&.response)).present?
13+
raise "Error syncing vaccination #{vaccination_record.id} record to" \
14+
" Immunisations API: #{diagnostics}"
15+
else
16+
raise
17+
end
2118
end
2219

23-
def extract_error_info(response_body)
24-
return { code: nil, diagnostics: "No response body" } unless response_body
25-
26-
response = JSON.parse(response_body, symbolize_names: true)
20+
private
2721

28-
if response.empty?
29-
{ code: nil, diagnostics: "No response body" }
30-
elsif response[:issue].blank?
31-
{ code: nil, diagnostics: "No issues in response" }
32-
elsif response[:issue].first[:severity] != "error"
33-
{ code: nil, diagnostics: "Issue is not an error" }
34-
else
35-
diagnostics = response[:issue].first[:diagnostics]
36-
if diagnostics.match?(/NHS Number: \d{10} is invalid.*/)
37-
diagnostics.replace("NHS Number is invalid or it doesn't exist")
38-
end
22+
def extract_error_diagnostics(response)
23+
return nil if response.nil? || response[:body].blank?
3924

40-
{ code: response[:issue].first[:code], diagnostics: diagnostics }
25+
begin
26+
JSON.parse(response[:body], symbolize_names: true).dig(
27+
:issue,
28+
0,
29+
:diagnostics
30+
)
31+
rescue JSON::ParserError
32+
nil
4133
end
4234
end
4335
end

spec/lib/nhs/immunisations_api_spec.rb

Lines changed: 48 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -75,113 +75,66 @@
7575
end
7676

7777
context "an error is returned by the api" do
78-
let(:response) do
79-
{ issue: [{ severity: "error", code:, diagnostics: }] }.to_json
80-
end
81-
82-
before do
83-
stub_request(
84-
:post,
85-
"https://sandbox.api.service.nhs.uk/immunisation-fhir-api/FHIR/R4/Immunization"
86-
).to_return(status: 400, body: response, headers: {})
87-
88-
allow(Rails.logger).to receive(:error).and_return(true)
89-
end
78+
context "4XX error" do
79+
let(:response) do
80+
{
81+
resourceType: "OperationOutcome",
82+
id: "bc2c3c82-4392-4314-9d6b-a7345f82d923",
83+
meta: {
84+
profile: [
85+
"https://simplifier.net/guide/UKCoreDevelopment2/ProfileUKCore-OperationOutcome"
86+
]
87+
},
88+
issue: [
89+
{
90+
severity: "error",
91+
code: "invalid",
92+
details: {
93+
coding: [
94+
{
95+
system: "https://fhir.nhs.uk/Codesystem/http-error-codes",
96+
code: "NOT-FOUND"
97+
}
98+
]
99+
},
100+
diagnostics: "Invalid patient ID"
101+
}
102+
]
103+
}.to_json
104+
end
90105

91-
context "generic error" do
92-
let(:code) { "invalid" }
93-
let(:diagnostics) { "Invalid patient ID" }
106+
before do
107+
stub_request(
108+
:post,
109+
"https://sandbox.api.service.nhs.uk/immunisation-fhir-api/FHIR/R4/Immunization"
110+
).to_return(status: 404, body: response, headers: {})
111+
end
94112

95-
it "raises an error with the correct message" do
96-
begin
113+
it "raises an error with the diagnostic message" do
114+
expect {
97115
described_class.record_immunisation(vaccination_record)
98-
rescue StandardError
99-
nil
100-
end
101-
102-
expect(Rails.logger).to have_received(:error).with(
103-
/\[invalid\] Invalid patient ID/
116+
}.to raise_error(
117+
StandardError,
118+
"Error syncing vaccination #{vaccination_record.id} record to" \
119+
" Immunisations API: Invalid patient ID"
104120
)
105121
end
106122
end
107123

108-
context "the error is invalid NHS number" do
109-
let(:code) { "exception" }
110-
let(:diagnostics) do
111-
"NHS Number: 1234567890 is invalid or it doesn't exist"
124+
context "generic error" do
125+
before do
126+
stub_request(
127+
:post,
128+
"https://sandbox.api.service.nhs.uk/immunisation-fhir-api/FHIR/R4/Immunization"
129+
).to_return(status: 500, body: nil, headers: {})
112130
end
113131

114-
it "raises an error with the correct message" do
115-
begin
132+
it "raises an error with the diagnostic message" do
133+
expect {
116134
described_class.record_immunisation(vaccination_record)
117-
rescue StandardError
118-
nil
119-
end
120-
121-
expect(Rails.logger).to have_received(:error).with(
122-
/\[exception\] NHS Number is invalid or it doesn't exist/
123-
)
135+
}.to raise_error(Faraday::Error)
124136
end
125137
end
126138
end
127139
end
128-
129-
describe "extract_error_info" do
130-
subject(:error_info) { described_class.extract_error_info(response) }
131-
132-
context "response body has an error" do
133-
let(:response) do
134-
{
135-
issue: [
136-
{
137-
severity: "error",
138-
code: "invalid",
139-
diagnostics: "Invalid patient ID"
140-
}
141-
]
142-
}.to_json
143-
end
144-
145-
its([:code]) { should eq "invalid" }
146-
its([:diagnostics]) { should eq "Invalid patient ID" }
147-
end
148-
149-
context "when the response body is empty" do
150-
let(:response) { nil }
151-
152-
its([:code]) { should be_nil }
153-
its([:diagnostics]) { should eq "No response body" }
154-
end
155-
156-
context "when the response body has no issue attribute" do
157-
let(:response) { "{}" }
158-
159-
its([:code]) { should be_nil }
160-
its([:diagnostics]) { should eq "No response body" }
161-
end
162-
163-
context "when the response body has no issues" do
164-
let(:response) { '{"issues": [] }' }
165-
166-
its([:code]) { should be_nil }
167-
its([:diagnostics]) { should eq "No issues in response" }
168-
end
169-
170-
context "the issue severity is not 'error'" do
171-
let(:response) do
172-
{
173-
issue: [
174-
{
175-
severity: "warning",
176-
code: "not-found",
177-
diagnostics: "Patient not found"
178-
}
179-
]
180-
}.to_json
181-
end
182-
183-
its([:code]) { should be_nil }
184-
its([:diagnostics]) { should eq "Issue is not an error" }
185-
end
186-
end
187140
end

0 commit comments

Comments
 (0)