UNPKG

cloudevent

Version:

JavaScript/Node.js implementation of the CloudEvents standard format

395 lines (375 loc) 20.9 kB
/* * Copyright 2018-2022 the original author or authors. * * Licensed 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 CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 'use strict' /** * Sample Node.js script to show usage of CloudEvent library */ const assert = require('node:assert').strict // import some common example data const { // commonEventTime, ceCommonData, ceCommonExtensions, ceCommonOptions, ceCommonOptionsForTextData, ceCommonOptionsStrict, ceDataAsJSONString, ceDataAsString, ceDataAsStringEncoded, ceNamespace, ceOptionsNoStrict, // ceOptionsStrict, ceServerUrl, valOnlyValidAllInstance, valOnlyValidInstance, valOptionsNoStrict, valOptionsStrict } = require('./common-example-data') console.log('Sample script: start execution ...\n') // reference the library, not needed if using destructuring assignment, see below const CloudEventExports = require('../src/') // from local path assert(CloudEventExports !== null) // get a reference only to cloudevent class definition/s // const { CloudEvent } = require('cloudevent') // from published module // const { CloudEvent } = require('../src/') // from local path const { CloudEvent, CloudEventValidator: V, CloudEventTransformer: T, JSONBatch } = require('../src/') // from local path assert(CloudEvent !== null && V !== null && T !== null && JSONBatch !== null) // create some sample instances but without mandatory fields (so not good for validation) ... // note that errors will be thrown at instance creation only when strict mode is true console.log('\nCreation of some CloudEvent (ce) instances, and related diagnostics:') const ceEmpty = new CloudEvent() // create an empty CloudEvent instance (not valid for the validator, even in default case, when strict mode flag is disabled) assert(ceEmpty !== null) console.log(`ce dump (but not good for validation): ${T.dumpObject(ceEmpty, 'ceEmpty')}`) const ceMinimalMandatoryUndefinedNoStrict = new CloudEvent(undefined, undefined, undefined, undefined, ceOptionsNoStrict) // expected success assert(ceMinimalMandatoryUndefinedNoStrict !== null) console.log(`ce dump (but not good for validation): ${T.dumpObject(ceMinimalMandatoryUndefinedNoStrict, 'ceMinimalMandatoryUndefinedNoStrict')}`) // const ceMinimalMandatoryUndefinedStrict = new CloudEvent(undefined, undefined, undefined, undefined, ceOptionsStrict) // expected failure // assert(ceMinimalMandatoryUndefinedStrict == null) // no, ReferenceError: ceMinimalMandatoryUndefinedStrict is not defined // create a sample minimal instance good for normal validation but not for strict validation ... const ceMinimalBadSource = new CloudEvent('1', ceNamespace, 'source (bad)', null) assert(ceMinimalBadSource !== null) console.log(`ce dump (good but not for strict validation): ${T.dumpObject(ceMinimalBadSource, 'ceMinimalBadSource')}`) // create a sample minimal instance ... const ceMinimal = new CloudEvent('1', // id ceNamespace, // type '/', // source {} // data (empty) // optional, but useful the same in this sample usage ) assert(ceMinimal !== null) console.log(`ce dump: ${T.dumpObject(ceMinimal, 'ceMinimal')}`) // When creating some instances with an undefined mandatory argument (handled by defaults), // but with strict flag disabled success is expected, otherwise with strict flag enabled a failure is expected ... // In JavaScript, null values are not handled as default values, only undefined values ... // create a sample instance with most common attributes defined ... const ceFull = new CloudEvent('1/full', ceNamespace, ceServerUrl, ceCommonData, // data ceCommonOptions, ceCommonExtensions ) assert(ceFull !== null) assert(!ceFull.isStrict) console.log(`ce dump: ${T.dumpObject(ceFull, 'ceFull')}`) const ceFullStrict = new CloudEvent('1/full-strict', ceNamespace, ceServerUrl, ceCommonData, // data ceCommonOptionsStrict, // use common options, but set strict mode to true ceCommonExtensions ) assert(ceFullStrict !== null) assert(ceFullStrict.isStrict) assert(!ceFull.isStrict) // ensure common options object has not been changed when reusing some of its values for the second instance assert(!CloudEvent.isStrictEvent(ceFull)) // the same, but using static method console.log(`ce dump: ${T.dumpObject(ceFullStrict, 'ceFullStrict')}`) // create an instance with a JSON string as data const ceFullStrictJSONTextData = new CloudEvent('2/full-strict-json-string-data', ceNamespace, ceServerUrl, ceDataAsJSONString, // data ceCommonOptionsStrict, // use strict options ceCommonExtensions ) assert(ceFullStrictJSONTextData !== null) assert(ceFullStrictJSONTextData.isStrict) console.log(`ce dump: ${T.dumpObject(ceFullStrictJSONTextData, 'ceFullStrictJSONTextData')}`) console.log(`ce validation results on ceFullStrictJSONTextData = ${CloudEvent.validateEvent(ceFullStrictJSONTextData)}`) // create an instance that wrap an Error const error = new Error('sample error') error.code = 1000 // add a sample error code, as number const errorToData = T.errorToData(error, { includeStackTrace: true, // addStatus: false, addTimestamp: true }) const ceErrorStrict = new CloudEvent('3/error-strict', ceNamespace, ceServerUrl, errorToData, // data ceCommonOptionsStrict, // use common options, but set strict mode to true ceCommonExtensions ) assert(ceErrorStrict !== null) assert(ceErrorStrict.isStrict) console.log(`ce dump: ${T.dumpObject(ceErrorStrict, 'ceErrorStrict')}`) // create an instance with a different content type const ceFullStrictOtherContentType = new CloudEvent('4/full-strict-other-content-type', ceNamespace, ceServerUrl, // ceDataAsString, // data ceCommonData, // data { ...ceCommonOptionsStrict, datacontenttype: 'application/xml' }, // use common strict options ceCommonExtensions ) assert(ceFullStrictOtherContentType !== null) assert(ceFullStrictOtherContentType.isStrict) assert(!ceFull.ceFullStrictOtherContentType) // ensure common options object has not been changed when reusing some of its values for the second instance assert(!CloudEvent.isStrictEvent(ceFull)) // the same, but using static method console.log(`ce dump: ${T.dumpObject(ceFullStrictOtherContentType, 'ceFullStrictOtherContentType')}`) // create an instance with data as a string, but not strict (to validate it even in strict mode) const ceFullTextData = new CloudEvent('5/no-strict-text-data', ceNamespace, ceServerUrl, ceDataAsString, // data // ceCommonOptions, // ok but not in strict validation ceCommonOptionsForTextData, // ok even in strict validation ceCommonExtensions ) assert(ceFullTextData !== null) assert(!ceFullTextData.isStrict) assert(ceFullTextData.payload === ceDataAsString) // returned data is transformed console.log(`ce payload: '${ceFullTextData.payload}', length: ${ceFullTextData.payload.length}`) console.log(`ce dump: ${T.dumpObject(ceFullTextData, 'ceFullTextData')}`) console.log(`ce validation results on ceFullTextData (no strict validation) = ${CloudEvent.validateEvent(ceFullTextData)}`) console.log(`ce validation results on ceFullTextData (with strict validation) = ${CloudEvent.validateEvent(ceFullTextData, valOptionsStrict)}`) // create an instance with data encoded in base64 const ceFullStrictBinaryData = new CloudEvent('6/full-strict-binary-data', ceNamespace, ceServerUrl, null, // data { ...ceCommonOptionsStrict, datainbase64: ceDataAsStringEncoded }, // use common strict options, and set binary data in base64 ceCommonExtensions ) assert(ceFullStrictBinaryData !== null) assert(ceFullStrictBinaryData.isStrict) assert(ceFullStrictBinaryData.payload === ceDataAsString) // returned data is transformed console.log(`ce payload: '${ceFullStrictBinaryData.payload}', length: ${ceFullStrictBinaryData.payload.length}`) console.log(`ce dump: ${T.dumpObject(ceFullStrictBinaryData, 'ceFullStrictBinaryData')}`) // validate/check if valid instances (optional) // then, to validate objects, use class static methods like 'isValidEvent' and 'ValidateEvent', or instance methods like 'isValid', 'validate', etc ... assert(!ceEmpty.isValid()) assert(!ceMinimalMandatoryUndefinedNoStrict.isValid()) // console.log(`DEBUG | ${CloudEvent.dumpValidationResults(ceMinimalBadSource, null, 'ceMinimalBadSource')}`) assert(ceMinimalBadSource.isValid()) // console.log(`DEBUG | ${CloudEvent.dumpValidationResults(ceMinimalBadSource, valOptionsStrict, 'ceMinimalBadSource')}`) assert(!ceMinimalBadSource.isValid(valOptionsStrict)) assert(ceMinimal.isValid()) assert(ceMinimal.isValid(valOptionsStrict)) assert(ceFull.isValid()) assert(ceFullStrict.isValid()) assert(ceFullStrictJSONTextData.isValid()) assert(ceErrorStrict.isValid()) assert(ceFullStrictOtherContentType.isValid()) assert(ceFullTextData.isValid()) assert(ceFullTextData.isValid(valOptionsStrict)) assert(ceFullStrictBinaryData.isValid()) // the same, but using static method assert(!CloudEvent.isValidEvent(ceEmpty)) assert(!CloudEvent.isValidEvent(ceMinimalMandatoryUndefinedNoStrict)) assert(CloudEvent.isValidEvent(ceMinimal)) assert(CloudEvent.isValidEvent(ceFull)) assert(CloudEvent.isValidEvent(ceFullStrict)) assert(CloudEvent.isValidEvent(ceFullStrictJSONTextData)) assert(CloudEvent.isValidEvent(ceErrorStrict)) assert(CloudEvent.isValidEvent(ceFullStrictOtherContentType)) assert(CloudEvent.isValidEvent(ceFullTextData)) assert(CloudEvent.isValidEvent(ceFullTextData, valOptionsStrict)) assert(CloudEvent.isValidEvent(ceFullStrictBinaryData)) // console.log(`DEBUG | ${CloudEvent.dumpValidationResults(ceEmpty, null, 'ceEmpty')}`) assert(CloudEvent.validateEvent(ceEmpty).length === 3) // console.log(`DEBUG | ${CloudEvent.dumpValidationResults(ceEmpty, valOptionsStrict, 'ceEmpty')}`) assert(CloudEvent.validateEvent(ceEmpty, valOptionsStrict).length === 4) assert(CloudEvent.validateEvent(ceMinimalMandatoryUndefinedNoStrict).length > 0) assert(CloudEvent.validateEvent(ceMinimal).length === 0) assert(CloudEvent.validateEvent(ceFull).length === 0) assert(CloudEvent.validateEvent(ceFull, valOptionsNoStrict).length === 0) assert(CloudEvent.validateEvent(ceFull, valOptionsStrict).length === 0) assert(CloudEvent.validateEvent(ceFullStrict).length === 0) assert(CloudEvent.validateEvent(ceFullStrict, valOptionsNoStrict).length === 0) assert(CloudEvent.validateEvent(ceFullStrict, valOptionsStrict).length === 0) assert(CloudEvent.validateEvent(ceFullStrictJSONTextData).length === 0) assert(CloudEvent.validateEvent(ceFullStrictJSONTextData, valOptionsNoStrict).length === 0) assert(CloudEvent.validateEvent(ceFullStrictJSONTextData, valOptionsStrict).length === 0) assert(CloudEvent.validateEvent(ceFullStrictOtherContentType).length === 0) assert(CloudEvent.validateEvent(ceFullStrictOtherContentType, valOptionsNoStrict).length === 0) assert(CloudEvent.validateEvent(ceFullStrictOtherContentType, valOptionsStrict).length === 0) assert(CloudEvent.validateEvent(ceFullTextData).length === 0) assert(CloudEvent.validateEvent(ceFullTextData, valOptionsNoStrict).length === 0) assert(CloudEvent.validateEvent(ceFullTextData, valOptionsStrict).length === 0) assert(CloudEvent.validateEvent(ceFullStrictBinaryData).length === 0) assert(CloudEvent.validateEvent(ceFullStrictBinaryData, valOptionsNoStrict).length === 0) assert(CloudEvent.validateEvent(ceFullStrictBinaryData, valOptionsStrict).length === 0) // some diagnostic info console.log('\nSome expected validation errors:') console.log(`Validation output for ceEmpty (default strict mode) is: size: ${CloudEvent.validateEvent(ceEmpty).length}, details:\n` + CloudEvent.validateEvent(ceEmpty)) console.log(`Validation output for ceEmpty (force strict mode to true) is: size: ${CloudEvent.validateEvent(ceEmpty, valOptionsStrict).length}, details:\n` + CloudEvent.validateEvent(ceEmpty, valOptionsStrict)) console.log(`Validation output for ceEmpty, alternative way: ${CloudEvent.dumpValidationResults(ceEmpty, valOptionsStrict, 'ceEmpty')}`) // serialization examples // default contenttype console.log('\nSome serialization examples:') const ceFullSerializedStatic = CloudEvent.serializeEvent(ceFull) assert(ceFullSerializedStatic !== null) const ceFullSerialized = ceFull.serialize() assert(ceFullSerialized !== null) assert(ceFullSerializedStatic === ceFullSerialized) console.log('Serialization output for ceFull, details:\n' + ceFullSerialized) const ceFullStrictSerialized = ceFullStrict.serialize() assert(ceFullStrictSerialized !== null) console.log('Serialization output for ceFullStrict, details:\n' + ceFullStrictSerialized) const ceFullStrictSerializedOnlyValid = CloudEvent.serializeEvent(ceFullStrict, valOnlyValidInstance) assert(ceFullStrictSerializedOnlyValid !== null) // non default contenttype const ceFullStrictOtherContentTypeSerializedStatic = CloudEvent.serializeEvent(ceFullStrictOtherContentType, { // encoder: (data) => '<data "encoder"="sample" />', encodedData: '<data "hello"="world" "year"="2020" />', ...valOnlyValidInstance }) assert(ceFullStrictOtherContentTypeSerializedStatic !== null) const ceFullStrictOtherContentTypeSerialized = ceFullStrictOtherContentType.serialize({ // encoder: (data) => '<data "encoder"="sample" />', encodedData: '<data "hello"="world" "year"="2020" />', ...valOnlyValidInstance }) assert(ceFullStrictOtherContentTypeSerialized !== null) assert(ceFullStrictOtherContentTypeSerializedStatic === ceFullStrictOtherContentTypeSerialized) console.log('Serialization output for ceFullStrictOtherContentType, details:\n' + ceFullStrictOtherContentTypeSerialized) const ceFullTextDataSerialized = CloudEvent.serializeEvent(ceFullTextData, valOnlyValidInstance) assert(ceFullTextDataSerialized !== null) console.log('Serialization output for ceFullTextData, details:\n' + ceFullTextDataSerialized) const ceFullStrictBinaryDataSerialized = CloudEvent.serializeEvent(ceFullStrictBinaryData, valOnlyValidInstance) assert(ceFullStrictBinaryDataSerialized !== null) console.log('Serialization output for ceFullStrictBinaryData, details:\n' + ceFullStrictBinaryDataSerialized) // then use (send/store/etc) serialized instances ... // deserialization examples // default contenttype console.log('\nSome deserialization/parse examples:') const ceFullDeserialized = CloudEvent.deserializeEvent(ceFullSerialized) assert(ceFullDeserialized !== null) assert(ceFullDeserialized.isValid()) assert(!ceFullDeserialized.isStrict) assert(CloudEvent.isCloudEvent(ceFullDeserialized)) console.log(`ce dump: ${T.dumpObject(ceFullDeserialized, 'ceFullDeserialized')}`) const ceFullStrictDeserializedOnlyValid = CloudEvent.deserializeEvent(ceFullStrictSerialized, valOnlyValidInstance) assert(ceFullStrictDeserializedOnlyValid !== null) console.log(`ce dump: ${T.dumpObject(ceFullStrictDeserializedOnlyValid, 'ceFullStrictDeserializedOnlyValid')}`) // non default contenttype const ceFullStrictOtherContentTypeDeserialized = CloudEvent.deserializeEvent(ceFullStrictOtherContentTypeSerialized, { // decoder: (data) => { decoder: 'Sample' }, decodedData: { hello: 'world', year: 2020 }, ...valOnlyValidInstance }) assert(ceFullStrictOtherContentTypeDeserialized !== null) assert(ceFullStrictOtherContentTypeDeserialized.isValid()) assert(ceFullStrictOtherContentTypeDeserialized.isStrict) assert(CloudEvent.isCloudEvent(ceFullStrictOtherContentTypeDeserialized)) console.log(`ce dump: ${T.dumpObject(ceFullStrictOtherContentTypeDeserialized, 'ceFullStrictOtherContentTypeDeserialized')}`) const ceFullTextDataDeserialized = CloudEvent.deserializeEvent(ceFullTextDataSerialized, valOnlyValidInstance) assert(ceFullTextDataDeserialized !== null) assert(ceFullTextDataDeserialized.isValid()) assert(!ceFullTextDataDeserialized.isStrict) assert(CloudEvent.isCloudEvent(ceFullTextDataDeserialized)) console.log(`ce dump: ${T.dumpObject(ceFullTextDataDeserialized, 'ceFullTextDataDeserialized')}`) const ceFullStrictBinaryDataDeserialized = CloudEvent.deserializeEvent(ceFullStrictBinaryDataSerialized, valOnlyValidInstance) assert(ceFullStrictBinaryDataDeserialized !== null) assert(ceFullStrictBinaryDataDeserialized.isValid()) assert(ceFullStrictBinaryDataDeserialized.isStrict) assert(CloudEvent.isCloudEvent(ceFullStrictBinaryDataDeserialized)) console.log(`ce dump: ${T.dumpObject(ceFullStrictBinaryDataDeserialized, 'ceFullStrictBinaryDataDeserialized')}`) // then use (validate/send/store/etc) deserialized instances ... // example usage of some CloudEvent instances as a JSONBatch // note that I put even wrong data types inside the array to show some features console.log('\nJSONBatch examples:') const batch = [ undefined, null, 'string', // bad 1234567890, // bad 3.14159, // bad false, // bad true, // bad ceMinimalBadSource, // good but not for strict validation ceMinimal, ceFull, new Date(), // bad {}, // bad [], // bad ceFullStrict, ceErrorStrict, ceFullStrictOtherContentType, // good, but to serialize/deserialize related options must be used ceFullTextData, ceFullStrictBinaryData, null, undefined ] assert(JSONBatch.isJSONBatch(batch)) assert(!JSONBatch.isValidBatch(batch)) // it has some validation error (on its content) console.log(`JSONBatch contains ${batch.length} items, but only some are valid CloudEvent instances, see related sample code:`) console.log(`CloudEvent instances valid: ${JSONBatch.getEvents(batch, { ...valOnlyValidInstance, strict: false }).length}`) console.log(`CloudEvent instances valid in strict mode: ${JSONBatch.getEvents(batch, { ...valOnlyValidInstance, strict: true }).length}`) // sample validation, in normal and in strict mode console.log(`JSONBatch validation errors, num: ${JSONBatch.validateBatch(batch, valOptionsNoStrict).length}`) console.log(`JSONBatch validation errors in strict mode, num: ${JSONBatch.validateBatch(batch, valOptionsStrict).length}`) console.log(`JSONBatch validation errors in strict mode, details:\n${JSONBatch.validateBatch(batch, valOptionsStrict)}\n`) assert(JSONBatch.validateBatch(batch, valOptionsNoStrict).length === 8) // expected validation errors assert(JSONBatch.validateBatch(batch, valOptionsStrict).length === 13) // expected validation errors // sample filtering of events // console.log(`DEBUG | JSONBatch.getEvents, num: ${JSONBatch.getEvents(batch, { ...valOnlyValidInstance, strict: true }).length}`) assert(JSONBatch.getEvents(batch, { ...valOnlyValidAllInstance, strict: false }).length === 8) // no filtering assert(JSONBatch.getEvents(batch, { ...valOnlyValidAllInstance, strict: true }).length === 8) // no filtering (neither in strict mode) assert(JSONBatch.getEvents(batch, { ...valOnlyValidInstance, strict: false }).length === 8) // only valid assert(JSONBatch.getEvents(batch, { ...valOnlyValidInstance, strict: true }).length === 7) // only valid in strict mode console.log('JSONBatch events: get only valid instances, as a sample') const events = JSONBatch.getEvents(batch, { ...valOnlyValidInstance, ...valOptionsNoStrict }) console.log(`JSONBatch events: length = ${events.length}, summary: ${events}`) console.log(`JSONBatch events: length = ${events.length}, details: ${JSON.stringify(events)}`) assert(events !== null) // sample serialization/deserialization on it (batch) or a subset (events) // note that additional serialization options could be used, for example to handle non default data content types ... const ser = JSONBatch.serializeEvents(events, { prettyPrint: true, logError: true }) console.log(`JSONBatch events serialized = \n${ser}\n`) const deser = JSONBatch.deserializeEvents(ser, { logError: true, throwError: true, ...valOnlyValidInstance // sample, to filter out not valid serialized instances ... // onlyIfLessThan64KB: true }) console.log(`JSONBatch events: deserialized length = ${deser.length}, summary: ${deser}`) console.log(`JSONBatch events: deserialized JSONBatch length = ${deser.length}, details: ${JSON.stringify(deser)}`) assert(deser !== null) // other ... console.log('\nSample script: end execution.') console.log('----') assert(true) // all good here // end of script