diff --git a/src/schema-validator.js b/src/schema-validator.js new file mode 100644 index 0000000..82cba9b --- /dev/null +++ b/src/schema-validator.js @@ -0,0 +1,30 @@ +/* + * Copyright 2023 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +import { validate } from 'jsonschema'; +import ingestionRequestSchema from './schemas/ingestion-request.json' assert { type: 'json' }; + +export class SchemaValidator { + // eslint-disable-next-line class-methods-use-this + validateIngestionRequest(ingestionRequest, additionalRequired) { + const result = validate(ingestionRequest, ingestionRequestSchema, { + allowUnknownAttributes: false, + }); + + if (result.errors?.length > 0) { + throw new Error( + `Failed to validate schema, errors: \n- ${result.errors + .map((e) => e.message) + .join('\n- ')}`, + ); + } + } +} diff --git a/src/schemas/ingestion-request.json b/src/schemas/ingestion-request.json new file mode 100644 index 0000000..33c0d5d --- /dev/null +++ b/src/schemas/ingestion-request.json @@ -0,0 +1,102 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "type": "object", + "default": {}, + "title": "Ingestion Request", + "required": ["data", "binary", "jobId", "batchId", "requestId"], + "properties": { + "data": { + "type": "object", + "default": {}, + "title": "Source Data", + "required": ["sourceAssetId", "sourceId", "sourceType", "name"], + "properties": { + "sourceAssetId": { + "type": "string", + "description": "The unique identifier for the asset in the Source system" + }, + "sourceId": { + "type": "string", + "description": "The identifier for the instance of the source" + }, + "sourceType": { + "type": "string", + "description": "The type of the source" + }, + "sourceUrl": { + "type": "string", + "default": "", + "description": "A URL for accessing this asset in the source system" + }, + "name": { + "type": "string", + "description": "The name of the asset in the source" + }, + "size": { + "type": "integer", + "default": 0, + "description": "The size of the binary of the source asset" + }, + "created": { + "type": "string", + "description": "The date on which the asset was created in the source system", + "format": "date-time" + }, + "createdBy": { + "type": "string", + "description": "An identifier for the principal which created the asset in the source system" + }, + "lastModified": { + "type": "string", + "description": "The date on which the asset was last modified in the source", + "format": "date-time" + }, + "lastModifiedBy": { + "type": "string", + "description": "An ID for the principal whom last updated the asset in the source system" + }, + "path": { + "type": "string", + "description": "The path to the asset in the source system" + }, + "version": { + "description": "The version of the current asset in the source system", + "type": "string" + } + }, + "additionalProperties": false + }, + "binary": { + "type": "object", + "default": {}, + "title": "Binary Request", + "required": ["url"], + "properties": { + "url": { + "type": "string", + "title": "A URL from which the binary can be retrieved" + }, + "headers": { + "type": "object", + "description": "Headers required to be passed along with the request to the URL", + "additionalProperties": { "type": "string" } + } + }, + "additionalProperties": false + }, + "jobId": { + "type": "string", + "description": "An identifier for an execution of extracting assets from a source" + }, + "batchId": { + "type": "string", + "default": "", + "description": "An identifier for the batch of assets within a job" + }, + "requestId": { + "type": "string", + "description": "An identifier for a specific request, should be stable across retries of a request" + } + }, + "additionalProperties": false +} diff --git a/test/schema-validator.test.js b/test/schema-validator.test.js new file mode 100644 index 0000000..6afdc82 --- /dev/null +++ b/test/schema-validator.test.js @@ -0,0 +1,108 @@ +/* + * Copyright 2023 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +/* eslint-env mocha */ +import assert from 'assert'; +import { SchemaValidator } from '../src/schema-validator.js'; + +describe('Schema Validator Tests', () => { + const validator = new SchemaValidator(); + describe('validateIngestionRequest', () => { + it('validates full object', () => { + validator.validateIngestionRequest({ + data: { + sourceAssetId: '2D155092-F458-4DDC-A00C-3B003C55EF54', + sourceId: 'site.sharepoint.com:/sites/ASite', + sourceType: 'microsoft', + sourceUrl: + 'https://site.sharepoint.com/sites/ASite/_layouts/15/Doc.aspx?sourcedoc=someid\u0026file=somefile.png\u0026action=default\u0026mobileredirect=true', + name: 'somefile.png', + size: 36699, + created: '2017-03-06T22:41:31Z', + createdBy: 'testuser@adobe.com', + lastModified: '2017-03-24T05:59:37Z', + lastModifiedBy: 'testuser2@adobe.com', + path: '/sites/ASite/somepath/somefile.png', + }, + binary: { + url: 'https://site.sharepoint.com/sites/ASite/_layouts/15/download.aspx?UniqueId=SOMEID\u0026Translate=false\u0026tempauth=SOMEJWT', + }, + jobId: '123', + batchId: '2023-03-15T16:23:22.149Z', + requestId: '4556', + }); + }); + + it('validates limited object', () => { + validator.validateIngestionRequest({ + data: { + sourceAssetId: '2D155092-F458-4DDC-A00C-3B003C55EF54', + sourceId: 'site.sharepoint.com:/sites/ASite', + sourceType: 'microsoft', + name: 'testFile.png', + }, + binary: { + url: 'https://site.sharepoint.com/sites/ASite/_layouts/15/download.aspx?UniqueId=SOMEID\u0026Translate=false\u0026tempauth=SOMEJWT', + }, + jobId: '123', + batchId: '2023-03-15T16:23:22.149Z', + requestId: '4556', + }); + }); + + it('fails on unexpected keys', () => { + let caught; + try { + validator.validateIngestionRequest({ + data: { + sourceAssetId: '2D155092-F458-4DDC-A00C-3B003C55EF54', + sourceId: 'site.sharepoint.com:/sites/ASite', + sourceType: 'microsoft', + name: 'testFile.png', + }, + binary: { + url: 'https://site.sharepoint.com/sites/ASite/_layouts/15/download.aspx?UniqueId=SOMEID\u0026Translate=false\u0026tempauth=SOMEJWT', + }, + jobId: '123', + batchId: '2023-03-15T16:23:22.149Z', + requestId: '4556', + iLikeNewKeys: true, + }); + } catch (err) { + caught = err; + } + assert.ok(caught); + }); + + it('fails on missing fields', () => { + let caught; + try { + validator.validateIngestionRequest({ + data: { + sourceAssetId: '2D155092-F458-4DDC-A00C-3B003C55EF54', + sourceId: 'site.sharepoint.com:/sites/ASite', + sourceType: 'microsoft', + name: 'testFile.png', + }, + binary: { + url: 'https://site.sharepoint.com/sites/ASite/_layouts/15/download.aspx?UniqueId=SOMEID\u0026Translate=false\u0026tempauth=SOMEJWT', + }, + jobId: '123', + batchId: '2023-03-15T16:23:22.149Z', + }); + } catch (err) { + caught = err; + } + assert.ok(caught); + }); + }); +});