sls-helper-plugin-janis

9.5.3 • Public • Published

Serverless Helper Plugin JANIS

A plugin for JANIS Commerce to use with the Serverless Helper Framework.

npm version Build status Coverage Status

Helpers

base

Used to implement a base service with minimal setup

Option Type Description Attributes Default value
serviceCode string The service name in lowercase dash separated Required
servicePort number The service port Required
params { [env]: { [param]: value } } A mapping of param name and value by environment. Well known environments are: local, beta, qa and prod, but any other env will be kept The params humanReadableStage and janisDomain are defined for each well-known env.

Some properties of the initial configuration have a new special meaning:

package.include and package.includeOnly

package.exclude and package.excludeOnly

package.plugins and package.pluginsOnly

This properties (if present in the initial service configuration) have the following behavior:

  • package.include, package.exclude and plugins will be appended to the hooks defaults
  • package.includeOnly, package.excludeOnly and pluginsOnly will replace entirely the hooks defaults

Trace Lambda Layer

If the env vars TRACE_ACCOUNT_ID and JANIS_TRACE_EXTENSION_VERSION are set, the Trace Lambda Layer will be set for every function by default.

apiGet and apiList are the only functions that have this behaviour changed by default.

To disable the layer, see the skipTraceLayer property in other helpers.

templates

Used to implement Lambda APIs requests and response templates as custom props

No options

authorizers

Used to implement APIs authorizers as custom props.

Using the env var AUTHORIZER_ACCOUNT_ID that indicates the AWS account ID where the authorizers are deployed. Required.

cors

Used to implement APIs CORS configuration as custom props

If options is undefined or set to true it will use the default CORS config for every property. You can also customize or override every property:

Option Type Description Default value
replace boolean Indicates whether it should replace the CORS properties or merge then with the default false
origins array<string> An array of allowed origins ['*']
headers array<string> An array of allowed headers See below
allowCredentials boolean Indicates whether the credentials header should be set true
maxAge number The time in seconds thar CORS headers should be cached 600

CORS Default headers:

[
	'authorization',
	'content-type',
	'janis-api-key',
	'janis-api-secret',
	'janis-client',
	'janis-service',
	'janis-entity',
	'x-api-key',
	'x-janis-totals',
	'x-janis-only-totals',
	'x-janis-page',
	'x-janis-page-size'
]

api

Used to implement a custom API

Option Type Description Attributes Default value
functionName string The name of the lambda function. Will be used in API-{serviceName}-{functionName}-{stage}. Since 5.6.0
path string The API path Required
method string The API HTTP Method 'get'
methodName string The JANIS API Method Enum<list, get, post, put, patch, delete> Defaults to same value of method option
layers array[object] An array of function-level layers. This will override any provider-level layers, except for the Trace Layer. Use together with skipTraceLayer to remove the Trace layer (since 8.2.0)
addLayers array[object] An array of function-level layers. This will be appended to any provider-level layers (since 8.2.0)
skipTraceLayer boolean Set to true if the API should not use the Trace Lambda Layer false
handler string The lambda handler path and function 'src/lambda/RestApi/index.handler'
caching boolean Set to true to enable cache false
cors boolean object Set to true to enable services default CORS, or configure as an object as explained in CORS to customize the API CORS
queryParameters object A key value to map query string parameters to a boolean indicating if it's required or not
requestTemplates object A key value to map content types to request mapping headers. By default only application/json is enabled (Docs)
requestHeaders object A key value to map headers to a boolean indicating if it's required or not
authorizer string The name of the authorizer
timeout number The function timeout in seconds
package.include array[string] The List of paths of files to include
functionRawProps object Custom properties to set in the function configuration
eventRawProps object Custom properties to set in the event configuration

apiList, apiGet, apiPost and apiPut

Used to implement JANIS CRUD APIs.

