Skip to content

Commit 9067d6a

Browse files
committed
Respond with JSON for error page or directory listing if accepted
1 parent 9865a82 commit 9067d6a

File tree

1 file changed

+40
-10
lines changed

1 file changed

+40
-10
lines changed

src/index.js

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -267,9 +267,10 @@ const canBeListed = (excluded, file) => {
267267
return whether;
268268
};
269269

270-
const renderDirectory = async (current, relativePath, absolutePath, handlers, config) => {
270+
const renderDirectory = async (current, acceptsJSON, handlers, config, paths) => {
271271
const {directoryListing, trailingSlash, unlisted = []} = config;
272272
const slashSuffix = typeof trailingSlash === 'boolean' ? (trailingSlash ? '/' : '') : '/';
273+
const {relativePath, absolutePath} = paths;
273274

274275
const excluded = [
275276
'.DS_Store',
@@ -296,7 +297,10 @@ const renderDirectory = async (current, relativePath, absolutePath, handlers, co
296297
details.base += slashSuffix;
297298
details.relative += slashSuffix;
298299

299-
details.isDirectory = true;
300+
// This is not camelcase, as we might be sending
301+
// the data away as JSON later, which shouldn't contain
302+
// any camelcased keys.
303+
details['is-directory'] = true;
300304
} else {
301305
details.ext = details.ext.split('.')[1] || 'txt';
302306

@@ -321,8 +325,8 @@ const renderDirectory = async (current, relativePath, absolutePath, handlers, co
321325

322326
// Sort to list directories first, then sort alphabetically
323327
files = files.sort((a, b) => {
324-
const aIsDir = a.isDirectory;
325-
const bIsDir = b.isDirectory;
328+
const aIsDir = a['is-directory'];
329+
const bIsDir = b['is-directory'];
326330

327331
if (aIsDir && !bIsDir) {
328332
return -1;
@@ -355,7 +359,7 @@ const renderDirectory = async (current, relativePath, absolutePath, handlers, co
355359
});
356360
}
357361

358-
const paths = [];
362+
const subPaths = [];
359363

360364
for (let index = 0; index < pathParts.length; index++) {
361365
const parents = [];
@@ -370,17 +374,23 @@ const renderDirectory = async (current, relativePath, absolutePath, handlers, co
370374

371375
parents.shift();
372376

373-
paths.push({
377+
subPaths.push({
374378
name: pathParts[index] + (isLast ? slashSuffix : '/'),
375379
url: index === 0 ? '' : parents.join('/') + slashSuffix
376380
});
377381
}
378382

379-
return template({
383+
const spec = {
380384
files,
381385
directory,
382-
paths
383-
});
386+
paths: subPaths
387+
};
388+
389+
if (acceptsJSON) {
390+
return JSON.stringify(spec);
391+
}
392+
393+
return template(spec);
384394
};
385395

386396
module.exports = async (request, response, config = {}, methods = {}) => {
@@ -433,11 +443,20 @@ module.exports = async (request, response, config = {}, methods = {}) => {
433443
}
434444
}
435445

446+
const acceptsJSON = request.headers.accept.includes('application/json');
447+
448+
if (((stats && stats.isDirectory()) || !stats) && acceptsJSON) {
449+
response.setHeader('Content-Type', 'application/json');
450+
}
451+
436452
if (stats && stats.isDirectory()) {
437453
let directory = null;
438454

439455
try {
440-
directory = await renderDirectory(current, relativePath, absolutePath, handlers, config);
456+
directory = await renderDirectory(current, acceptsJSON, handlers, config, {
457+
relativePath,
458+
absolutePath
459+
});
441460
} catch (err) {
442461
response.statusCode = 500;
443462
response.end(err.message);
@@ -460,6 +479,17 @@ module.exports = async (request, response, config = {}, methods = {}) => {
460479
if (!stats) {
461480
response.statusCode = 404;
462481

482+
if (acceptsJSON) {
483+
response.end(JSON.stringify({
484+
error: {
485+
code: 'not_found',
486+
message: 'Not Found'
487+
}
488+
}));
489+
490+
return;
491+
}
492+
463493
const errorPage = '404.html';
464494
const errorPageFull = path.join(current, errorPage);
465495

0 commit comments

Comments
 (0)