UNPKG

fastify-cloudevents

Version:

Fastify Plugin to serialize events in the CloudEvents standard format

238 lines (225 loc) 7.86 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' /** * Builder: * Utility module to export builder functions useful for creating * values (grouped or not) to use in Cloudevents. * Should not be used outside of the plugin. * @module utility */ /** * Get a reference to CloudEvent class definition and related utilities. * See {@link CloudEvent}. * @private */ const { CloudEvent, CloudEventTransformer } = require('cloudevent') /** * Utility function for creating grouped values to use in Cloudevents. * Should not be used outside of the plugin. * * @param {!object} options configuration options * @return {object} an object with builder functions (configured) to use * @private */ function builder (options = {}) { const { pluginName, pluginVersion, serverUrl, serverUrlMode, baseNamespace, idGenerator, includeHeaders, includeRedundantAttributes, cloudEventOptions, cloudEventExtensions } = options return { /** * Build the value for the source field of the CloudEvent, * depending on the plugin configuration of options * `serverUrlMode`, `serverUrl`, * and the uri part of the current request. * Note that this is mainly for usage inside the plugin, * but in some cases could be useful even outside. * * @param {string} [url=''] the uri part of the current request * @return {string} the source value to use, as a string * @private */ buildSourceUrl (url = '') { let sourceUrl switch (serverUrlMode) { case null: case 'pluginAndRequestSimplified': sourceUrl = serverUrl + CloudEventTransformer.uriStripArguments(url) break case 'pluginAndRequestUrl': sourceUrl = serverUrl + url break case 'pluginServerUrl': sourceUrl = serverUrl break case 'requestUrl': sourceUrl = url break default: throw new Error(`Illegal value for serverUrlMode: '${serverUrlMode}'`) } return sourceUrl }, /** * Extract and build the value for the client IP address, * useful to add into the CloudEvent in a custom attribute inside data, * otherwise nothing. * * @param {!object} request the request * @return {string} the IP address, as a string or undefined * @private */ buildClientIP (request) { if (request === undefined || request === null) { throw new Error('Illegal value for request: undefined or null') } return request.ip || undefined }, /** * Extract and build the value for the HTTP headers, * useful to add into the CloudEvent in a custom attribute inside data. * If plugin flag 'includeHeaders' is enabled, headers will be returned, * otherwise nothing. * Note that some config options for builders are used here. * * @param {!object} request the request * @return {string} HTTP request headers, as a string, or undefined * @private */ buildHeaders (request) { if (request === undefined || request === null) { throw new Error('Illegal value for request: undefined or null') } const headers = (includeHeaders === null || includeHeaders === false) ? undefined : request.headers return headers }, /** * Extract and build values from the given arguments, * and returns them inside a wrapper object. * * @param {!object} request the request * @return {object} an object containing headers, source URL, the IP address * @private */ buildValues (request) { const clientIp = this.buildClientIP(request) const headers = this.buildHeaders(request) const sourceUrl = this.buildSourceUrl(request.raw.url) return { clientIp, headers, sourceUrl } }, /** * Extract some values from the given arguments, * and returns them inside a wrapper object * to be used in a CloudEvent data (sub-)property. * * @param {!object} request the request * @return {object} an object containing extracted attributes * @private */ buildRequestDataForCE (request) { return { id: request.id, headers: this.buildHeaders(request), clientIp: this.buildClientIP(request), params: request.params, query: request.query, body: request.body, method: request.raw.method, url: request.raw.url } }, /** * Extract some values from the given arguments, * and returns them inside a wrapper object * to be used in a CloudEvent data (sub-)property. * * @param {!object} reply the reply * @return {object} an object containing extracted attributes * @private */ buildReplyDataForCE (reply) { return { statusCode: reply.raw.statusCode, statusMessage: reply.raw.statusMessage, finished: reply.raw.finished } }, /** * Extract some values from the given arguments, * and returns them inside a wrapper object * to be used in a CloudEvent data (sub-)property. * Note that some config options for builders are used here. * * @param {object} [description=''] the description (maybe related to the event) * @return {object} an object containing extracted attributes * @private */ buildPluginDataForCE (description = '') { return { timestamp: CloudEventTransformer.timestampToNumber(), description, name: pluginName, version: pluginVersion } }, /** * Build a CloudEvent instance from the given arguments, * useful for simplify plugin hooks. * If plugin flag 'includeRedundantAttributes' is enabled, * some redundant attributes will be added to data. * Note that some config options for builders are used here. * * @param {!string} hookName the name of the hook * @param {!object} request the request * @param {object} reply the reply * @param {object} payload the payload * @return {object} the CloudEvent instance * @private */ buildCloudEventForHook (hookName, request, reply, payload) { if (!hookName || !request) { throw new Error('Illegal arguments: mandatory argument undefined or null') } const ceData = { request: this.buildRequestDataForCE(request), reply: (reply === null) ? undefined : this.buildReplyDataForCE(reply), payload } if (includeRedundantAttributes !== null && includeRedundantAttributes === true) { ceData.id = request.id ceData.timestamp = CloudEventTransformer.timestampToNumber() } const ce = new CloudEvent(idGenerator.next().value, `${baseNamespace}.${hookName}`, this.buildSourceUrl(request.raw.url), ceData, cloudEventOptions, cloudEventExtensions ) return ce } } } module.exports = builder