diff --git a/src/storage/conversion/DynamicJsonToTemplateConverter.ts b/src/storage/conversion/DynamicJsonToTemplateConverter.ts index 975c34106..7fe90afbb 100644 --- a/src/storage/conversion/DynamicJsonToTemplateConverter.ts +++ b/src/storage/conversion/DynamicJsonToTemplateConverter.ts @@ -24,6 +24,8 @@ import type { RepresentationConverterArgs } from './RepresentationConverter'; * describing the content-type of that template. * * The output of the result depends on the content-type matched with the template. + * In case JSON is the most preferred output type, + * the input representation will be returned unless a JSON template is defined. */ export class DynamicJsonToTemplateConverter extends RepresentationConverter { private readonly templateEngine: TemplateEngine; @@ -51,6 +53,11 @@ export class DynamicJsonToTemplateConverter extends RepresentationConverter { const typeMap = this.constructTypeMap(identifier, representation); const type = this.findType(typeMap, preferences.type); + // No conversion needed if JSON is requested and there is no specific JSON template + if (type === APPLICATION_JSON && typeMap[APPLICATION_JSON].length === 0) { + return representation; + } + const json = JSON.parse(await readableToString(representation.data)); const rendered = await this.templateEngine.render(json, { templateFile: typeMap[type] }); @@ -69,6 +76,11 @@ export class DynamicJsonToTemplateConverter extends RepresentationConverter { .map((quad): Term => quad.object) .filter((term: Term): boolean => term.termType === 'NamedNode') as NamedNode[]; + // This handler should only cover cases where templates are defined + if (templates.length === 0) { + throw new NotImplementedHttpError('No templates found.'); + } + // Maps all content-types to their template const typeMap: Record = {}; for (const template of templates) { @@ -77,6 +89,12 @@ export class DynamicJsonToTemplateConverter extends RepresentationConverter { typeMap[type] = template.value; } } + + // Not using a template is always an option unless there is a specific JSON template + if (!typeMap[APPLICATION_JSON]) { + typeMap[APPLICATION_JSON] = ''; + } + return typeMap; } diff --git a/test/unit/storage/conversion/DynamicJsonToTemplateConverter.test.ts b/test/unit/storage/conversion/DynamicJsonToTemplateConverter.test.ts index e63ce6a9e..17e59f7a3 100644 --- a/test/unit/storage/conversion/DynamicJsonToTemplateConverter.test.ts +++ b/test/unit/storage/conversion/DynamicJsonToTemplateConverter.test.ts @@ -1,9 +1,11 @@ import { DataFactory } from 'n3'; import { BasicRepresentation } from '../../../../src/http/representation/BasicRepresentation'; import type { Representation } from '../../../../src/http/representation/Representation'; +import { RepresentationMetadata } from '../../../../src/http/representation/RepresentationMetadata'; import type { RepresentationPreferences } from '../../../../src/http/representation/RepresentationPreferences'; import { DynamicJsonToTemplateConverter } from '../../../../src/storage/conversion/DynamicJsonToTemplateConverter'; import type { RepresentationConverterArgs } from '../../../../src/storage/conversion/RepresentationConverter'; +import { NotImplementedHttpError } from '../../../../src/util/errors/NotImplementedHttpError'; import { readableToString } from '../../../../src/util/StreamUtil'; import type { TemplateEngine } from '../../../../src/util/templates/TemplateEngine'; import { CONTENT_TYPE_TERM, SOLID_META } from '../../../../src/util/Vocabularies'; @@ -50,6 +52,12 @@ describe('A DynamicJsonToTemplateConverter', (): void => { await expect(converter.canHandle(input)).resolves.toBeUndefined(); }); + it('rejects JSON input if no templates are defined.', async(): Promise => { + preferences.type = { 'application/json': 1 }; + representation.metadata = new RepresentationMetadata('application/json'); + await expect(converter.canHandle(input)).rejects.toThrow(NotImplementedHttpError); + }); + it('uses the input JSON as parameters for the matching template.', async(): Promise => { const result = await converter.handle(input); await expect(readableToString(result.data)).resolves.toBe(''); @@ -64,4 +72,19 @@ describe('A DynamicJsonToTemplateConverter', (): void => { const result = await converter.handle(input); await expect(readableToString(result.data)).resolves.toBe(''); }); + + it('returns the input representation if JSON is preferred.', async(): Promise => { + input.preferences.type = { 'application/json': 1, 'text/html': 0.5 }; + await expect(converter.handle(input)).resolves.toBe(input.representation); + }); + + it('still converts if JSON is preferred but there is a JSON template.', async(): Promise => { + input.preferences.type = { 'application/json': 1 }; + const templateNode = namedNode(templateFile); + representation.metadata.add(SOLID_META.terms.template, templateNode); + representation.metadata.addQuad(templateNode, CONTENT_TYPE_TERM, 'application/json'); + const result = await converter.handle(input); + await expect(readableToString(result.data)).resolves.toBe(''); + expect(result.metadata.contentType).toBe('application/json'); + }); });