diff --git a/app.js b/app.js index ac3b1683..ff9e2877 100644 --- a/app.js +++ b/app.js @@ -6,6 +6,7 @@ const loadConfig = require('./lib/load-config') const { preflightCheck } = require('./lib/preflight_check') const { loadNyplCoreData } = require('./lib/load_nypl_core') const handleError = require('./lib/handle-error') +const { NotFoundError } = require('./lib/errors') const swaggerDocs = require('./swagger.v1.1.x.json') @@ -60,6 +61,10 @@ app.init = async () => { res.send(swaggerDocs) }) + app.use((req, res, next) => { + next(new NotFoundError(`Route ${req.originalUrl} not found`)) + }) + app.use((err, req, res, next) => { handleError(err, req, res, next, app.logger) }) diff --git a/lib/jsonld_serializers.js b/lib/jsonld_serializers.js index 79e0d154..5ed90a0e 100644 --- a/lib/jsonld_serializers.js +++ b/lib/jsonld_serializers.js @@ -398,7 +398,7 @@ class ItemResourceSerializer extends JsonLdItemSerializer { // Ensure identifiers array exists: item.identifier = item.identifier || [] const nyplSourceMapper = await NyplSourceMapper.instance() - const { id, nyplSource, type } = nyplSourceMapper.splitIdentifier(item.uri) + const { id, nyplSource, type } = nyplSourceMapper.splitIdentifier(item.uri) ?? {} if (type === 'item') { // Build prefix nyplSource as camel case const sourceIdentifierPrefix = ItemResourceSerializer.sourceIdentifierPrefixByNyplSource(nyplSource) @@ -485,7 +485,7 @@ class AggregationsSerializer extends JsonLdListSerializer { if ((typeof options) === 'undefined') options = {} const items = await Promise.all( - Object.entries(resp.aggregations) + Object.entries(resp.aggregations || {}) // Add id property to body of aggregation: .map(([id, agg]) => Object.assign({ id }, agg)) .map((agg) => AggregationSerializer.serialize(agg, options)) diff --git a/lib/resources.js b/lib/resources.js index e95de659..57532f96 100644 --- a/lib/resources.js +++ b/lib/resources.js @@ -114,7 +114,7 @@ module.exports = function (app, _private = null) { // Validate uri: const nyplSourceMapper = await NyplSourceMapper.instance() - const { id, nyplSource } = nyplSourceMapper.splitIdentifier(params.uri) + const { id, nyplSource } = nyplSourceMapper.splitIdentifier(params.uri) ?? {} if (!id || !nyplSource) { throw new errors.InvalidParameterError(`Invalid bnum: ${params.uri}`) } @@ -211,9 +211,14 @@ module.exports = function (app, _private = null) { app.resources.annotatedMarc = async function (params, opts) { // Convert discovery id to nyplSource and un-prefixed id: const nyplSourceMapper = await NyplSourceMapper.instance() - const { id, nyplSource } = nyplSourceMapper.splitIdentifier(params.uri) + const { id, nyplSource } = nyplSourceMapper.splitIdentifier(params.uri) ?? {} + + if (!id || !nyplSource) { + throw new errors.InvalidParameterError(`Invalid bnum: ${params.uri}`) + } app.logger.debug('Resources#annotatedMarc', { id, nyplSource }) + return makeNyplDataApiClient().get(`bibs/${nyplSource}/${id}`) .then((resp) => { // need to check that the query actually found an entry diff --git a/test/jsonld-serializers.test.js b/test/jsonld-serializers.test.js index 10c97848..10526662 100644 --- a/test/jsonld-serializers.test.js +++ b/test/jsonld-serializers.test.js @@ -3,9 +3,12 @@ const { expect } = require('chai') const { AggregationsSerializer, ItemResultsSerializer, + ItemResourceSerializer, ResourceSerializer } = require('../lib/jsonld_serializers') +const NyplSourceMapper = require('research-catalog-indexer/lib/utils/nypl-source-mapper') + describe('JSONLD Serializers', () => { describe('ResourceSerializer', () => { it('enables hasItemDates when numItemsTotal is above thresshold', async () => { @@ -172,5 +175,22 @@ describe('JSONLD Serializers', () => { .filter((val) => !val.label) expect(bucketsWithoutLabels).to.have.lengthOf(0) }) + + it('defaults to empty aggregations if missing', async () => { + const serialized = await AggregationsSerializer.serialize({ hits: { total: 0 } }) + expect(serialized.itemListElement).to.deep.equal([]) + expect(serialized.totalResults).to.equal(0) + }) + }) + + describe('ItemResourceSerializer', async () => { + describe('addSourceIdentifier', async () => { + it('makes no change if item uri has unexpected format', async () => { + await NyplSourceMapper.loadInstance({}) + const fakeItem = { uri: '1234' } + await ItemResourceSerializer.addSourceIdentifier(fakeItem) + expect(fakeItem).to.deep.equal({ uri: '1234', identifier: [] }) + }) + }) }) }) diff --git a/test/resources.test.js b/test/resources.test.js index 7ae45032..056a2926 100644 --- a/test/resources.test.js +++ b/test/resources.test.js @@ -410,6 +410,13 @@ describe('Resources query', function () { expect(data.bib.id).to.eq('11055155') }) }) + + it('Throws InvalidParameterError for unexpected uri format', async () => { + return app.resources.annotatedMarc({ uri: '1234' }) + .catch((e) => { + expect(e.message).to.equal('Invalid bnum: 1234') + }) + }) }) describe('findByUri 4xx', () => { @@ -604,6 +611,24 @@ describe('Resources query', function () { }) }) + describe('findByUri with unexpected uri format', async () => { + before(() => { + fixtures.enableEsFixtures() + }) + + after(() => { + fixtures.disableEsFixtures() + }) + + it('throws an InvalidParameterError', () => { + return app.resources.findByUri({ uri: '1234' }) + .catch((e) => { + console.log('message: ', e.message) + expect(e.message).to.equal('Invalid bnum: 1234') + }) + }) + }) + describe('esRangeValue', () => { it('should handle a range with two values', () => { expect(resourcesPrivMethods.esRangeValue([123, 456])).to.deep.equal({