Option Type Description Attributes Default value
functionName string The name of the lambda function. Will be used in API-{serviceName}-{functionName}-{stage}. Since 5.6.0
entityName string The entity name Required
handler string The lambda handler path and function 'src/lambda/RestApi/index.handler'
path string The API path /[entity-name] (for apiList and apiPost) or /[entity-name]/{id} (for apiGet and apiPut)
layers array[object] An array of function-level layers. This will override any provider-level layers, except for the Trace Layer. Use together with skipTraceLayer to remove the Trace layer (since 8.2.0)
addLayers array[object] An array of function-level layers. This will be appended to any provider-level layers (since 8.2.0)
skipTraceLayer boolean Set to true if the API should not use the Trace Lambda Layer false for post and put APIs, true for get and list APIs
caching boolean Set to true to enable cache false
cors boolean object Set to true to enable services default CORS, or configure as an object as explained in CORS to customize the API CORS
queryParameters object A key value to map query string parameters to a boolean indicating if it's required or not
requestTemplates object A key value to map content types to request mapping headers. By default only application/json is enabled (Docs)
requestHeaders object A key value to map headers to a boolean indicating if it's required or not
authorizer string The name of the authorizer
timeout number The function timeout in seconds
package.include array[string] The List of paths of files to include
functionRawProps object Custom properties to set in the function configuration
eventRawProps object Custom properties to set in the event configuration

eventListener

Used to implement JANIS Events listeners

Option Type Description Attributes Default value
serviceName string The service name Required
entityName string The entity name Required
eventName string The event name Required
mustHaveClient boolean Indicates if authorizer must validate that client or not false
listenersDirName string Indicates the path where the event listener files are placed 'event-listeners'
layers array[object] An array of function-level layers. This will override any provider-level layers, except for the Trace Layer. Use together with skipTraceLayer to remove the Trace layer (since 8.2.0)
addLayers array[object] An array of function-level layers. This will be appended to any provider-level layers (since 8.2.0)
skipTraceLayer boolean Set to true if the API should not use the Trace Lambda Layer (since 8.2.0) false
authorizer string The name of the authorizer If not set, it defaults to ServiceAuthorizer or ServiceNoClientAuthorizer based on the value of mustHaveClient
package.include array[string] The List of paths of files to include
timeout number The function timeout in seconds
functionRawProps object Custom properties to set in the function configuration

dbConfig

(since 3.1.0)

Used to implement JANIS Database config as secret with an auto-generated password

Option Type Description Attributes Default value
secret string | object The secret content as an object or a JSON stringified object Required
secretName string The secret name 'janis/${self:custom.serviceCode}/${self:custom.stage}/db-config'
description string The secret description 'Database config secret for janis ${self:custom.serviceCode} ${self:custom.stage}'
passwordKey string The property name where the password will be generated 'password'
passwordLength number The generated password length 40

stateMachine

(since 4.3.0)

Used to implement AWS State Machines

Option Type Description Attributes Default value
name string The name of the state machine Required
definition object The definition of the state machine. See more Step Functions Required
type string The type of workflow of the state machine. Enum<STANDARD,EXPRESS> STANDARD
loggingConfig boolean|string|object The Cloudwatch Logging Configuration of the state machine. If not set, logging will be OFF.
If set to true, logging will be set to INFO and a default Log Group will be created.
If set as string, it will be used as log level and a default Log Group will be created.
If set as an object, it will be used as is (a default Log Group will be created if destinations property is not set)

See loggingConfig documentation for full configuration options.
rawProperties object A free form object to set any property supported by the Step Functions Plugin but not supported by this package.

It will automatically include the serverless-step-functions plugin.

It also defines 2 properties in the custom namespace:

  • custom.machines.{MachineName}.arn: The State Machine ARN
  • custom.machines.{MachineName}.name: The State Machine Name

Important: The {MachineName} in the custom.machines path will replaced be the name property converted to PascalCase. For example, if the following hook is configured

['janis.stateMachine', {
	name: 'my-super-machine',
	definition: myDefinition
}]

