Raise Cazoo business events
npm install @cazoo/events@cazoo/eventsUsed for raising and parsing Cazoo business events.
Abstracts away EventBridge, which we are using as an event bus.
EventClient.publish Validates and publish an event. It will fail with a validation exception if the event is not valid.
``ts
import { EventClient, DoNotValidator, parse } from '@cazoo/events';
export const someHandler = async (ev, context) => {
const { name, payload } = parse(ev);
const registryARN = proces.env.SCHEMA_REGISTRY_ARN;
/ Implement your Lambda logic here /
// Raise a new event on the shared EventBridge event bus.
const validator = new DynamicSchemaValidator(registryARN);
const client = new EventClient({ context, validator });
const event = {
name: "orderPlaced",
payload: { foo: 'bar' }
};
await client.publish(event)
}
`
It's possible to use an Environment Variable CAZOO_EVENTS_TARGET_EVENT_BUS to use a custom event bus, you can also manually use a
custom event bus using the information below.
If eventBusName parameter is not provided, the default event bus is targeted, instead.
`ts`
const client = new EventClient({
context: myContext,
eventBusName: "custom-event-bus"
});
If you wish to provide a custom event bus as your target, you can also optionally validate the existence of the event bus by using the eventBusValidation boolean as shown below:
`ts`
const client = new EventClient({
context: myContext,
eventBusName: "custom-event-bus",
eventBusValidation: true
})
#### IAM Permissions
If you want to use event bus validation, then you will need the events:DescribeEventBus IAM permission on your Lambda.
Note: If eventBusValidation is set, then the eventBusName parameter or the environment variable CAZOO_EVENTS_TARGET_EVENT_BUS must be provided, else an error will throw
You can provide your own config for the event bridge client the library uses.
`ts`
const client = new EventClient({
context: myContext,
clientConfig: { endpoint: 'http://localhost:3213' }
});
We now have support for runtime validation of events via the EventClient class. This class will dynamically fetch schemas from the Eventbridge Schema Registry and validate messages before they are raised.
`ts
// We use the ARN of the schema registry to look up event schemas
const registryArn = process.env.CAZOO_EVENT_REGISTRY_ARN ||
"arn:aws:schemas:eu-west-1:571578941547:registry/cazoo-events"
const validator = new DynamicSchemaValidator(registryArn)
// We create a client passing a validator and the lambda context
const client = new EventClient({
context,
validator,
});
try {
const result = await client.publish({
name: "deliveryCancelled",
payload: {
orderNumber: "abc-123"
}
});
} catch (e) {
console.log(e.message);
console.log(JSON.stringify(e.errors, null, 2))
}
`
`
/* Yields the following error
data must NOT have additional properties, data must have required property 'order_number'
[
{
"keyword": "additionalProperties",
"instancePath": "",
"schemaPath": "#/additionalProperties",
"params": {
"additionalProperty": "orderNumber"
},
"message": "must NOT have additional properties"
},
{
"keyword": "required",
"dataPath": "",
"instancePath": "#/required",
"params": {
"missingProperty": "order_number"
},
"message": "must have required property 'order_number'"
}
]
*/
`
NOT RECOMMENDED
You can also explicitly disable validation with the DoNotValidator.
`ts`
const validator = new DoNotValidator()
const client = new EventClient({ context, validator });
// This won't throw
const result = await client.publish({
name: "anyOldRubbish",
payload: {
foo: "bar"
}
});
ts
const client = new EventClient({ context, validator, config: { xrayEnabled: true } });
`Also add the xray dependency to your package.json
aws-xray-sdk@3 and make sure you add the required permission to your lambda from the latest AWS documentation https://docs.aws.amazon.com/xray/latest/devguide/aws-xray.html.IAM Permissions
Your lambda will require the following IAM permissions to validate schemas.
$3
`yaml
iamRoleStatements:
- Effect: Allow
Action:
- schemas:DescribeSchema
Resource:
- arn:aws:schemas:${AWS::Region}:${AWS::AccountId}:schema/REGISTRY_NAME/SCHEMA_NAME
- ...
`$3
`hcl
variable "account_id" {}
variable "region" {}
variable "registry_name" {}
variable "schema_name {}data "aws_iam_policy_document" "allow_describe_schema" {
statement {
sid = "AllowDescribeSchema"
actions = [
"schemas:DescribeSchema"
]
resources = [
"arn:aws:schemas:${var.region}:${var.account_id}:schema/${var.registry_name}/${var.schema_name}",
...
]
}
}
resource "aws_iam_policy" "allow_describe_schema" {
name = "allow-describe-schema"
path = "/"
policy = data.aws_iam_policy_document.allow_describe_schema.json
}
attach the policy to your lambda role.
resource "aws_iam_role_policy_attachment" "attach_allow_describe_schema" {
role = aws_iam_role.lambda_execution_role.name
policy_arn = aws_iam_policy.allow_describe_schema.arn
}
``