Fix entries API POST response format and empty array handling

Fixes two bugs in the entries API that caused test failures:

1. POST endpoints now return JSON arrays consistently
   - Created format_post_response() middleware for POST requests
   - Replaces format_entries() which is designed for GET with content negotiation
   - Previously, POST requests without Accept header defaulted to text/plain handler
   - This caused responses to fail or return empty objects instead of JSON arrays
   - Now matches behavior of treatments and devicestatus APIs

2. Fixed callback never being called for empty array posts
   - Added empty array check in lib/server/entries.js create() function
   - Previously, empty array caused forEach loop to never execute
   - Completion callback was inside forEach, so never triggered for empty input
   - This caused 15 second timeouts on POST requests with empty arrays

All 26 tests in api.shape-handling.test.js now pass.

Files changed:
- lib/api/entries/index.js: Added format_post_response, updated POST routes
- lib/server/entries.js: Added empty array handling in create()
This commit is contained in:
Ben West
2026-01-19 13:14:21 -08:00
parent 2268e50d0e
commit 636ef4091b
2 changed files with 23 additions and 2 deletions
+18 -2
View File
@@ -252,6 +252,22 @@ function configure (app, wares, ctx, env) {
});
}
/**
* @method format_post_response
* Simple middleware to format POST response as JSON array
* Unlike format_entries, this doesn't support content negotiation
* and always returns JSON, which is appropriate for POST responses
*/
function format_post_response (req, res) {
// If there's been some error, report that
if (res.entries_err) {
return res.sendJSONStatus(res, consts.HTTP_INTERNAL_ERROR, 'Mongo Error', res.entries_err);
}
// Always return JSON array for POST requests
res.json(res.entries || []);
}
/**
* @method insert_entries
* middleware to process "uploads" of sgv data
@@ -767,7 +783,7 @@ function configure (app, wares, ctx, env) {
// setting this flag tells insert_entries to not actually store the results
req.persist_entries = false;
next();
}, insert_entries, wares.obscure_device, format_entries);
}, insert_entries, wares.obscure_device, format_post_response);
// Protect endpoints with authenticated api.
if (app.enabled('api')) {
@@ -782,7 +798,7 @@ function configure (app, wares, ctx, env) {
// setting this flag tells insert_entries to store the results
req.persist_entries = true;
next();
}, insert_entries, wares.obscure_device, format_entries);
}, insert_entries, wares.obscure_device, format_post_response);
/**
* @module delete#/entries/:spec
+5
View File
@@ -95,6 +95,11 @@ function storage (env, ctx) {
, numDocs = docs.length
, totalCreated = 0;
// Handle empty array case - call callback immediately
if (numDocs === 0) {
return fn(null, docs);
}
docs.forEach(function(doc) {
// Normalize dates to be in UTC, store offset in utcOffset