The following custom props will be set: custom.machines.MySuperMachine.arn and custom.machines.MySuperMachine.name

functionsVpc

(since 7.1.0)

Used to attach the service to a VPC with a Custom Security Group

Important: This hook MUST be set after declaring every function of the service. If a function is declared after this hook, it won't be attached to the VPC.

Option Type Description Attributes Default value
vpcId string The ID of the VPC, for example vpc-11111111. If this is not set, VPC will not be attached.
subnetIds string[] The IDs of the Subnets, for example subnet-111111111. If this is not set or is empty, VPC will not be attached.

It will automatically create a Security Group in the given VPC and attach it to every lambda function. The logical name of the SG will be ServiceSecurityGroup. It can be overriden using Serverless resource overrides.

['janis.functionsVpc', {
	vpcId: 'vpc-11111111',
	subnetIds: [
		'subnet-111111111',
		'subnet-222222222'
	]
}]

VPC Configuration

(since 8.0.0)

If the env vars LAMBDA_SECURITY_GROUP_ID and LAMBDA_SUBNET_IDS are set, the global VPC configuration for all functions added in the service will be added in provider.

See more VPC Configuration

process.env.LAMBDA_SECURITY_GROUP_ID = 'sg-abcdef0001';
process.env.LAMBDA_SUBNET_IDS = 'subnet-111111111,subnet-222222222';

Function URL

This plugin is used to create Lambda functions with customized domains. The domain structure follows the format ${customSubdomain}.${hostedZone}/{customPath}.

Important:

  • This hook links existing Lambda functions with custom domains. It means referenced Functions must be defined before this hook.
  • The hostedZone name is obtained from ${self:custom.customDomain.lambdaUrlDomainName}. If it is not defined, the value of ${self:custom.customDomain.domainName} will be used instead.
Option Type Description
subdomainName string Subdomain to prepend to Service domain name (defined as a custom property for each service).
acmCertificate string AWS's ACM Certificate Id valid for defined subdomain.
functions Array{} Array of objects with path definitions for the subdomain.

* The first referenced function will be set as the default for requests with no path.
functions.0.functionName string Name of the function being referenced.

* In order to be valid, referenced Functions must be defined as Lambdas Url.
functions.0.path string Relative path associated with the function.

* Use '' to redirect all requests with that specific path and any additional subpaths to that specific function*

It will automatically create (or update) a Cloudfront Distribution and a Route 53 Record Set.

[
	"janis.functionUrl",
	{
		"subdomainName": "subSubdomain.subdomain",
		"acmCertificate": "${param:acmCertificateId}",
		"functions": [
			{
				"functionName": "CustomUrlLambda",
				"path": "/customUrl/*"
			},
			{
				"functionName": "CustomUrlLambda2",
				"path": "/customUrl2/"
			}
		]
	}
]

Expected URLs to access CustomUrlLambda: https://subSubdomain.subdomain.{HostedZoneName}/customUrl. https://subSubdomain.subdomain.{HostedZoneName}/customUrl/subpath

Expected URL to access CustomUrlLambda2: https://subSubdomain.subdomain.{HostedZoneName}/customUrl2

🆕 Hook Builders Helpers

This kind of Helpers aren't hooks, this helpers builds hooks (normally many of them) that together make available some kind of resource.

This helpers exist to create some kind of standard and re-utilize another hooks

SQS Helper

This helpers must be used to create SQS resources and consumers with minimal data to a full customization.

Require Helpers

Unlike to normal Hooks, they must be explicitly required from the package.

const { SQSHelper } = require('sls-helper-plugin-janis');  // eslint-disable-line

Permissions

To use SQS resources, AWS permissions must be added, in order to make it easier, you can get them from the Helper using SQSHelper.sqsPermissions getter.

Build Hook

To use the hook Builder of:

  • SQS Queue
  • DLQ Queue
  • Main Consumer
  • DLQ Consumer (optional)
  • Env Vars for SQS Urls

You can use SQSHelper.buildHooks(configs) method. This will create an array of Hooks with the proper data.

