Skip to content

Commit

Permalink
Count errors to give 200, 207, or 500 HTTP status (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
jessepeterson authored May 7, 2022
1 parent 4db121a commit 1ce7077
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 25 deletions.
42 changes: 31 additions & 11 deletions docs/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ paths:
- basicAuth: []
responses:
'200':
description: API response. Can include errors in response object.
content:
application/json:
schema:
$ref: '#/components/schemas/APIResult'
$ref: '#/components/responses/APIResultOK'
'207':
$ref: '#/components/responses/APIResultSomeFailed'
'500':
$ref: '#/components/responses/APIResultAllFailed'
'401':
$ref: '#/components/responses/UnauthorizedError'
parameters:
Expand Down Expand Up @@ -89,17 +89,19 @@ paths:
</plist>
responses:
'200':
description: API response. Can include errors in response object.
content:
application/json:
schema:
$ref: '#/components/schemas/APIResult'
$ref: '#/components/responses/APIResultOK'
'207':
$ref: '#/components/responses/APIResultSomeFailed'
'400':
description: Error decoding MDM command plist.
'401':
$ref: '#/components/responses/UnauthorizedError'
'500':
description: Error reading HTTP body from request
description: One of two modes. One mode is an error reading HTTP body from request (which will return no content nor content-type). Otherwise all enqueue requests failed. Returns JSON API response object including errors.
content:
application/json:
schema:
$ref: '#/components/schemas/APIResult'
parameters:
- $ref: '#/components/parameters/idParam'
- in: query
Expand Down Expand Up @@ -148,6 +150,24 @@ components:
WWW-Authenticate:
schema:
type: string
APIResultOK:
description: All requests succeeded. Returns JSON API response object.
content:
application/json:
schema:
$ref: '#/components/schemas/APIResult'
APIResultSomeFailed:
description: Some requests succeeded and some failed. Returns JSON API response object including errors.
content:
application/json:
schema:
$ref: '#/components/schemas/APIResult'
APIResultAllFailed:
description: All requests failed. Returns JSON API response object including errors.
content:
application/json:
schema:
$ref: '#/components/schemas/APIResult'
schemas:
APIResult:
type: object
Expand Down
52 changes: 38 additions & 14 deletions http/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,19 @@ func PushHandler(pusher push.Pusher, logger log.Logger) http.HandlerFunc {
} else {
logger.Debug(logs...)
}
// generate response codes depending on if everything succeeded, failed, or parially succedded
header := http.StatusInternalServerError
if (errCt > 0 || err != nil) && ct > 0 {
header = http.StatusMultiStatus
} else if (errCt == 0 && err == nil) && ct >= 1 {
header = http.StatusOK
}
json, err := json.MarshalIndent(output, "", "\t")
if err != nil {
logger.Info("msg", "marshal json", "err", err)
}
w.Header().Set("Content-type", "application/json")
w.WriteHeader(header)
_, err = w.Write(json)
if err != nil {
logger.Info("msg", "writing body", "err", err)
Expand Down Expand Up @@ -159,11 +167,17 @@ func RawCommandEnqueueHandler(enqueuer storage.CommandEnqueuer, pusher push.Push
"msg", "enqueue",
}
idErrs, err := enqueuer.EnqueueCommand(ctx, ids, command)
ct := len(ids) - len(idErrs)
if err != nil {
logs = append(logs, "err", err)
output.CommandError = err.Error()
if len(idErrs) == 0 {
// we assume if there were no ID-specific errors but
// there was a general error then all IDs failed
ct = 0
}
}
logs = append(logs, "count", len(ids)-len(idErrs))
logs = append(logs, "count", ct)
if len(idErrs) > 0 {
logs = append(logs, "errs", len(idErrs))
}
Expand All @@ -172,16 +186,6 @@ func RawCommandEnqueueHandler(enqueuer storage.CommandEnqueuer, pusher push.Push
} else {
logger.Debug(logs...)
}
pushResp := make(map[string]*push.Response)
if !nopush {
pushResp, err = pusher.Push(ctx, ids)
if err != nil {
logger.Info("msg", "push", "err", err)
output.PushError = err.Error()
}
} else {
err = nil
}
// loop through our command errors, if any, and add to output
for id, err := range idErrs {
if err != nil {
Expand All @@ -190,6 +194,18 @@ func RawCommandEnqueueHandler(enqueuer storage.CommandEnqueuer, pusher push.Push
}
}
}
// optionally send pushes
pushResp := make(map[string]*push.Response)
var pushErr error
if !nopush {
pushResp, pushErr = pusher.Push(ctx, ids)
if err != nil {
logger.Info("msg", "push", "err", err)
output.PushError = err.Error()
}
} else {
pushErr = nil
}
// loop through our push errors, if any, and add to output
var pushCt, pushErrCt int
for id, resp := range pushResp {
Expand All @@ -211,22 +227,30 @@ func RawCommandEnqueueHandler(enqueuer storage.CommandEnqueuer, pusher push.Push
"msg", "push",
"count", pushCt,
}
if err != nil {
logs = append(logs, "err", err)
if pushErr != nil {
logs = append(logs, "err", pushErr)
}
if pushErrCt > 0 {
logs = append(logs, "errs", pushErrCt)
}
if err != nil || pushErrCt > 0 {
if pushErr != nil || pushErrCt > 0 {
logger.Info(logs...)
} else {
logger.Debug(logs...)
}
// generate response codes depending on if everything succeeded, failed, or parially succedded
header := http.StatusInternalServerError
if (len(idErrs) > 0 || err != nil || (!nopush && (pushErrCt > 0 || pushErr != nil))) && (ct > 0 || (!nopush && (pushCt > 0))) {
header = http.StatusMultiStatus
} else if (len(idErrs) == 0 && err == nil && (nopush || (pushErrCt == 0 && pushErr == nil))) && (ct >= 1 && (nopush || (pushCt >= 1))) {
header = http.StatusOK
}
json, err := json.MarshalIndent(output, "", "\t")
if err != nil {
logger.Info("msg", "marshal json", "err", err)
}
w.Header().Set("Content-type", "application/json")
w.WriteHeader(header)
_, err = w.Write(json)
if err != nil {
logger.Info("msg", "writing body", "err", err)
Expand Down

0 comments on commit 1ce7077

Please sign in to comment.