Skip to content
This repository was archived by the owner on Jan 29, 2026. It is now read-only.

Commit f4a27db

Browse files
committed
Handle error responses correctly
1 parent 521a647 commit f4a27db

File tree

4 files changed

+75
-18
lines changed

4 files changed

+75
-18
lines changed

audit/client.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -209,12 +209,7 @@ func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
209209

210210
response := newResponse(resp)
211211

212-
err = CheckResponse(resp)
213-
if err != nil {
214-
// even though there was an error, we still return the response
215-
// in case the caller wants to inspect it further
216-
return response, err
217-
}
212+
doErr := CheckResponse(resp)
218213

219214
if v != nil {
220215
defer resp.Body.Close() // Only close if we plan to read it
@@ -223,16 +218,21 @@ func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
223218
} else {
224219
err = json.NewDecoder(resp.Body).Decode(v)
225220
}
221+
if err != nil {
222+
return response, err
223+
}
226224
}
227225

228-
return response, err
226+
return response, doErr
229227
}
230228

231229
// CheckResponse checks the API response for errors, and returns them if present.
232230
func CheckResponse(r *http.Response) error {
233231
switch r.StatusCode {
234232
case 200, 201, 202, 204, 304:
235233
return nil
234+
case 400:
235+
return ErrBadRequest
236236
}
237237
return ErrNonHttp20xResponse
238238
}

audit/create.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ import (
77
"net/http"
88

99
dstu2pb "github.com/google/fhir/go/proto/google/fhir/proto/dstu2/resources_go_proto"
10+
stu3pb "github.com/google/fhir/go/proto/google/fhir/proto/stu3/resources_go_proto"
1011
)
1112

12-
func (c *Client) CreateAuditEvent(event *dstu2pb.AuditEvent) (*dstu2pb.ContainedResource, *Response, error) {
13+
func (c *Client) CreateAuditEvent(event *dstu2pb.AuditEvent) (*stu3pb.ContainedResource, *Response, error) {
1314
eventJSON, err := c.ma.MarshalResource(event)
1415
if err != nil {
1516
return nil, nil, err
@@ -20,22 +21,24 @@ func (c *Client) CreateAuditEvent(event *dstu2pb.AuditEvent) (*dstu2pb.Contained
2021
}
2122
_ = c.httpSigner.SignRequest(req)
2223
var operationResponse bytes.Buffer
23-
resp, err := c.Do(req, &operationResponse)
24-
if (err != nil && err != io.EOF) || resp == nil {
25-
if resp == nil && err != nil {
26-
err = ErrEmptyResult
24+
resp, doErr := c.Do(req, &operationResponse)
25+
if (doErr != nil && !(doErr == io.EOF || doErr == ErrBadRequest)) || resp == nil {
26+
if resp == nil && doErr != nil {
27+
doErr = ErrEmptyResult
2728
}
28-
return nil, resp, err
29+
return nil, resp, doErr
2930
}
30-
// Success
31-
contained := &dstu2pb.ContainedResource{}
31+
contained := &stu3pb.ContainedResource{}
3232
if resp.StatusCode == http.StatusCreated {
3333
return contained, resp, nil
3434
}
3535
// OperationOutcome
3636
unmarshalled, err := c.um.Unmarshal(operationResponse.Bytes())
37-
if err == nil {
38-
contained = unmarshalled.(*dstu2pb.ContainedResource)
37+
if err != nil {
38+
return nil, resp, fmt.Errorf("c.um.Unmarshal: %w", err)
39+
}
40+
if unmarshalled != nil {
41+
contained = unmarshalled.(*stu3pb.ContainedResource)
3942
}
40-
return contained, resp, err
43+
return contained, resp, doErr
4144
}

audit/create_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,56 @@ func TestCreate(t *testing.T) {
127127
return
128128
}
129129
}
130+
131+
func TestBadRequest(t *testing.T) {
132+
operationOutcome := `{
133+
"issue": [
134+
{
135+
"severity": "error",
136+
"code": "invalid",
137+
"details": {
138+
"coding": [
139+
{
140+
"system": "https://www.hl7.org/fhir/valueset-operation-outcome.html",
141+
"code": "MSG_ERROR_PARSING"
142+
}
143+
],
144+
"text": "Not complaint with AuditEvent specification"
145+
},
146+
"diagnostics": "Not complaint with AuditEvent specification"
147+
}
148+
],
149+
"resourceType": "OperationOutcome"
150+
}`
151+
teardown := setup(t)
152+
defer teardown()
153+
154+
muxAudit.HandleFunc("/core/audit/AuditEvent", func(w http.ResponseWriter, r *http.Request) {
155+
w.Header().Set("Content-Type", "application/json")
156+
switch r.Method {
157+
case "POST":
158+
if !assert.Equal(t, audit.APIVersion, r.Header.Get("API-Version")) {
159+
w.WriteHeader(http.StatusPreconditionFailed)
160+
return
161+
}
162+
w.WriteHeader(http.StatusBadRequest)
163+
w.Write([]byte(operationOutcome))
164+
default:
165+
w.WriteHeader(http.StatusMethodNotAllowed)
166+
}
167+
})
168+
event := &dstu2pb.AuditEvent{
169+
Id: &dstu2dt.Id{Value: "someID"},
170+
}
171+
contained, resp, err := auditClient.CreateAuditEvent(event)
172+
if !assert.Equal(t, audit.ErrBadRequest, err) {
173+
return
174+
}
175+
if !assert.NotNil(t, resp) {
176+
return
177+
}
178+
if !assert.NotNil(t, contained) {
179+
return
180+
}
181+
182+
}

audit/errors.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ var (
1010
ErrEmptyResult = errors.New("empty result")
1111
ErrCouldNoReadResourceAfterCreate = errors.New("could not read resource after create")
1212
ErrNotImplementedYet = errors.New("not implemented yet")
13+
ErrBadRequest = errors.New("bad request")
1314
ErrNonHttp20xResponse = errors.New("non http 20x Audit response")
1415
)

0 commit comments

Comments
 (0)