Parameters

  • configs: Object
    • name: REQUIRED | String | The name of SQS, it will be uses for every resource. It must be not empty and camelCase to avoid issues creating the resources names.
    • consumerProperties: OPTIONAL | Object | If it is not passed, it will use default data.
    • dlqConsumerProperties: OPTIONAL | Object | By default the DLQ consumer won't be created, you must pass values to create it.
    • mainQueueProperties: OPTIONAL Object | If it is not passed, it will use default data.
    • dlqQueueProperties: OPTIONAL Object | If it is not passed, it will use default data.

Only with a name can create everything except for the DLQ Consumer function

Consumer Properties: Both consumerPropertiesand dlqConsumerProperties fields can be customized with the following properties:

  • timeout: default: 15 | Change the Function timeout (in seconds).
  • handler: default: src/sqs-consumer/[name in lowerCase]-consumer.handler | Change the location of the file.
  • description: default: [name] SQS Queue Consumer | Change the function description.
  • batchSize: default: 1 (only for main consumer) | Change the SQS consumer batch Size.
  • maximumBatchingWindow: default: 10 (only for main consumer) | Change the SQS consumer maximum batching window.

Some other properties

  • functionProperties: Object | To add other properties to the function (the same one in function hook).
  • rawProperties: Object | To add rawProperties to the function for example changed a DependsOn.
  • eventProperties: Object | To add extra Properties to the sqs event configuration, for example functionResponseType

Queue Properties: Both mainQueuePropertiesand dlqQueueProperties fields can be customized with the following properties:

  • maxReceiveCount: default: 5 (only for Main Queue) | Change the max receive count properties before sent the message to DLQ.
  • receiveMessageWaitTimeSeconds: default: 20 (main Queue) or 5 (dlq).
  • visibilityTimeout: default: 60 (main queue) or 20 (dlq).
  • messageRetentionPeriod: default: 864000 (only for DLQ).

Returns: array of Hooks

Consumer Files

If handler's location don't change (uses default values), the files must be located in

  • src/sqs-consumer/[name-in-kebab-case]-consumer.js for main queue consumer
  • src/sqs-consumer/[name-in-kebab-case]-dlq-consumer.js for dlq consumer

SQS URL Env Vars

Environment Variables will be created for SQS URLs (both):

  • [NAME_IN_SNAKE_CASE]_SQS_QUEUE_URL for main queue consumer
  • [NAME_IN_SNAKE_CASE]_DLQ_SQS_QUEUE_URL for dlq consumer

Quick hook example

const { helper } = require('sls-helper'); // eslint-disable-line
const { SQSHelper } = require('sls-helper-plugin-janis');  // eslint-disable-line

// ...

module.exports = helper({
	hooks: [
		// other hooks

		// Permissions must be applied once
		SQSHelper.sqsPermissions

		// must spread it
		...SQSHelper.buildHooks({ name: 'SessionEnded' })
	]
});

/*

Creates the following Hooks
// For permissions

	['iamStatement', {
		action: [
			'sqs:SendMessage',
			'sqs:DeleteMessage',
			'sqs:ReceiveMessage',
			'sqs:GetQueueAttributes'
		],
		// eslint-disable-next-line no-template-curly-in-string
		resource: 'arn:aws:sqs:${aws:region}:${aws:accountId}:*'
	}]

// For Env Vars

	['envVars', {
		SESSION_ENDED_SQS_QUEUE_URL: 'https://sqs.${aws:region}.amazonaws.com/${aws:accountId}/${self:custom.serviceName}SessionEndedQueue',
		SESSION_ENDED_DLQ_QUEUE_URL: 'https://sqs.${aws:region}.amazonaws.com/${aws:accountId}/${self:custom.serviceName}SessionEndedDLQ'
	}]

// For SQS Consumer

	['function', {
		functionName: 'SessionEndedQueueConsumer',
		handler: 'src/sqs-consumer/session-ended-consumer.handler',
		description: 'SessionEnded SQS Queue Consumer',
		timeout: 15,
		rawProperties: {
			dependsOn: ['SessionEndedQueue']
		},
		events: [
			{
				sqs: {
					arn: 'arn:aws:sqs:${aws:region}:${aws:accountId}:${self:custom.serviceName}SessionEndedQueue',
					batchSize: 1,
					maximumBatchingWindow: 10
				}
			}
		]
	}]

// For SQS Resources

	['resource', {
		name: 'SessionEndedQueue',
		resource: {
			Type: 'AWS::SQS::Queue',
			Properties: {
				QueueName: '${self:custom.serviceName}SessionEndedQueue',
				ReceiveMessageWaitTimeSeconds: 20,
				VisibilityTimeout: 60,
				// eslint-disable-next-line max-len
				RedrivePolicy: '{"maxReceiveCount": 5, "deadLetterTargetArn": "arn:aws:sqs:${aws:region}:${aws:accountId}:${self:custom.serviceName}SessionEndedDLQ"}'
			},
			DependsOn: ['SessionEndedDLQ']
		}
	}]

	['resource', {
		name: 'SessionEndedDLQ',
		resource: {
			Type: 'AWS::SQS::Queue',
			Properties: {
				QueueName: '${self:custom.serviceName}SessionEndedDLQ',
				ReceiveMessageWaitTimeSeconds: 5,
				VisibilityTimeout: 20,
				MessageRetentionPeriod: 864000
			}
		}
	}]
*/

With DLQ Consumer example

const { helper } = require('sls-helper'); // eslint-disable-line
const { SQSHelper } = require('sls-helper-plugin-janis');  // eslint-disable-line

// ...

module.exports = helper({
	hooks: [
		// other hooks

		SQSHelper.sqsPermissions

		// must be spread
		...SQSHelper.buildHooks({
			name: 'SessionEnded',
			dlqConsumerProperties: {
				timeout: 30,
				batchSize: 10,
				maximumBatchingWindow: 100
			}
		})
	]
});

/*

Creates the following Hooks

// For permissions

	['iamStatement', {
		action: [
			'sqs:SendMessage',
			'sqs:DeleteMessage',
			'sqs:ReceiveMessage',
			'sqs:GetQueueAttributes'
		],
		// eslint-disable-next-line no-template-curly-in-string
		resource: 'arn:aws:sqs:${aws:region}:${aws:accountId}:*'
	}]

// For Env Vars

	['envVars', {
		SESSION_ENDED_SQS_QUEUE_URL: 'https://sqs.${aws:region}.amazonaws.com/${aws:accountId}/${self:custom.serviceName}SessionEndedQueue',
		SESSION_ENDED_DLQ_QUEUE_URL: 'https://sqs.${aws:region}.amazonaws.com/${aws:accountId}/${self:custom.serviceName}SessionEndedDLQ'
	}]

// For SQS Consumers

	['function', {
		functionName: 'SessionEndedQueueConsumer',
		handler: 'src/sqs-consumer/session-ended-consumer.handler',
		description: 'SessionEnded SQS Queue Consumer',
		timeout: 15,
		rawProperties: {
			dependsOn: ['SessionEndedQueue']
		},
		events: [
			{
				sqs: {
					arn: 'arn:aws:sqs:${aws:region}:${aws:accountId}:${self:custom.serviceName}SessionEndedQueue',
					batchSize: 1,
					maximumBatchingWindow: 10
				}
			}
		]
	}]

	['function', {
		functionName: 'SessionEndedDLQQueueConsumer',
		handler: 'src/sqs-consumer/session-ended-dlq-consumer.handler',
		description: 'SessionEndedDLQ SQS Queue Consumer',
		timeout: 30,
		rawProperties: {
			dependsOn: ['SessionEndedDLQ']
		},
		events: [
			{
				sqs: {
					arn: 'arn:aws:sqs:${aws:region}:${aws:accountId}:${self:custom.serviceName}SessionEndedDLQ',
					batchSize: 10,
					maximumBatchingWindow: 100
				}
			}
		]
	}]

// For SQS Resources

	['resource', {
		name: 'SessionEndedQueue',
		resource: {
			Type: 'AWS::SQS::Queue',
			Properties: {
				QueueName: '${self:custom.serviceName}SessionEndedQueue',
				ReceiveMessageWaitTimeSeconds: 20,
				VisibilityTimeout: 60,
				// eslint-disable-next-line max-len
				RedrivePolicy: '{"maxReceiveCount": 5, "deadLetterTargetArn": "arn:aws:sqs:${aws:region}:${aws:accountId}:${self:custom.serviceName}SessionEndedDLQ"}'
			},
			DependsOn: ['TestDLQ']
		}
	}]

	['resource', {
		name: 'SessionEndedDLQ',
		resource: {
			Type: 'AWS::SQS::Queue',
			Properties: {
				QueueName: '${self:custom.serviceName}SessionEndedDLQ',
				ReceiveMessageWaitTimeSeconds: 5,
				VisibilityTimeout: 20,
				MessageRetentionPeriod: 864000
			}
		}
	}]
*/

Full example

// serverless.js

'use strict';

const { helper } = require('sls-helper'); // eslint-disable-line

// Only for SQS
const { SQSHelper } = require('sls-helper-plugin-janis');  // eslint-disable-line

module.exports = helper({
	hooks: [

		['janis.base', {
			serviceCode: 'my-service',
			servicePort: 5000,
			apiSecrets: {
				beta: 'foo',
				qa: 'bar',
				prod: 'baz'
			}
		}],

		'janis.templates',

		['janis.authorizers', {
			accountId: '012345678910'
		}],

		'janis.cors',

		['janis.api', {
			path: '/hello-world',
			authorizer: 'NoClientAuthorizer',
			cors: true
		}],

		['janis.apiList', {
			entityName: 'product',
			authorizer: 'FullAuthorizer',
			cors: true
		}],

		['janis.apiGet', {
			entityName: 'product',
			authorizer: 'FullAuthorizer',
			cors: true
		}]

		['janis.apiPost', {
			entityName: 'product',
			authorizer: 'FullAuthorizer',
			cors: true
		}],

		['janis.apiPut', {
			entityName: 'product',
			authorizer: 'FullAuthorizer',
			cors: true
		}],

		['janis.apiList', {
			entityName: 'otherEntity',
			authorizer: 'FullAuthorizer',
			cors: {
				origins: ['*'], // Open to every origin
				allowCredentials: false
			}
		}],

		['janis.eventListener', {
			serviceName: 'catalog',
			entityName: 'product',
			eventName: 'created',
			mustHaveClient: true
		}],

		['janis.stateMachine', {
			name: 'StateMachineName',
			definition: {
				Comment: 'State Machine Comment',
				StartAt: 'WaitForCall',
				States: {
					WaitForCall: {
						Type: 'Wait',
						SecondsPath: '$.body.wait',
						Next: 'Finish'
					}
				}
			}
		}],

		['janis.functionsVpc', {
			vpcId: 'vpc-11111111',
			subnetIds: [
				'subnet-111111111',
				'subnet-222222222'
			]
		}],

		['janis.functionUrl', {
			subdomainName: 'subSubdomain.subdomain',
			acmCertificate: '${param:acmCertificateId}',
			functions: [
				{
					functionName: 'CustomUrlLambda',
					path: '/customUrl/*'
				}
			]
		}],

		SQSHelper.sqsPermissions
		...SQSHelper.buildHooks({ name: 'ProductToUpdate' })
	]
}, {});

Package Sidebar

Install

npm i sls-helper-plugin-janis

Weekly Downloads

570

Version

9.5.3

License

MIT

Unpacked Size

90.8 kB

Total Files

39

Last publish

Collaborators

  • janiscommerce
  • jormaechea