From b64dcf68797f654a8b5a7d626795e86a7a24e10b Mon Sep 17 00:00:00 2001 From: Ian Cooper Date: Fri, 9 Jul 2021 17:50:01 +0100 Subject: [PATCH 01/76] Add conventions for bindings --- Conventions.md | 301 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 301 insertions(+) create mode 100644 Conventions.md diff --git a/Conventions.md b/Conventions.md new file mode 100644 index 00000000..30ddc573 --- /dev/null +++ b/Conventions.md @@ -0,0 +1,301 @@ +# Conventions +## What is this? +This document describes a set of conventions that implementers may adopt when describing [Channel](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#channelBindingsObject), [Operation](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#operationBindingsObject) or [Message](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#messageBindingsObject) bindings for different protocols. + +## Why Adopt These? +AsyncAPI does not constrain how Bindings are defined, beyond a valid JSON schema. This makes Bindings flexible extension points for implementers. This flexibility is powerful, but it comes at a price in that it can be hard for implementers to understand how to use Bindings consistently, which makes it difficult for those writing tools that work with AsyncAPI to support a range of protocols. + +## What Belongs on a Binding? +The Binding should be used to provide configuration data that a protocol requires. That configuration may be exposed via Message-Oriented-Middleware (MoM) using a Management API that allows code to configure the MoM as described. The fields in a Binding should represent protocol specific metadata, that is not exposed as an existing field on the Channel, Operation or Message objects. + +A Binding may also be used by the providers of SDKs for MoM to provide metadata to configure producers or consumers using that SDK. That is outside the scope of advice here, but SDK owners wishing to use Bindings may follow the general advice here. + +## Effective Bindings +### **Item 1** Use the Extensions Format +Prefer use of the [Bindings Extensions](https://github.com/asyncapi/extensions-catalog) format when defining a binding over raw JSON Schema. + +The Binding Extensions format works with tools because it indicates where in the specification the binding should be used via a Hook. Using a Hook signals clearly to the user of an extension on which of Channel, Operation or Message the binding can be used. Implementers may choose to use author a binding so that the only fields on the binding are those appropriate to the object identified by the Hook. It also makes it possible for tools to determine correctness of an AsyncAPI file by ensuring that the binding is only used where permitted. + +### **Item** 2 Prefer JSON for Bindings +Prefer the use of JSON to define a Binding. + +[The AsyncAPI specification is in JSON](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#format), so using JSON to define the Binding assures consistency of the format of the two. + +Whilst both JSON and YAML are human readable, YAML is more readable. As [YAML is a superset of JSON](https://yaml.org/spec/1.2/spec.html#id2759572) users may prefer to write AsyncAPI files in YAML, benefitting from the improved readability. + +However, as JSON is a subset of YAML, defining the Binding in YAML risks using parts of the specification not supported by JSON. As it is possible to use a binding defined in JSON from YAML (this is true of AsyncAPI in general), authoring a binding in JSON ensures that implementers stick to the subset defined by JSON when defining the Binding. + +Writing the Binding in JSON uses the common subset of JSON and YAML and should be preferred. + +### **Item 3** Support Infrastructure as Code +Design your binding to support Infrastructure as Code (IaC) scenarios, so that it is possible to use the Binding with a [Generator](https://github.com/asyncapi/generator) [template](https://github.com/asyncapi/template-for-generator-templates) to generate code that will allow repeatable infrastructure for asynchronous communication. At a minimum, the binding should support the variables required by the transport's management API to create required infrastructure. + +Not all uses of a Binding have Infrastructure as Code as a goal, and not all parameters to API calls tend to be required, so it is important to avoid using required fields on any bindings where the information is likely needed in IaC or Contract-First scenarios [see Item 4](#item-4-support-contract-first--scaffolding). + +Some transports do not provide a specification of a management API used to create infrastructure but instead have middleware specific APIs. To support a protocol that does not define infrastructure creation as part of its standard, consider a binding for the middleware in addition to the protocol i.e. AMQP 1-0-0. + +### **Item 4** Support Contract First && Scaffolding +Design your binding to support Contract First definition of an endpoint that is later used with [Scaffolding](https://en.wikipedia.org/wiki/Scaffold_(programming)) to generate the skeleton of an application. Contract Fist scenarios requires the binding to support the necessary parameters to either produce or consume messages via the API or SDK. + +Code generation from an AsyncAPI definition, particularly for consumers, is a use case that improves developer productivity and tends to drive adoption. Not all uses of a Binding have later generation of code via Scaffolding as a goal. + +There may be multiple SDKs for a particular protocol, for different languages and frameworks. In many cases the variables required by these targets remain common across the targets and can simply be inferred from the protocol. In this case it is possible to define a common set of fields for a binding that can be used by Scaffolding regardless of the SDK. In other cases, SDKs vary considerably for the middleware. In this case you may prefer to provide a binding for the middleware that facilitates code generation for that middleware. + +### **Item 5** Assume Separate Endpoints Have Separate AsyncAPI Files +Producers and consumers are usually separate apps, they may belong to separate teams, and under models such as pub-sub, there may an architectural goal to decouple producer and consumer by ensuring that each knows about the channel, but not the other. For this reason, you should assume that it will be common to define separate endpoints for the producer and consumer, but that the channel and the message schema will be shared. (Users may use $ref to prevent duplication, but that does not change these guidelines). + +### **Item 6** The Channel Binding Describes the 'Virtual Pipe' +Design your binding to support the separation of the definitions of producer and consumer endpoints. The [Channel Binding](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#channelBindingsObject) should contain the data required to create a channel via [Infrastructure as Code](#item-3-support-infrastructure-as-code). + +```yml +channels: + quux: + subscribe: + summary: Messages about quux + operationId: sendQuux + $ref: "#/components/messages/quuxEvent" + bindings: + amqp: + exchange: + name: myExchange + type: topic + durable: true + autoDelete: false + vhost: / + bindingVersion: 0.1.0 +``` + +```yml +channels: + quux: + subscribe: + summary: Messages about quux + operationId: sendQuux + $ref: "#/components/messages/quuxEvent" + bindings: + kafka: + topic: + partitioner: ConsistentRandom + numOfPartitions: 6 + replicationFactor: 3 +``` + +The Channel Binding should not contain the data required to create a subscription to the channel, or to publish to the channel. Note that the name of the channel for use by middleware is given by the name of the Channel object, which would be 'quux' in the example above. + + +### **Item 7** The Subscribe Operation Binding on a Producer Describes How We Send +Design your binding to support the separation of the definitions of producer and consumer endpoints. The Subscribe [Operation Binding](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#operationBindingsObject) on a producer should contain the data required to publish to a channel via [Infrastructure as Code](#item-3-support-infrastructure-as-code). Commonly, there may be reliability and security requirements for the producer. The binding should also contain any data required to support [Contract First](#item-4-support-contract-first--scaffolding) development. + +```yml +channels: + quux: + subscribe: + summary: Messages about quux + operationId: sendQuux + $ref: "#/components/messages/quuxEvent" + bindings: + amqp: + producer: + confirmSelect: true + bindings: + amqp: + exchange: + name: myExchange + type: topic + durable: true + autoDelete: false + vhost: / + bindingVersion: 0.1.0 +``` + +```yml +channels: + quux: + subscribe: + summary: Messages about quux + operationId: sendQuux + $ref: "#/components/messages/quuxEvent" + kafka: + producer: + transactionalId: Foo + replication: Acks.All + batchMessages: 10 + retries: 3 + queue_strategy: fifo + max_in_flight: 5 + + bindings: + kafka: + topic: + partitioner: ConsistentRandom + numOfPartitions: 6 + replicationFactor: 3 +``` + +Note that the producer defines what it exposes - a subscribe operation because it can be subscribed to - so the middleware 'publication' is defined on the consumer's publish operation. This catches out some users of AsyncAPI. + +### **Item 8** The Publish Operation Binding on a Consumer Describes How We Receive +Design your binding to support the separation of the definitions of producer and consumer endpoints. The Publish [Operation Binding](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#operationBindingsObject) on a consumer should contain the data required to receive from a channel via [Infrastructure as Code](#item-3-support-infrastructure-as-code). Commonly, a subscription must be made to the channel to route messages to the consumer. There may also be security requirements for the consumer to receive messages. Where middleware uses a queue, this will typically be defined as part of the Operation Binding on the consumer. The binding should also contain any data required to support [Contract First](#item-4-support-contract-first--scaffolding) development. + +```yml +channels: + quux: + publish: + summary: Messages about quux + operationId: sendQuux + $ref: "#/components/messages/quuxEvent" + bindings: + amqp: + queue: + name: myQueue + type: topic + durable: true + autoDelete: false + bindingVersion: 0.1.0 + bindings: + amqp: + exchange: + name: myExchange + type: topic + durable: true + autoDelete: false + vhost: / + bindingVersion: 0.1.0 +``` + +```yml +channels: + quux: + publish: + summary: Messages about quux + operationId: sendQuux + $ref: "#/components/messages/quuxEvent" + bindings: + kafka: + consumer: + group: myGroup + maxPollIntervalInMs: 100 + enableAutoOffsetStore: true + enableAutoCommit: true + bindings: + kafka: + topic: + partitioner: ConsistentRandom + numOfPartitions: 6 + replicationFactor: 3 +``` + + +Note that the consumer defines what it exposes - a publish operation because it can be published to - so the middleware 'subscription' is defined on the consumer's publish operation. This catches out some users of AsyncAPI. + +### **Item 9** Define Protocol Required Message Properties as Schema not Bindings +A [Message](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#messageBindingsObject) consists of headers (metadata) and payload (data); AsyncAPI also defines some common metadata values as fields of a Message, for example correlationId. The headers are defined as a [Schema](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#schemaObject) object under [Components](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#componentsObject). A payload may be of any type, but defaults to JSON Schema. [MessageTraits](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#messageTraitObject) allow the definition of metadata values related to a protocol once, rather than per message, and simplify the use of protocol related message metadata when defining message headers. + +Where a protocol defines metadata that forms part of the message sent via middleware it should be defined as part of the header schema (potentially as MessageTraits), and where the protocol defines data (or transmits metadata in the payload) it should be defined as part of the payload. Note that the payload does not support MessageTraits. + +Tooling to validate that messages match the schema will expect to verify against the schema of the message payload and headers, putting message metadata into a Message Binding makes this harder as tooling must know to look there as well. + +Implementers of producers or consumers are also likely to assume that the the can refer to #/Components/Schema to understand payloads and headers, and adding metadata into bindings in addition makes it harder to comprehend the schema of a message. + +A [Message Binding](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#messageBindingsObject) should be used to define metadata about the protocol's message format that is used for [Infrastructure as Code](#item-3-support-infrastructure-as-code) or [Scaffolding](#item-4-support-contract-first--scaffolding). Don't use the Message Bindings to describe what is sent; use the Message Binding to describe how it is sent, if required. + +```yml +channels: + quux: + subscribe: + summary: Messages about quux + operationId: sendQuux + $ref: "#/components/messages/quuxEvent" + +... + +components: + schemas: + quux: + type: object + properties: + quuxDetails: + type: string + amqpBasicProperties: + type: object + properties: + content_encoding: + type: string + delivery-mode: + type: integer + minimum: 0 + maximum: 1 + priority: + type: integer + minimum: 0 + maximum: 9 + correlation-id: + type: string + reply-to: + type: string + expiration: + type: string + message-id: + type: string + timestamp: + type: string + type: + type: string + user-id: + type: string + app-id: + type: string + + messages: + quuxEvent: + summary: Raised when a quux occurs. + description: When a quux happens, describes the quux + contentType: application/json + payload: + $ref: "#/components/schemas/quux" + traits: + $ref: "#/components/schemas/amqpBasicProperties" + + +``` + +### **Item 10** Be Consistent with Other Protocols +Design your binding with the possibility that a producer might expose a message over different bindings - so as to support a wider range of consumers. By following the guidelines in this document your binding should be compatible with other bindings, and simplify the development of tooling that supports those because they operate at the same level. + +```yml +channels: + quux: + subscribe: + summary: Messages about quux + operationId: sendQuux + $ref: "#/components/messages/quuxEvent" + bindings: + amqp: + producer: + confirmSelect: true + kafka: + producer: + transactionalId: Foo + replication: Acks.All + batchMessages: 10 + retries: 3 + queue_strategy: fifo + max_in_flight: 5 + + bindings: + amqp: + exchange: + name: myExchange + type: topic + durable: true + autoDelete: false + vhost: / + bindingVersion: 0.1.0 + kafka: + topic: + partitioner: ConsistentRandom + numOfPartitions: 6 + replicationFactor: 3 +``` + + From c322a0b8602782fda83e95b41b6bbebb1eccba3e Mon Sep 17 00:00:00 2001 From: Ian Cooper Date: Wed, 15 Sep 2021 17:00:33 +0100 Subject: [PATCH 02/76] Create bindings for AWS messaging infrastructure --- sns/README.md | 271 ++++++++++++++++++++++++++++++++++++- sns/SNS-HTTP.png | Bin 0 -> 50765 bytes sns/SNS-SQS-Pub-Sub.png | Bin 0 -> 47278 bytes sqs/README.md | 216 +++++++++++++++++++++++++++-- sqs/SNS-SQS-Pub-Sub.png | Bin 0 -> 47278 bytes sqs/SQS-Point-To-Point.png | Bin 0 -> 37204 bytes 6 files changed, 475 insertions(+), 12 deletions(-) create mode 100644 sns/SNS-HTTP.png create mode 100644 sns/SNS-SQS-Pub-Sub.png create mode 100644 sqs/SNS-SQS-Pub-Sub.png create mode 100644 sqs/SQS-Point-To-Point.png diff --git a/sns/README.md b/sns/README.md index 6a0f81d9..ad9cded1 100644 --- a/sns/README.md +++ b/sns/README.md @@ -15,23 +15,286 @@ Current version is `0.1.0`. This object MUST NOT contain any properties. Its name is reserved for future use. - - ## Channel Binding Object -This object MUST NOT contain any properties. Its name is reserved for future use. +This object contains information about the channel representation in SNS. + +We represent an AsyncAPI Channel with a Topic in SNS. The bindings here allow definition of a topic within SNS. We provide properties on the binding that allow creation of a topic in infrastructure-as-code scenarios. Be aware that although the binding offers that flexibility, it may be more maintainable to specify properties such as SNS Access Control Policy outside of AsyncAPI. + +SNS supports many optional properties. To mark a channel as SNS, but use default values for the channel properties, just use an empty object {}. + +### Fields + +|Field Name | Type | Description| +|---|:---:|---| +| `type` | [ordering](#ordering)| **Optional.** By default, we assume an unordered SNS topic. This field allows configuration of a FIFO SNS Topic. | +| `policy` |[policy](#policy) | **Optional.** The security policy for the SNS Topic | +|`bindingVersion` | string | **Optional**, defaults to `latest`. The version of this binding.| + +### Schemas + +#### Ordering +|Field Name | Type | Description| +|---|:---:|---| +| `type` | string one of: standard or FIFO | **Required.** What type of SNS Topic is this? | +| `contentBasedDepulication` | boolean | **Optional.** True to turn on de-duplication of messages for a channel.| + +#### Policy +|Field Name | Type | Description| +|---|:---:|---| +| `statements` | [Statement](#statement) | **Required.** An array of Statement objects, each of which controls a permission for this topic | + +#### Statement +|Field Name | Type | Description| +|---|:---:|---| +| `effect` | string |**Required.** Either "Allow" or "Deny"| +| `principal` | string or array of string |**Required.** The AWS account or IAM user to whom this statement applies| +| `action` | string or array of string |**Required.** The SNS permission being allowed or denied e.g. sns:Publish| + +##### Examples +Just use defaults +```yaml +channels: + user-signedup: + description: A user has signed up to our service + bindings: + sns: {} +``` + +Minimal definition, just policy + +```yaml +channels: + user-signedup: + description: A user has signed up to our service + bindings: + sns: + policy: + statements: + - effect : Allow + principal: * + action: SNS:Publish +``` ## Operation Binding Object -This object MUST NOT contain any properties. Its name is reserved for future use. +This object contains information operation binding in SNS. + +We represent SNS producers via a **subscribe** Operation Object. In simple cases this may not require configuration, and can be shown as an empty SNS Binding Object i.e. {} if you need to explicitly indicate how a producer publishes to the channel. + +We represent SNS consumers via a **publish** Operation Object. These consumers need an SNS Subscription that defines how they consume from SNS i.e. the protocol that they use, and any filters applied. + +The SNS binding does not describe the receiver.If you wish to define the receiver, add a **publish** Operation Binding Object for that receiver. For example, if you send message to an SQS queue from an SNS Topic, you would add a protocol of 'sqs' and an Identifier object for the queue. That identifier could be an ARN of a queue defined outside of the scope of AsyncAPI, but if you wanted to define the receiver you would use the name of a queue defined in an SQS Binding on the **publish** Operation Binding Object. + +We support an array of consumers via the **consumers** field. This allows you to represent multiple protocols consuming an SNS Topic in one file. You may also use it for multiple consumers with the same protocol, instead of representing each consumer in a separate file. + +### Fields + +| Field Name | Type | Applies To | Description | +|---|:---:|:---:|---| +| `topic` | [identifier](#identifier) |Publish, Subscribe| **Optional.** Often we can assume that the SNS Topic is the channel name-we provide this field in case the you need to supply the ARN, or the Topic name is not the channel name in the AsyncAPI document.| +| `consumers` | [[Consumer](#consumer)] |Publish| **Required.** The protocols that listen to this topic and their endpoints.| +| `deliveryPolicy` | [deliveryPolicy](#delivery-policy) |Subscribe| **Optional.** Policy for retries to HTTP. The field is the default for HTTP receivers of the [SNS Topic](https://docs.aws.amazon.com/sns/latest/api/API_CreateTopic.html) which may be overridden by a specific consumer.| +|`bindingVersion` | string |Publish, Subscribe| **Optional**, defaults to `latest`. The version of this binding.| + +### Schemas + +#### Consumer + +| Field Name | Type | Description | +|---|:---:|---| +| `protocol` |string, one of: http, https, email, email-json, sms, sqs, application, lambda, firehose | **Required.** What protocol will this endpoint receive messages by.| +| `endpoint` |[identifier](#identifier)| **Required.** Where are messages being delivered to?| +| `filterPolicy` | [filterPolicy](#filter-policy) | **Optional.** Only receive a subset of messages from the channel, determined by this policy.| +| `rawMessageDelivery` | boolean | **Required.** If *true* AWS SNS attributes are removed from the body, and for SQS, SNS message attributes are copied to SQS message attributes. If *false* the SNS attributes are included in the body. | +| `reDrivePolicy` | [redrivePolicy](#redrive-policy) | **Optional.** Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue. | +| `deliveryPolicy` | [deliveryPolicy](#delivery-policy) | **Optional.** Policy for retries to HTTP. The parameter is for that [SNS Subscription](https://docs.aws.amazon.com/sns/latest/api/API_Subscribe.html)and overrides any policy on the [SNS Topic](https://docs.aws.amazon.com/sns/latest/api/API_CreateTopic.html).| +| `displayName` | string |**Optional.** The display name to use with an SMS subscription | + + +#### Delivery Policy +|Field Name | Type | Description| +|---|:---:|---| +| `minDelayTarget` | integer | **Optional.** The minimum delay for a retry in seconds | +| `maxDelayTarget` | integer | **Optional.** The maximum delay for a retry in seconds | +| `numRetries` | integer | **Optional.** The total number of retries, including immediate, pre-backoff, backoff, and post-backoff retries | +| `numNoDelayRetries` | integer | **Optional.** The number of immediate retries (with no delay) | +| `numMinDelayRetries` | integer | **Optional.** The number of immediate retries (with no delay) | +| `numMaxDelayRetries` | integer | **Optional.** The number of post-backoff phase retries, with the maximum delay between retries | +| `backoffFunction` | string, one of: arithmetic, exponential, geometric or linear | **Optional.** The algorithm for backoff between retries | +| `maxReceivesPerSecond` | integer | **Optional.** The maximum number of deliveries per second, per subscription | + +#### Filter Policy +|Field Name | Type | Description| +|---|:---:|---| +| `attributes` |Map(string, array or string or object) | **Required.** A map of a message attribute to an array of possible matches. The match may be a simple string for an exact match, but it may also be an object that represents a constraint and values for that constraint | + +#### Identifier +|Field Name | Type | Description| +|---|:---:|---| +|`url` |string| **Optional.** The endpoint is a URL | +|`email` |string| **Optional.** The endpoint is an email address | +|`phone` |string| **Optional.** The endpoint is a phone number| +|`arn` |string| **Optional.** The target is an [ARN](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html). For example, for SQS, the identifier may be an ARN, which will be of the form: ["arn:aws:sqs:{region}:{account-id}:{queueName}"](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html)| +|`name` |string| **Optional.** The endpoint is identified by a name, which corresponds to an identifying field called 'name' of a binding for that protocol on this **publish** Operation Object. For example, if the protocol is 'sqs' then the name refers to the name field **sqs** binding. We don't use $ref because we are referring, not including. | + +We provide an Identifer Object to support providing the identifier of an externally defined endpoint for this SNS *publication* to target, or an endpoint on another binding against this Operation Object (via the name field). + +#### Redrive Policy + +|Field Name | Type | Description| +|---|:---:|---| +| `deadLetterQueue` |[Identifier](#identifier)| **Required.** The SQS queue to use as a dead letter queue (DLQ) | +| `maxReceiveCount` |integer| **Optional.** The SQS queue to use as a dead letter queue (DLQ). Note that you may have a Redrive Policy to put messages that cannot be delivered to an SQS queue, even if you use another protocol to consume messages from the queue, so it is defined at the level of the SNS Operation Binding Object in a Consumer Object (and is applied as part of an [SNS Subscription](https://docs.aws.amazon.com/sns/latest/dg/sns-create-subscribe-endpoint-to-topic.html)). The SQS Binding describes how to define an SQS Binding that supports defining the target SQS of the Redrive Policy. | + +### Examples + +#### SNS to SQS Pub-Sub + +[](SNS-SQS-Pub-Sub.png) + +We are producing to an SNS channel + +```yaml +channels: + user-signedup: + description: A user has signed up for our service + binding : + sns: {} # Indicates that the channel is an SNS Topic + subscribe: + operationId: sendMessage + description: send messages to the topic + bindings: + sns: + policy: + statements: + - effect : Allow + principal: * + action: SNS:Publish +``` + +We are consuming an SNS channel, using an SQS queue. A separate file specifies the producer, and has the SNS Bindings for the channel. For this reason we do not repeat the SNS binding information for the channel here, to avoid duplicated definitions diverging. Instead we just define the **publish** Operation Binding. + +In this version, the SQS queue is defined elsewhere, and we just reference via its ARN. It is worth noting that this couples the specification to the AWS *region* and *account*, which are part of the ARN, and if we moved the queue to a new region or account was this specification would need to be updated to reflect that. + + +```yaml +channels: + user-signedup: + description: A user has signed up for our service + publish: + operationId: receiveMessage + description: receive messages from the topic + bindings: + sns: + consumers: + - protocol: sqs + endpoint: + arn: arn:aws:sq:Aus-west-2:123456789012:UserSignedUpQueue + rawMessageDelivery: true +``` + +We are consuming an SNS channel, using an SQS queue. A separate file specifies the producer, and has the SNS Bindings for the channel. For this reason we do not repeat the SNS binding information for the channel here, to avoid duplicated definitions diverging. Instead we just define the **publish** Operation Binding. + +In this version, the SQS queue is defined in this file, and we reference it by name. For brevity that definition is not shown here. See the SQS Binding Object for more. + +```yaml +channels: + user-signedup: + description: A user has signed up for our service + publish: + operationId: receiveMessage + description: receive messages from the topic + bindings: + sns: + consumers: + - protocol: sqs + endpoint: + name: user-signedup-queue # refers to a queue defined in this file, but not shown in this example + rawMessageDelivery: true + filterPolicy: + attributes: + reason: + anything-but: password-reset + reDrivePolicy: + deadLetterQueue: + name: user-signedup-queue-dlq # refers toa queue defined in this file, but not show in this example +``` + +#### SNS to HTTP Pub Sub + +[](SNS-HTTP.png) + +We are producing to an SNS channel. + +In this version, we define a default delivery policy for any HTTP based consumers + +```yaml +channels: + user-signedup: + description: A user has signed up for our service + bindings: + sns: + policy: + statements: + - effect : Allow + principal: * + action: SNS:Publish + subscribe: + operationId: sendMessage + description: send messages to the topic + bindings: + sns: + deliveryPolicy: + minDelayTarget: 1 + maxDelayTarget: 60 + numRetries: 50 + numNoDelayRetries: 3 + numMinDelayRetries: 2 + numMaxDelayRetries: 35 + backoffFunction: exponential + maxReceivesPerSecond: 10 +``` +We are consuming an SNS channel, using an HTTP endpoint, which is defined in this AsyncAPI file. For brevity we do not show an http endpoint here. The delivery policy here is defined for the http consumer and overrides any policy set by the producer +```yaml +channels: + user-signedup: + description: A user has signed up for our service + bindings: + sns: {} # Indicates that the channel is an SNS Topic, but assumes defined by producer + publish: + operationId: receiveMessage + description: receive messages from the topic + bindings: + sns: + - protocol: http + endpoint: + url: http://login.my.com/user/new + filterPolicy: + attributes: + reason: + anything-but: password-reset + deliveryPolicy: + minDelayTarget: 1 + maxDelayTarget: 120 + numRetries: 30 + numNoDelayRetries: 3 + numMinDelayRetries: 2 + numMaxDelayRetries: 25 + backoffFunction: exponential + maxReceivesPerSecond: 20 + reDrivePolicy: + deadLetterQueue: + name: user-signedup-queue-dlq # refers toa queue defined in this file, but not show in this example +``` diff --git a/sns/SNS-HTTP.png b/sns/SNS-HTTP.png new file mode 100644 index 0000000000000000000000000000000000000000..72e52c730be93cbf230db6336eb611958fc3adf2 GIT binary patch literal 50765 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 Q7T||5IcxkFeI@Dt02psn>Hq)$ literal 0 HcmV?d00001 diff --git a/sqs/README.md b/sqs/README.md index 8bccca3f..d8f7e2aa 100644 --- a/sqs/README.md +++ b/sqs/README.md @@ -2,36 +2,236 @@ This document defines how to describe SQS-specific information on AsyncAPI. +SQS can be used both stand-alone as a point-to-point and paired with SNS and as a publish-subscribe channel (where SQS is the endpoint that SNS delivers messages to). For this reason we define a Queue schema, and reference that schema from both a Channel Binding Object and a **publish** Operation Binding Object. + +For point-to-point scenarios, use the Channel Binding Object, as producers send to the queue and consumers receive from it directly. + +For publish-subscribe scenarios, use as a **publish** Operation Binding Object, as the producer sends to SNS and the consumer receives via SQS. + ## Version Current version is `0.1.0`. - ## Server Binding Object This object MUST NOT contain any properties. Its name is reserved for future use. - - -## Channel Binding Object - -This object MUST NOT contain any properties. Its name is reserved for future use. - +## Channel Binding Object + +Use the Channel Binding Operation for Point-to-Point SQS channels. + +There are three likely scenarios for use of the Channel Binding Object: + +- One file defines both publish and subscribe operations, for example if we were implementing the work queue pattern to offload work from an HTTP API endpoint to a worker process. In this case the channel would be defined on the Channel Object in that single file. (Not illustrated above). +- The producer and consumer both have an AsyncAPI specification file, and the producer is raising an event, for example interop between microservices, and the producer 'owns' the channel definition and thus has the SQS Binding on its Channel Object. (Illustrated above). +- The producer and consumer both have an AsyncAPI specification file, and the consumer receives commands, for example interop between microservices, and the consumer 'owns' the channel definition and thus has the SQS Binding on its Channel Object. (Not illustrated above). + +An SQS queue can set up a Dead Letter Queue as part of a Redelivery Policy. To support this requirement, the Channel Binding Object allows you to define both a Queue Object to use as the Channel or target in a *publish* Operation and a Dead Letter Queue. You can then refer to the Dead letter Queue in the Redrive Policy using the Identifier Object and setting the *name* field to match the *name* field of your Dead Letter Queue Object. (If you define the DLQ externally, the Identifier also supports an ARN). + +### Fields +|Field Name | Type | Description| +|---|:---:|---| +| `queue` | [Queue](#queue)| **Required.** A definition of the queue that will be used as the channel. | +| `deadLetterQueue` | [Queue](#queue)| **Optional.** A definition of the queue that will be used as the channel. | +|`bindingVersion` | string | **Optional**, defaults to `latest`. The version of this binding.| + +### Schemas + +#### Queue +|Field Name | Type | Description| +|---|:---:|---| +|$ref | `string` | Allows for an external definition of a queue. The referenced structure MUST be in the format of a [Queue](#queue). If there are conflicts between the referenced definition and this Queue's definition, the behavior is *undefined*.| +| `name` | string | **Required.** The name of the queue. When an [SNS Operation Binding Object]() references an SQS queue by name, the identifier should be the one in this field.| +| `type` | string one of: fifo, standard | **Required.** Is this a FIFO queue or a standard queue? | +| `deliveryDelay` | integer | **Optional.** The number of seconds to delay before a message sent to the queue can be received. used to create a *delay queue*. Range is 0 to 15 minutes. Defaults to 0. | +| `visibilityTimeout` |integer| **Optional.** The length of time, in seconds, that a consumer locks a message - hiding it from reads - before it is unlocked and can be read again. Range from 0 to 12 hours. Defaults to 30 seconds. | +| `receiveMessageWaitTime` |integer| **Optional.** Determines if the queue uses [short polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html) or [long polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html). On a 0 (the default) the queue reads available messages and returns immediately. On a non-zero integer, long polling waits the specified number of seconds for messages to arrive before returning. | +| `messageRetentionPeriod` |integer| **Optional.** How long to retain a message on the queue, unless deleted, in days. The rang is 1 minute to 14 days. The default is 4 days. | +| `reDrivePolicy` | [Redrive Policy](#redrive-policy) | **Optional.** Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue.| +| `policy` |[Policy](#policy) | **Optional.** The security policy for the SQS Queue | + +#### Identifier +|Field Name | Type | Description| +|---|:---:|---| +|`arn` |string| **Optional.** The target is an [ARN](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html). For example, for SQS, the identifier may be an ARN, which will be of the form: ["arn:aws:sqs:{region}:{account-id}:{queueName}"](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html)| +|`name` |string| **Optional.** The endpoint is identified by a name, which corresponds to an identifying field called 'name' of a binding for that protocol on this **publish** Operation Object. For example, if the protocol is 'sqs' then the name refers to the name field **sqs** binding| + +#### Policy +|Field Name | Type | Description| +|---|:---:|---| +| `Statements` | [Statement](#statement) | **Required.** An array of Statement objects, each of which controls a permission for this topic | + +#### Redrive Policy +|Field Name | Type | Description| +|---|:---:|---| +| `deadLetterQueue` |[Identifier](#identifier)| **Required.** The SQS queue to use as a dead letter queue (DLQ) | +| `maxReceiveCount` |integer| **Optional.** The SQS queue to use as a dead letter queue (DLQ) + +#### Statement +|Field Name | Type | Description| +|---|:---:|---| +| `effect` | string |**Required.** Either "Allow" or "Deny"| +| `principal` | string or array of string |**Required.** The AWS account or IAM user to whom this statement applies| +| `action` | string or array of string |**Required.** The SNS permission being allowed or denied e.g. sns:Publish| ## Operation Binding Object -This object MUST NOT contain any properties. Its name is reserved for future use. +### SQS Point-To-Point + +Because we have defined Queue as part of the Channel Binding Binding object, we do not require Binding information for the **publish** Operation Object of the **subscribe** Operation Object. You can use an empty Queue object ({}) to denote the Binding on the Operation Object, if you want to indicate the protocol used to send or receive for generation purposes such as Infrastructure As Code. + +### SNS to SQS Pub-Sub + +Use the Operation Binding Object when SQS is listening to an SNS Topic. In this case we need to define both an SQS Operation Binding Objects on the receiver **publish** Operation Object to represent the queue definition and we need to define an SNS Operation Binding Object to define the Subscription to SNS that makes your queue a receiver of that endpoint. + +Assuming you have separate AsyncAPI specifications for the producer and the consumer, we would assume the following bindings would appear for an SNS producer and an SQS consumer. +Producer: SNS Channel Binding Object, SNS **subscribe** Operation Binding Object [if required] +Consumer: SNS **publish** Operation Binding Object, SQS **publish** Operation Binding Object +- We assume that the SNS binding information only needs to be present in the producer file (although defining it in both is allowable) and any infrastructure as code dependencies can recognize this. + + +On an Operation Binding Object we support an array of Queue objects. Members of this array may be Queue Objects that define the *endpoint* field required by an [SNS Operation Object]() delivering by the SQS protocol or Queue Objects that define the Dead Letter Queue used by either the Redrive Policy of the SNS Subscription (see the SNS Binding Object) or the [Redrive Policy of the SQS Queue](#redrive-policy). The name of the Queue Object is used by an Identifier field on either the *endpoint* field of the SNS Operation Object of *deadLetterQueue* on the Redrive Policy to identify the required member of this array. + + +### Fields +|Field Name | Type | Description| +|---|:---:|---| +| `queues` | [[Queue](#queue)]| **Required.** Queue objects that are either the *endpoint* for an SNS Operation Binding Object, or the *deadLetterQueue* of the SQS Operation Binding Object | +|`bindingVersion` | string | **Optional**, defaults to `latest`. The version of this binding.| + +### Examples + +#### SQS Point-To-Point + +[](SQS-Point-To-Point.png) + +In this example, we are using SQS for a point-to-point channel. For this example, we assume that we are defining two microservices that communicate over a shared SQS channel, with the consumer receiving events over that channel and the producer owning the channel definition. + +The producer file would look like this: + +```yaml +channels: + user-signedup: + bindings: + sqs: + queue: + name: user-signedup-queue + type: standard + receiveMessageWaitTime: 4 + reDrivePolicy: + deadLetterQueue: + name: user-signedup-dlq + policy: + statements: + - effect : Allow + principal: * + action: Sqs:SendMessage + - effect : Allow + principal: * + action: Sqs:ReceiveMessage + deadLetterQueue: + name: user-signedup-dlq + messageRetentionPeriod: 1209600 + type: standard + subscribe: + operationId: sendMessage + description: sends messages when a user has signed up + bindings: + sqs: {} + +``` +In this case we can minimize duplicated information by omitting the binding in our specification, and assume it is picked up from the producer file. We can use an empty object to indicate the SQS Binding on the **publish** Operation Object, if need a marker for generation, otherwise we could omit the Operation Binding Object. + +```yaml +channels: + user-signedup: + publish: + operationId: receiveMessage + description: receives a messages when a user has signed up + bindings: + sqs: {} + +``` + +#### SNS to SQS Pub-Sub + +[](SNS-SQS-Pub-Sub.png) + +In this example, we are using SNS for the channel, and SQS to receive from SNS. + + +The producer files looks like this (see the [SNS Binding]() for more). + +```yaml +channels: + user-signedup: + description: A user has signed up for our service + binding : + sns: {} # Indicates that the channel is an SNS Topic + subscribe: + operationId: sendMessage + description: send messages to the topic + bindings: + sns: + policy: + statements: + - effect : Allow + principal: * + action: SNS:Publish +``` + +And the consumer file would look like this. Note that for simplicity, we choose not to repeat the SNS Binding on the Consumer as it does not 'own' the channel. + + +```yaml +channels: + user-signedup: + description: A user has signed up for our service + publish: + operationId: receiveMessage + description: receive messages from the topic + bindings: + sns: + consumers: + - protocol: sqs + endpoint: + name: user-signedup-queue + rawMessageDelivery: true + filterPolicy: + attributes: + reason: + anything-but: password-reset + reDrivePolicy: + deadLetterQueue: + name: user-signedup-queue-dlq + sqs: + queues: + - name: user-signedup-queue + type: standard + receiveMessageWaitTime: 4 + policy: + statements: + - effect : Allow + principal: * + action: Sqs:SendMessage + - effect : Allow + principal: * + action: Sqs:ReceiveMessage + - name: user-signedup-dlq + messageRetentionPeriod: 1209600 + type: standard +``` diff --git a/sqs/SNS-SQS-Pub-Sub.png b/sqs/SNS-SQS-Pub-Sub.png new file mode 100644 index 0000000000000000000000000000000000000000..033d6de7f4b827bc0f53502991fb486a087b3931 GIT binary patch literal 47278 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 Q7T||5IcxkFeI@Dt02psn>Hq)$ literal 0 HcmV?d00001 diff --git a/sqs/SQS-Point-To-Point.png b/sqs/SQS-Point-To-Point.png new file mode 100644 index 0000000000000000000000000000000000000000..a94cfc7b95d2781110ce82cd453c21bf43e30499 GIT binary patch literal 37204 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 literal 0 HcmV?d00001 From 0d2956aec162a1cff73adf097f87d59ba402adcf Mon Sep 17 00:00:00 2001 From: Ian Cooper Date: Thu, 16 Sep 2021 14:23:56 +0100 Subject: [PATCH 03/76] Missing ttags; typos --- .DS_Store | Bin 0 -> 8196 bytes sns/README.md | 3 ++- sqs/README.md | 9 +++++---- 3 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..ea4dd271710dee1492830a432326f9b1cc97223e GIT binary patch literal 8196 zcmeHMNo*WN6#d_8R~B3jPVAoGWQdi-gfX!#Vta6wu|0|7EXp!o6BDOrx)Zl(ciYoF zo;b#6kU+T*1PH_?A)(wt$O#0waA8pdVi5|02;~45jtB%2C&aI=9+TLyxB*eRq^eg{ z|Np7_zg~Cww*dgVb9xIv9RMg)1@h(8+@=V*sEbNTFjG#5WDglD?Kl>7p>&aQI1xr5 zj6fKHFalu&!U+5?A|NhmD#{Y~zLbV-7=bVXcVz^``yonIU?RYRME})6jh_M#meI6d zsLw@*FdASYz=A}QP(f)*C`~a)F;JS*d^FHY1Xz$L%>jet1A~<@$WYKtLaJ0biL;0Z?UAbth}O9QI;vo zRxW!qHSXk7p62D;ZY_IUj1Ftwcsl6!(+7e1zLp*|jr2YjNGi@X58=Ja8Dx*WD ztvmT{Cui%f|2ruuP!y)HFgYM-5B!%xNR3 zd4@a2t6XxkFXPyUv&J;JG?a0y+=NY%>WpS(a-?i@SyswCYq-OnamEw9W3H3+dVIxU zlWfJ@7+)pq4^4WeW4nV!)+J=@tre^5H*9*adD|nqlGj$=Q^l)SF?Ni?VSDB&)5s3w zP2C$G(cFw->!y8rXxenmv}N?$+JsS!M;N=drnYXS8d2{niWZtEyg?bxrOm0F>CO0S ztXr?LQJr>v(9y*zI)7JTzNBHjsvZ}To~%Kwt|xMpWBrfOIdYe_ zAU598%G3c%OB)u~nKWx_XX?(yRG84=PhU8h|&BpT&m`(bEEG|LeecZ&)!*a>^!7-Wd+d3XlS!?W-j zT!72)4txNgz-RCUd^mihxieGj$h;V za)%{FvL2MlzxHTHCjG&7b6g zv%8r@K64~Be99Cl;UC^DJQSy`M%J?WrMNsmj5E$Cf;PNTYDXg*6k-bZsiHrv%3E2BLiFV2Qu;7!V?_ zFYYDwrLZ3daR^6MZ6I+6eHUi$n0o$O+`_b>us1pXlcSe8sByGd!Om%PZe zqf}2)6-DS3B>E=Q_~|&IpN`type` | [ordering](#ordering)| **Optional.** By default, we assume an unordered SNS topic. This field allows configuration of a FIFO SNS Topic. | | `policy` |[policy](#policy) | **Optional.** The security policy for the SNS Topic | +| `tags` |Object | **Optional.** Key-value pairs that represent AWS tags on the topic. | |`bindingVersion` | string | **Optional**, defaults to `latest`. The version of this binding.| ### Schemas @@ -196,7 +197,7 @@ channels: consumers: - protocol: sqs endpoint: - arn: arn:aws:sq:Aus-west-2:123456789012:UserSignedUpQueue + arn: arn:aws:sqs:us-west-2:123456789012:UserSignedUpQueue rawMessageDelivery: true ``` diff --git a/sqs/README.md b/sqs/README.md index d8f7e2aa..afa1d671 100644 --- a/sqs/README.md +++ b/sqs/README.md @@ -28,9 +28,9 @@ Use the Channel Binding Operation for Point-to-Point SQS channels. There are three likely scenarios for use of the Channel Binding Object: -- One file defines both publish and subscribe operations, for example if we were implementing the work queue pattern to offload work from an HTTP API endpoint to a worker process. In this case the channel would be defined on the Channel Object in that single file. (Not illustrated above). -- The producer and consumer both have an AsyncAPI specification file, and the producer is raising an event, for example interop between microservices, and the producer 'owns' the channel definition and thus has the SQS Binding on its Channel Object. (Illustrated above). -- The producer and consumer both have an AsyncAPI specification file, and the consumer receives commands, for example interop between microservices, and the consumer 'owns' the channel definition and thus has the SQS Binding on its Channel Object. (Not illustrated above). +- One file defines both publish and subscribe operations, for example if we were implementing the work queue pattern to offload work from an HTTP API endpoint to a worker process. In this case the channel would be defined on the Channel Object in that single file. +- The producer and consumer both have an AsyncAPI specification file, and the producer is raising an event, for example interop between microservices, and the producer 'owns' the channel definition and thus has the SQS Binding on its Channel Object. +- The producer and consumer both have an AsyncAPI specification file, and the consumer receives commands, for example interop between microservices, and the consumer 'owns' the channel definition and thus has the SQS Binding on its Channel Object. An SQS queue can set up a Dead Letter Queue as part of a Redelivery Policy. To support this requirement, the Channel Binding Object allows you to define both a Queue Object to use as the Channel or target in a *publish* Operation and a Dead Letter Queue. You can then refer to the Dead letter Queue in the Redrive Policy using the Identifier Object and setting the *name* field to match the *name* field of your Dead Letter Queue Object. (If you define the DLQ externally, the Identifier also supports an ARN). @@ -48,13 +48,14 @@ An SQS queue can set up a Dead Letter Queue as part of a Redelivery Policy. To s |---|:---:|---| |$ref | `string` | Allows for an external definition of a queue. The referenced structure MUST be in the format of a [Queue](#queue). If there are conflicts between the referenced definition and this Queue's definition, the behavior is *undefined*.| | `name` | string | **Required.** The name of the queue. When an [SNS Operation Binding Object]() references an SQS queue by name, the identifier should be the one in this field.| -| `type` | string one of: fifo, standard | **Required.** Is this a FIFO queue or a standard queue? | +| `type` | string one of: fifo, standard | **Required.** Is this a FIFO queue or a standard queue? | | `deliveryDelay` | integer | **Optional.** The number of seconds to delay before a message sent to the queue can be received. used to create a *delay queue*. Range is 0 to 15 minutes. Defaults to 0. | | `visibilityTimeout` |integer| **Optional.** The length of time, in seconds, that a consumer locks a message - hiding it from reads - before it is unlocked and can be read again. Range from 0 to 12 hours. Defaults to 30 seconds. | | `receiveMessageWaitTime` |integer| **Optional.** Determines if the queue uses [short polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html) or [long polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html). On a 0 (the default) the queue reads available messages and returns immediately. On a non-zero integer, long polling waits the specified number of seconds for messages to arrive before returning. | | `messageRetentionPeriod` |integer| **Optional.** How long to retain a message on the queue, unless deleted, in days. The rang is 1 minute to 14 days. The default is 4 days. | | `reDrivePolicy` | [Redrive Policy](#redrive-policy) | **Optional.** Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue.| | `policy` |[Policy](#policy) | **Optional.** The security policy for the SQS Queue | +| `tags` |Object | **Optional.** Key-value pairs that represent AWS tags on the queue. | #### Identifier |Field Name | Type | Description| From 6e6bbb377945287eeebb3328b745c170f2f371c3 Mon Sep 17 00:00:00 2001 From: ssemyonov Date: Tue, 8 Feb 2022 14:00:59 +0000 Subject: [PATCH 04/76] Introduce name property for SNS channel binding object --- sns/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/sns/README.md b/sns/README.md index 7f078bbd..08813041 100644 --- a/sns/README.md +++ b/sns/README.md @@ -29,6 +29,7 @@ SNS supports many optional properties. To mark a channel as SNS, but use default |Field Name | Type | Description| |---|:---:|---| +| `name` | string | **Required.** The name of the topic. Can be different from the channel name to allow flexibility around AWS resource naming limitations. When an [SNS Operation Binding Object]() references an SNS topic by name, the identifier should be the one in this field.| | `type` | [ordering](#ordering)| **Optional.** By default, we assume an unordered SNS topic. This field allows configuration of a FIFO SNS Topic. | | `policy` |[policy](#policy) | **Optional.** The security policy for the SNS Topic | | `tags` |Object | **Optional.** Key-value pairs that represent AWS tags on the topic. | From af5fa867a0a5b500828336f16d3c0630ff283487 Mon Sep 17 00:00:00 2001 From: ssemyonov Date: Tue, 8 Feb 2022 17:58:12 +0000 Subject: [PATCH 05/76] Remove confusing unnecessary statement --- sns/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sns/README.md b/sns/README.md index 08813041..edd3df37 100644 --- a/sns/README.md +++ b/sns/README.md @@ -29,7 +29,7 @@ SNS supports many optional properties. To mark a channel as SNS, but use default |Field Name | Type | Description| |---|:---:|---| -| `name` | string | **Required.** The name of the topic. Can be different from the channel name to allow flexibility around AWS resource naming limitations. When an [SNS Operation Binding Object]() references an SNS topic by name, the identifier should be the one in this field.| +| `name` | string | **Required.** The name of the topic. Can be different from the channel name to allow flexibility around AWS resource naming limitations.| | `type` | [ordering](#ordering)| **Optional.** By default, we assume an unordered SNS topic. This field allows configuration of a FIFO SNS Topic. | | `policy` |[policy](#policy) | **Optional.** The security policy for the SNS Topic | | `tags` |Object | **Optional.** Key-value pairs that represent AWS tags on the topic. | From d5493f484226244db726abe593a9fb37414d9a5a Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Tue, 21 Mar 2023 14:45:13 +0000 Subject: [PATCH 06/76] Remove DLQ requirement --- sqs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqs/README.md b/sqs/README.md index afa1d671..d2ede91c 100644 --- a/sqs/README.md +++ b/sqs/README.md @@ -71,7 +71,7 @@ An SQS queue can set up a Dead Letter Queue as part of a Redelivery Policy. To s #### Redrive Policy |Field Name | Type | Description| |---|:---:|---| -| `deadLetterQueue` |[Identifier](#identifier)| **Required.** The SQS queue to use as a dead letter queue (DLQ) | +| `deadLetterQueue` |[Identifier](#identifier)| The SQS queue to use as a dead letter queue (DLQ) | | `maxReceiveCount` |integer| **Optional.** The SQS queue to use as a dead letter queue (DLQ) #### Statement From f97af36e441fb15a178c38943904809549f69f80 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Tue, 21 Mar 2023 14:49:55 +0000 Subject: [PATCH 07/76] Update statement wording --- sqs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqs/README.md b/sqs/README.md index d2ede91c..8805c470 100644 --- a/sqs/README.md +++ b/sqs/README.md @@ -78,7 +78,7 @@ An SQS queue can set up a Dead Letter Queue as part of a Redelivery Policy. To s |Field Name | Type | Description| |---|:---:|---| | `effect` | string |**Required.** Either "Allow" or "Deny"| -| `principal` | string or array of string |**Required.** The AWS account or IAM user to whom this statement applies| +| `principal` | string or array of string |**Required.** The AWS account or resource ARN that this statement applies to| | `action` | string or array of string |**Required.** The SNS permission being allowed or denied e.g. sns:Publish| From 94443a08ba6fbca81f4822d7889652ef859be45a Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Tue, 21 Mar 2023 14:52:39 +0000 Subject: [PATCH 08/76] Update FIFO property to boolean --- sqs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqs/README.md b/sqs/README.md index 8805c470..b4694966 100644 --- a/sqs/README.md +++ b/sqs/README.md @@ -48,7 +48,7 @@ An SQS queue can set up a Dead Letter Queue as part of a Redelivery Policy. To s |---|:---:|---| |$ref | `string` | Allows for an external definition of a queue. The referenced structure MUST be in the format of a [Queue](#queue). If there are conflicts between the referenced definition and this Queue's definition, the behavior is *undefined*.| | `name` | string | **Required.** The name of the queue. When an [SNS Operation Binding Object]() references an SQS queue by name, the identifier should be the one in this field.| -| `type` | string one of: fifo, standard | **Required.** Is this a FIFO queue or a standard queue? | +| `type` | boolean | **Required.** Is this a FIFO queue or a standard queue? | | `deliveryDelay` | integer | **Optional.** The number of seconds to delay before a message sent to the queue can be received. used to create a *delay queue*. Range is 0 to 15 minutes. Defaults to 0. | | `visibilityTimeout` |integer| **Optional.** The length of time, in seconds, that a consumer locks a message - hiding it from reads - before it is unlocked and can be read again. Range from 0 to 12 hours. Defaults to 30 seconds. | | `receiveMessageWaitTime` |integer| **Optional.** Determines if the queue uses [short polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html) or [long polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html). On a 0 (the default) the queue reads available messages and returns immediately. On a non-zero integer, long polling waits the specified number of seconds for messages to arrive before returning. | From cada5686218b8e314dd9aa57b4c77627689b83bf Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Tue, 21 Mar 2023 14:54:00 +0000 Subject: [PATCH 09/76] Add ARN for SNS --- sns/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sns/README.md b/sns/README.md index edd3df37..b2b03255 100644 --- a/sns/README.md +++ b/sns/README.md @@ -52,7 +52,7 @@ SNS supports many optional properties. To mark a channel as SNS, but use default |Field Name | Type | Description| |---|:---:|---| | `effect` | string |**Required.** Either "Allow" or "Deny"| -| `principal` | string or array of string |**Required.** The AWS account or IAM user to whom this statement applies| +| `principal` | string or array of string |**Required.** The AWS account or resource ARN that this statement applies to| | `action` | string or array of string |**Required.** The SNS permission being allowed or denied e.g. sns:Publish| ##### Examples From 471e92adab573235a1bf17ace3679e6759d9a244 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Tue, 21 Mar 2023 14:55:10 +0000 Subject: [PATCH 10/76] Make redrive policy consistent with other uses --- sns/README.md | 4 ++-- sqs/README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sns/README.md b/sns/README.md index b2b03255..fed2a92b 100644 --- a/sns/README.md +++ b/sns/README.md @@ -224,7 +224,7 @@ channels: attributes: reason: anything-but: password-reset - reDrivePolicy: + redrivePolicy: deadLetterQueue: name: user-signedup-queue-dlq # refers toa queue defined in this file, but not show in this example ``` @@ -293,7 +293,7 @@ channels: numMaxDelayRetries: 25 backoffFunction: exponential maxReceivesPerSecond: 20 - reDrivePolicy: + redrivePolicy: deadLetterQueue: name: user-signedup-queue-dlq # refers toa queue defined in this file, but not show in this example ``` diff --git a/sqs/README.md b/sqs/README.md index b4694966..ea3600c8 100644 --- a/sqs/README.md +++ b/sqs/README.md @@ -130,7 +130,7 @@ channels: name: user-signedup-queue type: standard receiveMessageWaitTime: 4 - reDrivePolicy: + redrivePolicy: deadLetterQueue: name: user-signedup-dlq policy: @@ -213,7 +213,7 @@ channels: attributes: reason: anything-but: password-reset - reDrivePolicy: + redrivePolicy: deadLetterQueue: name: user-signedup-queue-dlq sqs: From 57d67ed76a16d2034dc05c037d8b6993ff8d9deb Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Tue, 18 Apr 2023 10:38:26 +0100 Subject: [PATCH 11/76] awsbindings: alter queue type type --- sqs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqs/README.md b/sqs/README.md index ea3600c8..c15d45a7 100644 --- a/sqs/README.md +++ b/sqs/README.md @@ -48,7 +48,7 @@ An SQS queue can set up a Dead Letter Queue as part of a Redelivery Policy. To s |---|:---:|---| |$ref | `string` | Allows for an external definition of a queue. The referenced structure MUST be in the format of a [Queue](#queue). If there are conflicts between the referenced definition and this Queue's definition, the behavior is *undefined*.| | `name` | string | **Required.** The name of the queue. When an [SNS Operation Binding Object]() references an SQS queue by name, the identifier should be the one in this field.| -| `type` | boolean | **Required.** Is this a FIFO queue or a standard queue? | +| `type` | string | **Required.** Is this a FIFO queue or a standard queue? | | `deliveryDelay` | integer | **Optional.** The number of seconds to delay before a message sent to the queue can be received. used to create a *delay queue*. Range is 0 to 15 minutes. Defaults to 0. | | `visibilityTimeout` |integer| **Optional.** The length of time, in seconds, that a consumer locks a message - hiding it from reads - before it is unlocked and can be read again. Range from 0 to 12 hours. Defaults to 30 seconds. | | `receiveMessageWaitTime` |integer| **Optional.** Determines if the queue uses [short polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html) or [long polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html). On a 0 (the default) the queue reads available messages and returns immediately. On a non-zero integer, long polling waits the specified number of seconds for messages to arrive before returning. | From 1139f7acfa6c30507d9e7a3f77aa71f1a507c0b2 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Tue, 18 Apr 2023 10:40:51 +0100 Subject: [PATCH 12/76] awsbindings: update FIFO queue to match AWS specs --- sqs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqs/README.md b/sqs/README.md index c15d45a7..d61f9c71 100644 --- a/sqs/README.md +++ b/sqs/README.md @@ -48,7 +48,7 @@ An SQS queue can set up a Dead Letter Queue as part of a Redelivery Policy. To s |---|:---:|---| |$ref | `string` | Allows for an external definition of a queue. The referenced structure MUST be in the format of a [Queue](#queue). If there are conflicts between the referenced definition and this Queue's definition, the behavior is *undefined*.| | `name` | string | **Required.** The name of the queue. When an [SNS Operation Binding Object]() references an SQS queue by name, the identifier should be the one in this field.| -| `type` | string | **Required.** Is this a FIFO queue or a standard queue? | +| `fifoQueue` | boolean | **Required.** Is this a FIFO queue? | `deliveryDelay` | integer | **Optional.** The number of seconds to delay before a message sent to the queue can be received. used to create a *delay queue*. Range is 0 to 15 minutes. Defaults to 0. | | `visibilityTimeout` |integer| **Optional.** The length of time, in seconds, that a consumer locks a message - hiding it from reads - before it is unlocked and can be read again. Range from 0 to 12 hours. Defaults to 30 seconds. | | `receiveMessageWaitTime` |integer| **Optional.** Determines if the queue uses [short polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html) or [long polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html). On a 0 (the default) the queue reads available messages and returns immediately. On a non-zero integer, long polling waits the specified number of seconds for messages to arrive before returning. | From c7a202a7f55726b6181968af039621ad2ef87533 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Tue, 18 Apr 2023 10:41:31 +0100 Subject: [PATCH 13/76] awsbindings: correct dropped separator --- sqs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqs/README.md b/sqs/README.md index d61f9c71..994fe472 100644 --- a/sqs/README.md +++ b/sqs/README.md @@ -48,7 +48,7 @@ An SQS queue can set up a Dead Letter Queue as part of a Redelivery Policy. To s |---|:---:|---| |$ref | `string` | Allows for an external definition of a queue. The referenced structure MUST be in the format of a [Queue](#queue). If there are conflicts between the referenced definition and this Queue's definition, the behavior is *undefined*.| | `name` | string | **Required.** The name of the queue. When an [SNS Operation Binding Object]() references an SQS queue by name, the identifier should be the one in this field.| -| `fifoQueue` | boolean | **Required.** Is this a FIFO queue? +| `fifoQueue` | boolean | **Required.** Is this a FIFO queue? | | `deliveryDelay` | integer | **Optional.** The number of seconds to delay before a message sent to the queue can be received. used to create a *delay queue*. Range is 0 to 15 minutes. Defaults to 0. | | `visibilityTimeout` |integer| **Optional.** The length of time, in seconds, that a consumer locks a message - hiding it from reads - before it is unlocked and can be read again. Range from 0 to 12 hours. Defaults to 30 seconds. | | `receiveMessageWaitTime` |integer| **Optional.** Determines if the queue uses [short polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html) or [long polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html). On a 0 (the default) the queue reads available messages and returns immediately. On a non-zero integer, long polling waits the specified number of seconds for messages to arrive before returning. | From 1690fe571de49fe8c32d22152e660b11007e444b Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Tue, 18 Apr 2023 10:42:34 +0100 Subject: [PATCH 14/76] awsbindings: fix typo on delay wording --- sns/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sns/README.md b/sns/README.md index fed2a92b..651b42f1 100644 --- a/sns/README.md +++ b/sns/README.md @@ -127,7 +127,7 @@ We support an array of consumers via the **consumers** field. This allows you to | `maxDelayTarget` | integer | **Optional.** The maximum delay for a retry in seconds | | `numRetries` | integer | **Optional.** The total number of retries, including immediate, pre-backoff, backoff, and post-backoff retries | | `numNoDelayRetries` | integer | **Optional.** The number of immediate retries (with no delay) | -| `numMinDelayRetries` | integer | **Optional.** The number of immediate retries (with no delay) | +| `numMinDelayRetries` | integer | **Optional.** The number of immediate retries (with delay) | | `numMaxDelayRetries` | integer | **Optional.** The number of post-backoff phase retries, with the maximum delay between retries | | `backoffFunction` | string, one of: arithmetic, exponential, geometric or linear | **Optional.** The algorithm for backoff between retries | | `maxReceivesPerSecond` | integer | **Optional.** The maximum number of deliveries per second, per subscription | From 1d33e72a077480ba0f44e0cbbc1fd4e62e5ba419 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Tue, 18 Apr 2023 11:55:48 +0100 Subject: [PATCH 15/76] awsbindings: Add SNS channel schema Co-authored-by: Goker Akce --- sns/json_schemas/channel.json | 131 ++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 sns/json_schemas/channel.json diff --git a/sns/json_schemas/channel.json b/sns/json_schemas/channel.json new file mode 100644 index 00000000..bf42700e --- /dev/null +++ b/sns/json_schemas/channel.json @@ -0,0 +1,131 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://asyncapi.com/bindings/sns/channel.json", + "title": "Channel Schema", + "description": "This object contains information about the channel representation in SNS.", + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^x-[\\w\\d\\.\\-\\_]+$": { + "$ref": "https://raw.githubusercontent.com/asyncapi/spec-json-schemas/v2.14.0/schemas/2.4.0.json#/definitions/specificationExtension" + } + }, + "properties": { + "name": { + "type": "string", + "description": "The name of the topic. Can be different from the channel name to allow flexibility around AWS resource naming limitations." + }, + "type": { + "$ref": "#/definitions/ordering" + }, + "policy": { + "$ref": "#/definitions/policy" + }, + "tags": { + "type": "object", + "description": "Key-value pairs that represent AWS tags on the topic." + }, + "bindingVersion": { + "type": "string", + "description": "Defaults to latest. The version of this binding." + } + }, + "required": [ + "name" + ], + "definitions": { + "ordering": { + "type": "object", + "description": "By default, we assume an unordered SNS topic. This field allows configuration of a FIFO SNS Topic.", + "properties": { + "type": { + "type": "string", + "description": "What type of SNS Topic is this?", + "enum": [ + "standard", + "FIFO" + ] + }, + "contentBasedDepulication": { + "type": "boolean", + "description": "True to turn on de-duplication of messages for a channel." + } + } + }, + "policy": { + "type": "object", + "description": "The security policy for the SNS Topic.", + "properties": { + "statements": { + "type": "array", + "description": "An array of statement objects, each of which controls a permission for this topic", + "items": { + "$ref": "#/definitions/statement" + } + } + }, + "required": [ + "statements" + ] + }, + "statement": { + "type": "object", + "properties": { + "effect": { + "type": "string", + "enum": [ + "Allow", + "Deny" + ] + }, + "principal": { + "description": "The AWS account or resource ARN that this statement applies to.", + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "action": { + "description": "The SNS permission being allowed or denied e.g. sns:Publish", + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "required": [ + "effect", + "principal", + "action" + ] + } + }, + "examples": [ + { + "name": "my-sns-topic", + "policy": { + "statements": [ + { + "effect": "Allow", + "principal": "*", + "action": "SNS:Publish" + } + ] + } + } + ] +} From cfa8115ef29c68f20752c18f9215319547f56942 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Tue, 18 Apr 2023 11:56:52 +0100 Subject: [PATCH 16/76] awsbindings: Add temp file to populate dir --- sns/json_schemas/temp | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 sns/json_schemas/temp diff --git a/sns/json_schemas/temp b/sns/json_schemas/temp new file mode 100644 index 00000000..e69de29b From 27829d9aecbe530813049b32b115d9c971fe4dc8 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Tue, 18 Apr 2023 12:04:35 +0100 Subject: [PATCH 17/76] awsbindings: Add SNS operation binding Co-authored-by: Goker Akce --- sns/json_schemas/operation.json | 198 ++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 sns/json_schemas/operation.json diff --git a/sns/json_schemas/operation.json b/sns/json_schemas/operation.json new file mode 100644 index 00000000..be1d3026 --- /dev/null +++ b/sns/json_schemas/operation.json @@ -0,0 +1,198 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://asyncapi.com/bindings/sns/operation.json", + "title": "Operation Schema", + "description": "This object contains information about the operation representation in SNS.", + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^x-[\\w\\d\\.\\-\\_]+$": { + "$ref": "https://raw.githubusercontent.com/asyncapi/spec-json-schemas/v2.14.0/schemas/2.4.0.json#/definitions/specificationExtension" + } + }, + "properties": { + "topic": { + "$ref": "#/definitions/identifier", + "description": "Often we can assume that the SNS Topic is the channel name-we provide this field in case the you need to supply the ARN, or the Topic name is not the channel name in the AsyncAPI document." + }, + "consumers": { + "type": "array", + "description": "The protocols that listen to this topic and their endpoints.", + "items": { + "$ref": "#/definitions/consumer" + }, + "minItems": 1 + }, + "deliveryPolicy": { + "$ref": "#/definitions/deliveryPolicy", + "description": "Policy for retries to HTTP. The field is the default for HTTP receivers of the SNS Topic which may be overridden by a specific consumer." + }, + "bindingVersion": { + "type": "string", + "description": "Defaults to latest. The version of this binding." + } + }, + "definitions": { + "identifier": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "The endpoint is a URL." + }, + "email": { + "type": "string", + "description": "The endpoint is an email adress." + }, + "phone": { + "type": "string", + "description": "The endpoint is a phone number." + }, + "arn": { + "type": "string", + "description": "The target is an ARN. For example, for SQS, the identifier may be an ARN, which will be of the form: arn:aws:sqs:{region}:{account-id}:{queueName}" + }, + "name": { + "type": "string", + "description": "The endpoint is identified by a name, which corresponds to an identifying field called 'name' of a binding for that protocol on this publish Operation Object. For example, if the protocol is 'sqs' then the name refers to the name field sqs binding. We don't use $ref because we are referring, not including." + } + } + }, + "consumer": { + "type": "object", + "description": "What protocol will this endpoint receive messages by.", + "properties": { + "protocol": { + "type": "string", + "enum": [ + "http", + "https", + "email", + "email-json", + "sms", + "sqs", + "application", + "lambda", + "firehose" + ] + }, + "endpoint": { + "$ref": "#/definitions/identifier", + "description": "Where are messages being delivered to?" + }, + "filterPolicy": { + "$ref": "#/definitions/filterPolicy" + }, + "rawMessageDelivery": { + "type": "boolean", + "description": "If true AWS SNS attributes are removed from the body, and for SQS, SNS message attributes are copied to SQS message attributes. If false the SNS attributes are included in the body." + }, + "redrivePolicy": { + "$ref": "#/definitions/redrivePolicy" + }, + "deliveryPolicy": { + "$ref": "#/definitions/deliveryPolicy", + "description": "Policy for retries to HTTP. The parameter is for that SNS Subscription and overrides any policy on the SNS Topic." + }, + "displayName": { + "type": "string", + "description": "The display name to use with an SNS subscription" + } + }, + "required": [ + "protocol", + "endpoint", + "rawMessageDelivery" + ] + }, + "deliveryPolicy": { + "type": "object", + "properties": { + "minDelayTarget": { + "type": "integer", + "description": "The minimum delay for a retry in seconds." + }, + "maxDelayTarget": { + "type": "integer", + "description": "The maximum delay for a retry in seconds." + }, + "numRetries": { + "type": "integer", + "description": "The total number of retries, including immediate, pre-backoff, backoff, and post-backoff retries." + }, + "numNoDelayRetries": { + "type": "integer", + "description": "The number of immediate retries (with no delay)." + }, + "numMinDelayRetries": { + "type": "integer", + "description": "The number of immediate retries (with delay)." + }, + "numMaxDelayRetries": { + "type": "integer", + "description": "The number of post-backoff phase retries, with the maximum delay between retries." + }, + "backoffFunction": { + "type": "string", + "description": "The algorithm for backoff between retries.", + "enum": [ + "arithmetic", + "exponential", + "geometric", + "linear" + ] + }, + "maxReceivesPerSecond": { + "type": "integer", + "description": "The maximum number of deliveries per second, per subscription." + } + } + }, + "filterPolicy": { + "type": "object", + "description": "Only receive a subset of messages from the channel, determined by this policy.", + "properties": { + "attributes": { + "type": "object", + "description": "A map of a message attribute to an array of possible matches. The match may be a simple string for an exact match, but it may also be an object that represents a constraint and values for that constraint.", + "additionalProperties": { + "oneOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "string" + }, + { + "type": "object" + } + ] + } + } + }, + "required": [ + "attributes" + ] + }, + "redrivePolicy": { + "type": "object", + "description": "Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue.", + "properties": { + "deadLetterQueue": { + "$ref": "#/definitions/identifier", + "description": "The SQS queue to use as a dead letter queue (DLQ)." + }, + "maxReceiveCount": { + "type": "integer", + "description": "The SQS queue to use as a dead letter queue (DLQ). Note that you may have a Redrive Policy to put messages that cannot be delivered to an SQS queue, even if you use another protocol to consume messages from the queue, so it is defined at the level of the SNS Operation Binding Object in a Consumer Object (and is applied as part of an SNS Subscription). The SQS Binding describes how to define an SQS Binding that supports defining the target SQS of the Redrive Policy." + } + }, + "required": [ + "deadLetterQueue" + ] + } + } +} From 08d2ba23b5aafb8aaa22370e6227f7e969af298c Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Tue, 18 Apr 2023 12:04:56 +0100 Subject: [PATCH 18/76] awsbindings: Delete temp --- sns/json_schemas/temp | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 sns/json_schemas/temp diff --git a/sns/json_schemas/temp b/sns/json_schemas/temp deleted file mode 100644 index e69de29b..00000000 From 401ec78c73bfea81f8cc77e4315933c673efe817 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 11:14:49 +0100 Subject: [PATCH 19/76] awsbindings: Add SQS channel schema Co-authored-by: Goker Akce --- sqs/json_schemas/channel.json | 168 ++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 sqs/json_schemas/channel.json diff --git a/sqs/json_schemas/channel.json b/sqs/json_schemas/channel.json new file mode 100644 index 00000000..63bea8f7 --- /dev/null +++ b/sqs/json_schemas/channel.json @@ -0,0 +1,168 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://asyncapi.com/bindings/sqs/channel.json", + "title": "Channel Schema", + "description": "This object contains information about the channel representation in SQS.", + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^x-[\\w\\d\\.\\-\\_]+$": { + "$ref": "https://raw.githubusercontent.com/asyncapi/spec-json-schemas/v2.14.0/schemas/2.4.0.json#/definitions/specificationExtension" + } + }, + "properties": { + "queue": { + "$ref": "#/definitions/queue" + }, + "deadLetterQueue": { + "$ref": "#/definitions/queue" + }, + "bindingVersion": { + "type": "string", + "description": "Defaults to latest. The version of this binding." + } + }, + "required": [ + "queue" + ], + "definitions": { + "queue": { + "type": "object", + "description": "A definition of the queue that will be used as the channel.", + "properties": { + "$ref": { + "type": "string", + "description": "Allows for an external definition of a queue. The referenced structure MUST be in the format of a Queue. If there are conflicts between the referenced definition and this Queue's definition, the behavior is undefined." + }, + "name": { + "type": "string", + "description": "The name of the queue. When an SNS Operation Binding Object references an SQS queue by name, the identifier should be the one in this field." + }, + "fifoQueue": { + "type": "boolean", + "description": "Default is standard queue. If set to true, creates a FIFO queue." + }, + "deliveryDelay": { + "type": "integer", + "description": "The number of seconds to delay before a message sent to the queue can be received. used to create a delay queue. Range is 0 to 15 minutes. Defaults to 0." + }, + "visibilityTimeout": { + "type": "integer", + "description": "The length of time, in seconds, that a consumer locks a message - hiding it from reads - before it is unlocked and can be read again. Range from 0 to 12 hours. Defaults to 30 seconds." + }, + "receiveMessageWaitTime": { + "type": "integer", + "description": "Determines if the queue uses short polling or long polling. On a 0 (the default) the queue reads available messages and returns immediately. On a non-zero integer, long polling waits the specified number of seconds for messages to arrive before returning." + }, + "messageRetentionPeriod": { + "type": "integer", + "description": "How long to retain a message on the queue, unless deleted, in days. The rang is 1 minute to 14 days. The default is 4 days." + }, + "redrivePolicy": { + "$ref": "#/definitions/redrivePolicy" + }, + "policy": { + "$ref": "#/definitions/policy" + }, + "tags": { + "type": "object", + "description": "Key-value pairs that represent AWS tags on the queue." + } + }, + "required": [ + "name" + ] + }, + "redrivePolicy": { + "type": "object", + "description": "Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue.", + "properties": { + "deadLetterQueue": { + "$ref": "#/definitions/identifier" + }, + "maxReceiveCount": { + "type": "integer", + "description": "The SQS queue to use as a dead letter queue (DLQ)." + } + }, + "required": [ + "deadLetterQueue" + ] + }, + "identifier": { + "type": "object", + "description": "The SQS queue to use as a dead letter queue (DLQ).", + "properties": { + "arn": { + "type": "string", + "description": "The target is an ARN. For example, for SQS, the identifier may be an ARN, which will be of the form: arn:aws:sqs:{region}:{account-id}:{queueName}" + }, + "name": { + "type": "string", + "description": "The endpoint is identified by a name, which corresponds to an identifying field called 'name' of a binding for that protocol on this publish Operation Object. For example, if the protocol is 'sqs' then the name refers to the name field sqs binding." + } + } + }, + "policy": { + "type": "object", + "description": "The security policy for the SQS Queue", + "properties": { + "statements": { + "type": "array", + "description": "An array of statement objects, each of which controls a permission for this topic.", + "items": { + "$ref": "#/definitions/statement" + } + } + }, + "required": [ + "statements" + ] + }, + "statement": { + "type": "object", + "properties": { + "effect": { + "type": "string", + "enum": [ + "Allow", + "Deny" + ] + }, + "principal": { + "description": "The AWS account or resource ARN that this statement applies to.", + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "action": { + "description": "The SNS permission being allowed or denied e.g. sns:Publish", + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "required": [ + "effect", + "principal", + "action" + ] + } + } +} From 61cc69a706c478abaf226f0d87fdb745a6c7c9b4 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 11:15:55 +0100 Subject: [PATCH 20/76] awsbindings: Add SQS operation schema Co-authored-by: Goker Akce --- sqs/json_schemas/operation.json | 168 ++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 sqs/json_schemas/operation.json diff --git a/sqs/json_schemas/operation.json b/sqs/json_schemas/operation.json new file mode 100644 index 00000000..16a7b8ce --- /dev/null +++ b/sqs/json_schemas/operation.json @@ -0,0 +1,168 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://asyncapi.com/bindings/sqs/operation.json", + "title": "Operation Schema", + "description": "This object contains information about the operation representation in SQS.", + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^x-[\\w\\d\\.\\-\\_]+$": { + "$ref": "https://raw.githubusercontent.com/asyncapi/spec-json-schemas/v2.14.0/schemas/2.4.0.json#/definitions/specificationExtension" + } + }, + "properties": { + "queues": { + "type": "array", + "description": "Queue objects that are either the endpoint for an SNS Operation Binding Object, or the deadLetterQueue of the SQS Operation Binding Object.", + "items": { + "$ref": "#/definitions/queue" + } + }, + "bindingVersion": { + "type": "string", + "description": "Defaults to latest. The version of this binding." + } + }, + "required": [ + "queues" + ], + "definitions": { + "queue": { + "type": "object", + "properties": { + "$ref": { + "type": "string", + "description": "Allows for an external definition of a queue. The referenced structure MUST be in the format of a Queue. If there are conflicts between the referenced definition and this Queue's definition, the behavior is undefined." + }, + "name": { + "type": "string", + "description": "The name of the queue. When an SNS Operation Binding Object references an SQS queue by name, the identifier should be the one in this field." + }, + "fifoQueue": { + "type": "boolean", + "description": "Default is standard queue. If set to true, creates a FIFO queue." + }, + "deliveryDelay": { + "type": "integer", + "description": "The number of seconds to delay before a message sent to the queue can be received. used to create a delay queue. Range is 0 to 15 minutes. Defaults to 0." + }, + "visibilityTimeout": { + "type": "integer", + "description": "The length of time, in seconds, that a consumer locks a message - hiding it from reads - before it is unlocked and can be read again. Range from 0 to 12 hours. Defaults to 30 seconds." + }, + "receiveMessageWaitTime": { + "type": "integer", + "description": "Determines if the queue uses short polling or long polling. On a 0 (the default) the queue reads available messages and returns immediately. On a non-zero integer, long polling waits the specified number of seconds for messages to arrive before returning." + }, + "messageRetentionPeriod": { + "type": "integer", + "description": "How long to retain a message on the queue, unless deleted, in days. The range is 1 minute to 14 days. The default is 4 days." + }, + "redrivePolicy": { + "$ref": "#/definitions/redrivePolicy" + }, + "policy": { + "$ref": "#/definitions/policy" + }, + "tags": { + "type": "object", + "description": "Key-value pairs that represent AWS tags on the queue." + } + }, + "required": [ + "name" + ] + }, + "redrivePolicy": { + "type": "object", + "description": "Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue.", + "properties": { + "deadLetterQueue": { + "$ref": "#/definitions/identifier" + }, + "maxReceiveCount": { + "type": "integer", + "description": "The SQS queue to use as a dead letter queue (DLQ)." + } + }, + "required": [ + "deadLetterQueue" + ] + }, + "identifier": { + "type": "object", + "description": "The SQS queue to use as a dead letter queue (DLQ).", + "properties": { + "arn": { + "type": "string", + "description": "The target is an ARN. For example, for SQS, the identifier may be an ARN, which will be of the form: arn:aws:sqs:{region}:{account-id}:{queueName}" + }, + "name": { + "type": "string", + "description": "The endpoint is identified by a name, which corresponds to an identifying field called 'name' of a binding for that protocol on this publish Operation Object. For example, if the protocol is 'sqs' then the name refers to the name field sqs binding." + } + } + }, + "policy": { + "type": "object", + "description": "The security policy for the SQS Queue.", + "properties": { + "statements": { + "type": "array", + "description": "An array of Statement objects, each of which controls a permission for this topic.", + "items": { + "$ref": "#/definitions/statement" + } + } + }, + "required": [ + "statements" + ] + }, + "statement": { + "type": "object", + "properties": { + "effect": { + "type": "string", + "enum": [ + "Allow", + "Deny" + ] + }, + "principal": { + "description": "The AWS account or resource ARN that this statement applies to.", + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "action": { + "description": "The SNS permission being allowed or denied e.g. sns:Publish", + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "required": [ + "effect", + "principal", + "action" + ] + } + } +} From eaa8becff69d7eac1d78eaed36105c6c97f59625 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 11:19:22 +0100 Subject: [PATCH 21/76] awsbindings: Generalise queue type description --- sqs/json_schemas/channel.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqs/json_schemas/channel.json b/sqs/json_schemas/channel.json index 63bea8f7..a2c6b288 100644 --- a/sqs/json_schemas/channel.json +++ b/sqs/json_schemas/channel.json @@ -28,7 +28,7 @@ "definitions": { "queue": { "type": "object", - "description": "A definition of the queue that will be used as the channel.", + "description": "A definition of a queue.", "properties": { "$ref": { "type": "string", From a7d982faf39f015311c677f77d37118e0dc1d740 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 11:22:28 +0100 Subject: [PATCH 22/76] awsbindings: Disambiguate queue and DLQ description --- sqs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqs/README.md b/sqs/README.md index 994fe472..1f80ac23 100644 --- a/sqs/README.md +++ b/sqs/README.md @@ -38,7 +38,7 @@ An SQS queue can set up a Dead Letter Queue as part of a Redelivery Policy. To s |Field Name | Type | Description| |---|:---:|---| | `queue` | [Queue](#queue)| **Required.** A definition of the queue that will be used as the channel. | -| `deadLetterQueue` | [Queue](#queue)| **Optional.** A definition of the queue that will be used as the channel. | +| `deadLetterQueue` | [Queue](#queue)| **Optional.** A definition of the queue that will be used for errors. | |`bindingVersion` | string | **Optional**, defaults to `latest`. The version of this binding.| ### Schemas From 0f75115bc3ced32169789e9bba59811e9a4bde85 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 11:23:45 +0100 Subject: [PATCH 23/76] awsbindings: Add queue and DLQ descriptions --- sqs/json_schemas/channel.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sqs/json_schemas/channel.json b/sqs/json_schemas/channel.json index a2c6b288..0bda2099 100644 --- a/sqs/json_schemas/channel.json +++ b/sqs/json_schemas/channel.json @@ -12,9 +12,11 @@ }, "properties": { "queue": { + "description": "A definition of the queue that will be used as the channel.", "$ref": "#/definitions/queue" }, "deadLetterQueue": { + "description": "A definition of the queue that will be used for errors.", "$ref": "#/definitions/queue" }, "bindingVersion": { From 162d72cce6ef24311a730a980f1e3ef80e7a4673 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 11:25:16 +0100 Subject: [PATCH 24/76] awsbindings: Extract default from description --- sqs/json_schemas/channel.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sqs/json_schemas/channel.json b/sqs/json_schemas/channel.json index 0bda2099..83226da2 100644 --- a/sqs/json_schemas/channel.json +++ b/sqs/json_schemas/channel.json @@ -21,7 +21,8 @@ }, "bindingVersion": { "type": "string", - "description": "Defaults to latest. The version of this binding." + "description": "The version of this binding.", + "default": "latest" } }, "required": [ From 6c495ba4ad9e6cf0cbf0c2770a7dc7d3b4e42be1 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 11:27:30 +0100 Subject: [PATCH 25/76] awsbindings: Match FIFO queue description to spec with default --- sqs/json_schemas/channel.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sqs/json_schemas/channel.json b/sqs/json_schemas/channel.json index 83226da2..983a5bf4 100644 --- a/sqs/json_schemas/channel.json +++ b/sqs/json_schemas/channel.json @@ -43,7 +43,8 @@ }, "fifoQueue": { "type": "boolean", - "description": "Default is standard queue. If set to true, creates a FIFO queue." + "description": "Is this a FIFO queue?", + "default": false }, "deliveryDelay": { "type": "integer", From a71f79861fc3912200745c7ad111b2bfe943a9f0 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 11:30:10 +0100 Subject: [PATCH 26/76] awsbindings: Encode DD def, min & max in schema --- sqs/json_schemas/channel.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sqs/json_schemas/channel.json b/sqs/json_schemas/channel.json index 983a5bf4..49f53507 100644 --- a/sqs/json_schemas/channel.json +++ b/sqs/json_schemas/channel.json @@ -48,7 +48,10 @@ }, "deliveryDelay": { "type": "integer", - "description": "The number of seconds to delay before a message sent to the queue can be received. used to create a delay queue. Range is 0 to 15 minutes. Defaults to 0." + "description": "The number of seconds to delay before a message sent to the queue can be received. used to create a delay queue.", + "minimum": 0, + "maximum": 15, + "default": 0 }, "visibilityTimeout": { "type": "integer", From d7ad6c206be0a384a23c48a47cdad114506ccce1 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 11:31:25 +0100 Subject: [PATCH 27/76] awsbindings: Extract VT bounds to schema --- sqs/json_schemas/channel.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sqs/json_schemas/channel.json b/sqs/json_schemas/channel.json index 49f53507..6ca061cc 100644 --- a/sqs/json_schemas/channel.json +++ b/sqs/json_schemas/channel.json @@ -55,7 +55,10 @@ }, "visibilityTimeout": { "type": "integer", - "description": "The length of time, in seconds, that a consumer locks a message - hiding it from reads - before it is unlocked and can be read again. Range from 0 to 12 hours. Defaults to 30 seconds." + "description": "The length of time, in seconds, that a consumer locks a message - hiding it from reads - before it is unlocked and can be read again.", + "minimum": 0, + "maximum": 43200, + "default": 0 }, "receiveMessageWaitTime": { "type": "integer", From 677e09532d2ae1166203b877313a72f5e5c7ec92 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 11:32:44 +0100 Subject: [PATCH 28/76] awsbindings: Make seconds explicit --- sqs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqs/README.md b/sqs/README.md index 1f80ac23..f892b89d 100644 --- a/sqs/README.md +++ b/sqs/README.md @@ -50,7 +50,7 @@ An SQS queue can set up a Dead Letter Queue as part of a Redelivery Policy. To s | `name` | string | **Required.** The name of the queue. When an [SNS Operation Binding Object]() references an SQS queue by name, the identifier should be the one in this field.| | `fifoQueue` | boolean | **Required.** Is this a FIFO queue? | | `deliveryDelay` | integer | **Optional.** The number of seconds to delay before a message sent to the queue can be received. used to create a *delay queue*. Range is 0 to 15 minutes. Defaults to 0. | -| `visibilityTimeout` |integer| **Optional.** The length of time, in seconds, that a consumer locks a message - hiding it from reads - before it is unlocked and can be read again. Range from 0 to 12 hours. Defaults to 30 seconds. | +| `visibilityTimeout` |integer| **Optional.** The length of time, in seconds, that a consumer locks a message - hiding it from reads - before it is unlocked and can be read again. Range from 0 to 12 hours (43200 seconds). Defaults to 30 seconds. | | `receiveMessageWaitTime` |integer| **Optional.** Determines if the queue uses [short polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html) or [long polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html). On a 0 (the default) the queue reads available messages and returns immediately. On a non-zero integer, long polling waits the specified number of seconds for messages to arrive before returning. | | `messageRetentionPeriod` |integer| **Optional.** How long to retain a message on the queue, unless deleted, in days. The rang is 1 minute to 14 days. The default is 4 days. | | `reDrivePolicy` | [Redrive Policy](#redrive-policy) | **Optional.** Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue.| From 9fbc3e6ad8b6f40efb3c722cd73f293a7a219db1 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 11:33:17 +0100 Subject: [PATCH 29/76] awsbindings: Correct default for VT --- sqs/json_schemas/channel.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqs/json_schemas/channel.json b/sqs/json_schemas/channel.json index 6ca061cc..e5ae1ffd 100644 --- a/sqs/json_schemas/channel.json +++ b/sqs/json_schemas/channel.json @@ -58,7 +58,7 @@ "description": "The length of time, in seconds, that a consumer locks a message - hiding it from reads - before it is unlocked and can be read again.", "minimum": 0, "maximum": 43200, - "default": 0 + "default": 30 }, "receiveMessageWaitTime": { "type": "integer", From 807dc5cc3f2c9767062a42c58fd1a8e89471bf74 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 12:15:24 +0100 Subject: [PATCH 30/76] awsbindings: Improve rmt description --- sqs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqs/README.md b/sqs/README.md index f892b89d..f1082e11 100644 --- a/sqs/README.md +++ b/sqs/README.md @@ -51,7 +51,7 @@ An SQS queue can set up a Dead Letter Queue as part of a Redelivery Policy. To s | `fifoQueue` | boolean | **Required.** Is this a FIFO queue? | | `deliveryDelay` | integer | **Optional.** The number of seconds to delay before a message sent to the queue can be received. used to create a *delay queue*. Range is 0 to 15 minutes. Defaults to 0. | | `visibilityTimeout` |integer| **Optional.** The length of time, in seconds, that a consumer locks a message - hiding it from reads - before it is unlocked and can be read again. Range from 0 to 12 hours (43200 seconds). Defaults to 30 seconds. | -| `receiveMessageWaitTime` |integer| **Optional.** Determines if the queue uses [short polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html) or [long polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html). On a 0 (the default) the queue reads available messages and returns immediately. On a non-zero integer, long polling waits the specified number of seconds for messages to arrive before returning. | +| `receiveMessageWaitTime` |integer| **Optional.** Determines if the queue uses [short polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html) or [long polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html). Set to zero (the default) the queue reads available messages and returns immediately. Set to a non-zero integer, long polling waits the specified number of seconds for messages to arrive before returning. | | `messageRetentionPeriod` |integer| **Optional.** How long to retain a message on the queue, unless deleted, in days. The rang is 1 minute to 14 days. The default is 4 days. | | `reDrivePolicy` | [Redrive Policy](#redrive-policy) | **Optional.** Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue.| | `policy` |[Policy](#policy) | **Optional.** The security policy for the SQS Queue | From 8c3a1fed1ae0c78611efc1ed4e7c6d793c92d76e Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 12:16:43 +0100 Subject: [PATCH 31/76] awsbindings: Add default and description to rmwt --- sqs/json_schemas/channel.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sqs/json_schemas/channel.json b/sqs/json_schemas/channel.json index e5ae1ffd..d916d7ff 100644 --- a/sqs/json_schemas/channel.json +++ b/sqs/json_schemas/channel.json @@ -62,7 +62,8 @@ }, "receiveMessageWaitTime": { "type": "integer", - "description": "Determines if the queue uses short polling or long polling. On a 0 (the default) the queue reads available messages and returns immediately. On a non-zero integer, long polling waits the specified number of seconds for messages to arrive before returning." + "description": "Determines if the queue uses short polling or long polling. Set to zero the queue reads available messages and returns immediately. Set to a non-zero integer, long polling waits the specified number of seconds for messages to arrive before returning.", + "default": 0 }, "messageRetentionPeriod": { "type": "integer", From f5dbc92bd749a60d8c288e026701bad5b6ae8dd5 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 12:19:41 +0100 Subject: [PATCH 32/76] awsbindings: Bring MRP in line with AWS standards --- sqs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqs/README.md b/sqs/README.md index f1082e11..a5ed7873 100644 --- a/sqs/README.md +++ b/sqs/README.md @@ -52,7 +52,7 @@ An SQS queue can set up a Dead Letter Queue as part of a Redelivery Policy. To s | `deliveryDelay` | integer | **Optional.** The number of seconds to delay before a message sent to the queue can be received. used to create a *delay queue*. Range is 0 to 15 minutes. Defaults to 0. | | `visibilityTimeout` |integer| **Optional.** The length of time, in seconds, that a consumer locks a message - hiding it from reads - before it is unlocked and can be read again. Range from 0 to 12 hours (43200 seconds). Defaults to 30 seconds. | | `receiveMessageWaitTime` |integer| **Optional.** Determines if the queue uses [short polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html) or [long polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html). Set to zero (the default) the queue reads available messages and returns immediately. Set to a non-zero integer, long polling waits the specified number of seconds for messages to arrive before returning. | -| `messageRetentionPeriod` |integer| **Optional.** How long to retain a message on the queue, unless deleted, in days. The rang is 1 minute to 14 days. The default is 4 days. | +| `messageRetentionPeriod` |integer| **Optional.** How long to retain a message on the queue in seconds, unless deleted. The range is 60 (1 minute) to 1,209,600 (14 days). The default is 345,600 (4 days). | | `reDrivePolicy` | [Redrive Policy](#redrive-policy) | **Optional.** Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue.| | `policy` |[Policy](#policy) | **Optional.** The security policy for the SQS Queue | | `tags` |Object | **Optional.** Key-value pairs that represent AWS tags on the queue. | From fb4c786d3f1b6e51bf0009728ea5f599b13581f9 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 12:20:57 +0100 Subject: [PATCH 33/76] awsbindings: Match MRP schema to spec --- sqs/json_schemas/channel.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sqs/json_schemas/channel.json b/sqs/json_schemas/channel.json index d916d7ff..f07c59e8 100644 --- a/sqs/json_schemas/channel.json +++ b/sqs/json_schemas/channel.json @@ -67,7 +67,10 @@ }, "messageRetentionPeriod": { "type": "integer", - "description": "How long to retain a message on the queue, unless deleted, in days. The rang is 1 minute to 14 days. The default is 4 days." + "description": "How long to retain a message on the queue in seconds, unless deleted.", + "minimum": 60, + "maximum": 1209600, + "default": 345600 }, "redrivePolicy": { "$ref": "#/definitions/redrivePolicy" From 8533ae3e157819cd593f7b61ed3462b2b7223709 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 12:22:44 +0100 Subject: [PATCH 34/76] awsbindings: Match casing to AWS standards --- sqs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqs/README.md b/sqs/README.md index a5ed7873..57a651ec 100644 --- a/sqs/README.md +++ b/sqs/README.md @@ -53,7 +53,7 @@ An SQS queue can set up a Dead Letter Queue as part of a Redelivery Policy. To s | `visibilityTimeout` |integer| **Optional.** The length of time, in seconds, that a consumer locks a message - hiding it from reads - before it is unlocked and can be read again. Range from 0 to 12 hours (43200 seconds). Defaults to 30 seconds. | | `receiveMessageWaitTime` |integer| **Optional.** Determines if the queue uses [short polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html) or [long polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html). Set to zero (the default) the queue reads available messages and returns immediately. Set to a non-zero integer, long polling waits the specified number of seconds for messages to arrive before returning. | | `messageRetentionPeriod` |integer| **Optional.** How long to retain a message on the queue in seconds, unless deleted. The range is 60 (1 minute) to 1,209,600 (14 days). The default is 345,600 (4 days). | -| `reDrivePolicy` | [Redrive Policy](#redrive-policy) | **Optional.** Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue.| +| `redrivePolicy` | [Redrive Policy](#redrive-policy) | **Optional.** Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue.| | `policy` |[Policy](#policy) | **Optional.** The security policy for the SQS Queue | | `tags` |Object | **Optional.** Key-value pairs that represent AWS tags on the queue. | From d05406da72d7189441c06f80327bc079ab516c85 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 12:23:20 +0100 Subject: [PATCH 35/76] awsbindings: Match DLQ description --- sqs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqs/README.md b/sqs/README.md index 57a651ec..593b77f2 100644 --- a/sqs/README.md +++ b/sqs/README.md @@ -38,7 +38,7 @@ An SQS queue can set up a Dead Letter Queue as part of a Redelivery Policy. To s |Field Name | Type | Description| |---|:---:|---| | `queue` | [Queue](#queue)| **Required.** A definition of the queue that will be used as the channel. | -| `deadLetterQueue` | [Queue](#queue)| **Optional.** A definition of the queue that will be used for errors. | +| `deadLetterQueue` | [Queue](#queue)| **Optional.** A definition of the queue that will be used for un-processable messages. | |`bindingVersion` | string | **Optional**, defaults to `latest`. The version of this binding.| ### Schemas From d0f3921a9f6d1271c92d1a982ac81341322e683e Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 12:23:43 +0100 Subject: [PATCH 36/76] awsbindings: Match DLQ description in schema --- sqs/json_schemas/channel.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqs/json_schemas/channel.json b/sqs/json_schemas/channel.json index f07c59e8..1618b3d5 100644 --- a/sqs/json_schemas/channel.json +++ b/sqs/json_schemas/channel.json @@ -16,7 +16,7 @@ "$ref": "#/definitions/queue" }, "deadLetterQueue": { - "description": "A definition of the queue that will be used for errors.", + "description": "A definition of the queue that will be used for un-processable messages.", "$ref": "#/definitions/queue" }, "bindingVersion": { From d3367a36225cdf5788c3f716808b07b0efad9c8f Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 12:27:56 +0100 Subject: [PATCH 37/76] awsbindings: Correct redrive MRC description --- sqs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqs/README.md b/sqs/README.md index 593b77f2..2e7e42e9 100644 --- a/sqs/README.md +++ b/sqs/README.md @@ -72,7 +72,7 @@ An SQS queue can set up a Dead Letter Queue as part of a Redelivery Policy. To s |Field Name | Type | Description| |---|:---:|---| | `deadLetterQueue` |[Identifier](#identifier)| The SQS queue to use as a dead letter queue (DLQ) | -| `maxReceiveCount` |integer| **Optional.** The SQS queue to use as a dead letter queue (DLQ) +| `maxReceiveCount` |integer| **Optional.** The number of times a message is delivered to the source queue before being moved to the dead-letter queue. Default is 10. | #### Statement |Field Name | Type | Description| From 414eb6829610e029664492bd3878906c1f942183 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 12:29:16 +0100 Subject: [PATCH 38/76] awsbindings: Match schema to spec for MRC --- sqs/json_schemas/channel.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sqs/json_schemas/channel.json b/sqs/json_schemas/channel.json index 1618b3d5..0afc547f 100644 --- a/sqs/json_schemas/channel.json +++ b/sqs/json_schemas/channel.json @@ -96,7 +96,8 @@ }, "maxReceiveCount": { "type": "integer", - "description": "The SQS queue to use as a dead letter queue (DLQ)." + "description": "The number of times a message is delivered to the source queue before being moved to the dead-letter queue.", + "default": 10 } }, "required": [ From bfbcdd0b73d7d195e21e9f625e110f22425e3c49 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 12:30:57 +0100 Subject: [PATCH 39/76] awsbindings: Correct typo on statements --- sqs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqs/README.md b/sqs/README.md index 2e7e42e9..a6aa30ac 100644 --- a/sqs/README.md +++ b/sqs/README.md @@ -66,7 +66,7 @@ An SQS queue can set up a Dead Letter Queue as part of a Redelivery Policy. To s #### Policy |Field Name | Type | Description| |---|:---:|---| -| `Statements` | [Statement](#statement) | **Required.** An array of Statement objects, each of which controls a permission for this topic | +| `Statements` | [Statement](#statement) | **Required.** An array of Statement objects, each of which controls a permission for this queue. | #### Redrive Policy |Field Name | Type | Description| From 4a6aa9fb4dd66d924332771fabc396d658b80b3b Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 12:31:24 +0100 Subject: [PATCH 40/76] awsbindings: Match typo corrections in schema --- sqs/json_schemas/channel.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqs/json_schemas/channel.json b/sqs/json_schemas/channel.json index 0afc547f..5b2e2bff 100644 --- a/sqs/json_schemas/channel.json +++ b/sqs/json_schemas/channel.json @@ -124,7 +124,7 @@ "properties": { "statements": { "type": "array", - "description": "An array of statement objects, each of which controls a permission for this topic.", + "description": "An array of statement objects, each of which controls a permission for this queue.", "items": { "$ref": "#/definitions/statement" } From d775f181d0e087496fd9cb42cdb73f979e54d8a0 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 12:34:23 +0100 Subject: [PATCH 41/76] awsbindings: Fix SQS permission typo --- sqs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqs/README.md b/sqs/README.md index a6aa30ac..bb962ddb 100644 --- a/sqs/README.md +++ b/sqs/README.md @@ -79,7 +79,7 @@ An SQS queue can set up a Dead Letter Queue as part of a Redelivery Policy. To s |---|:---:|---| | `effect` | string |**Required.** Either "Allow" or "Deny"| | `principal` | string or array of string |**Required.** The AWS account or resource ARN that this statement applies to| -| `action` | string or array of string |**Required.** The SNS permission being allowed or denied e.g. sns:Publish| +| `action` | string or array of string |**Required.** The SQS permission being allowed or denied e.g. sqs:ReceiveMessage | From d2d9da5d322bf4a12570da5e5e1204bf61df50da Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 12:34:55 +0100 Subject: [PATCH 42/76] awsbindings: Match typo fix in bindings --- sqs/json_schemas/channel.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqs/json_schemas/channel.json b/sqs/json_schemas/channel.json index 5b2e2bff..b0dacae4 100644 --- a/sqs/json_schemas/channel.json +++ b/sqs/json_schemas/channel.json @@ -159,7 +159,7 @@ ] }, "action": { - "description": "The SNS permission being allowed or denied e.g. sns:Publish", + "description": "The SQS permission being allowed or denied e.g. sqs:ReceiveMessage", "oneOf": [ { "type": "string" From a4b440ef401ae5b14187b591b772e75a8e37c660 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 14:32:20 +0100 Subject: [PATCH 43/76] awsbindings: Replace ops subobjects with updated --- sqs/json_schemas/operation.json | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/sqs/json_schemas/operation.json b/sqs/json_schemas/operation.json index 16a7b8ce..9e6437a2 100644 --- a/sqs/json_schemas/operation.json +++ b/sqs/json_schemas/operation.json @@ -29,6 +29,7 @@ "definitions": { "queue": { "type": "object", + "description": "A definition of a queue.", "properties": { "$ref": { "type": "string", @@ -40,23 +41,34 @@ }, "fifoQueue": { "type": "boolean", - "description": "Default is standard queue. If set to true, creates a FIFO queue." + "description": "Is this a FIFO queue?", + "default": false }, "deliveryDelay": { "type": "integer", - "description": "The number of seconds to delay before a message sent to the queue can be received. used to create a delay queue. Range is 0 to 15 minutes. Defaults to 0." + "description": "The number of seconds to delay before a message sent to the queue can be received. used to create a delay queue.", + "minimum": 0, + "maximum": 15, + "default": 0 }, "visibilityTimeout": { "type": "integer", - "description": "The length of time, in seconds, that a consumer locks a message - hiding it from reads - before it is unlocked and can be read again. Range from 0 to 12 hours. Defaults to 30 seconds." + "description": "The length of time, in seconds, that a consumer locks a message - hiding it from reads - before it is unlocked and can be read again.", + "minimum": 0, + "maximum": 43200, + "default": 30 }, "receiveMessageWaitTime": { "type": "integer", - "description": "Determines if the queue uses short polling or long polling. On a 0 (the default) the queue reads available messages and returns immediately. On a non-zero integer, long polling waits the specified number of seconds for messages to arrive before returning." + "description": "Determines if the queue uses short polling or long polling. Set to zero the queue reads available messages and returns immediately. Set to a non-zero integer, long polling waits the specified number of seconds for messages to arrive before returning.", + "default": 0 }, "messageRetentionPeriod": { "type": "integer", - "description": "How long to retain a message on the queue, unless deleted, in days. The range is 1 minute to 14 days. The default is 4 days." + "description": "How long to retain a message on the queue in seconds, unless deleted.", + "minimum": 60, + "maximum": 1209600, + "default": 345600 }, "redrivePolicy": { "$ref": "#/definitions/redrivePolicy" @@ -78,11 +90,12 @@ "description": "Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue.", "properties": { "deadLetterQueue": { - "$ref": "#/definitions/identifier" + "$ref": "#/definitions/identifier" }, "maxReceiveCount": { "type": "integer", - "description": "The SQS queue to use as a dead letter queue (DLQ)." + "description": "The number of times a message is delivered to the source queue before being moved to the dead-letter queue.", + "default": 10 } }, "required": [ @@ -105,11 +118,11 @@ }, "policy": { "type": "object", - "description": "The security policy for the SQS Queue.", + "description": "The security policy for the SQS Queue", "properties": { "statements": { "type": "array", - "description": "An array of Statement objects, each of which controls a permission for this topic.", + "description": "An array of statement objects, each of which controls a permission for this queue.", "items": { "$ref": "#/definitions/statement" } @@ -144,7 +157,7 @@ ] }, "action": { - "description": "The SNS permission being allowed or denied e.g. sns:Publish", + "description": "The SQS permission being allowed or denied e.g. sqs:ReceiveMessage", "oneOf": [ { "type": "string" From 504dc1effd294e82f1fe48bf29bca76c2516e794 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 14:33:07 +0100 Subject: [PATCH 44/76] awsbindings: Replace ops version description and default --- sqs/json_schemas/operation.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sqs/json_schemas/operation.json b/sqs/json_schemas/operation.json index 9e6437a2..6d6e1236 100644 --- a/sqs/json_schemas/operation.json +++ b/sqs/json_schemas/operation.json @@ -20,7 +20,8 @@ }, "bindingVersion": { "type": "string", - "description": "Defaults to latest. The version of this binding." + "description": "The version of this binding.", + "default": "latest" } }, "required": [ From 08a5bfd00ac4a987153de2abb89c045ca9140a1a Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 14:35:54 +0100 Subject: [PATCH 45/76] awsbindings: Update binding version with default --- sns/json_schemas/channel.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sns/json_schemas/channel.json b/sns/json_schemas/channel.json index bf42700e..a4722bf9 100644 --- a/sns/json_schemas/channel.json +++ b/sns/json_schemas/channel.json @@ -27,7 +27,8 @@ }, "bindingVersion": { "type": "string", - "description": "Defaults to latest. The version of this binding." + "description": "The version of this binding.", + "default": "latest" } }, "required": [ From f11a17d048e6a882d5537ae643d107507eebd991 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 14:36:19 +0100 Subject: [PATCH 46/76] awsbindings: Update binding version with default --- sns/json_schemas/operation.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sns/json_schemas/operation.json b/sns/json_schemas/operation.json index be1d3026..e33f7ae5 100644 --- a/sns/json_schemas/operation.json +++ b/sns/json_schemas/operation.json @@ -29,7 +29,8 @@ }, "bindingVersion": { "type": "string", - "description": "Defaults to latest. The version of this binding." + "description": "The version of this binding.", + "default": "latest" } }, "definitions": { From ce32e23ad574be3022c314ac569f1897fbe78d12 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 14:42:42 +0100 Subject: [PATCH 47/76] awsbindings: Fix typo --- sns/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sns/README.md b/sns/README.md index 651b42f1..124cdac8 100644 --- a/sns/README.md +++ b/sns/README.md @@ -41,7 +41,7 @@ SNS supports many optional properties. To mark a channel as SNS, but use default |Field Name | Type | Description| |---|:---:|---| | `type` | string one of: standard or FIFO | **Required.** What type of SNS Topic is this? | -| `contentBasedDepulication` | boolean | **Optional.** True to turn on de-duplication of messages for a channel.| +| `contentBasedDeduplication` | boolean | **Optional.** True to turn on de-duplication of messages for a channel.| #### Policy |Field Name | Type | Description| From 31d0df8f2dd82f099952cbd5b2367fcc0898c89e Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 14:43:11 +0100 Subject: [PATCH 48/76] awsbindings: Fix schema typo --- sns/json_schemas/channel.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sns/json_schemas/channel.json b/sns/json_schemas/channel.json index a4722bf9..f330c699 100644 --- a/sns/json_schemas/channel.json +++ b/sns/json_schemas/channel.json @@ -47,7 +47,7 @@ "FIFO" ] }, - "contentBasedDepulication": { + "contentBasedDeduplication": { "type": "boolean", "description": "True to turn on de-duplication of messages for a channel." } From 9cc5f83634ebfac9003f0ceb556c70b349499371 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 14:48:19 +0100 Subject: [PATCH 49/76] awsbindings: Add requirement for consumers to match spec --- sns/json_schemas/operation.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sns/json_schemas/operation.json b/sns/json_schemas/operation.json index e33f7ae5..5d50605f 100644 --- a/sns/json_schemas/operation.json +++ b/sns/json_schemas/operation.json @@ -33,6 +33,9 @@ "default": "latest" } }, + "required": [ + "consumers" + ], "definitions": { "identifier": { "type": "object", From 4e946c53712509021c86600aa81d252efb60c4c0 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 14:50:12 +0100 Subject: [PATCH 50/76] awsbindings: Move misplaced consumer description --- sns/json_schemas/operation.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sns/json_schemas/operation.json b/sns/json_schemas/operation.json index 5d50605f..d8079b05 100644 --- a/sns/json_schemas/operation.json +++ b/sns/json_schemas/operation.json @@ -64,9 +64,9 @@ }, "consumer": { "type": "object", - "description": "What protocol will this endpoint receive messages by.", "properties": { "protocol": { + "description": "What protocol will this endpoint receive messages by?", "type": "string", "enum": [ "http", From d78083cd79a2f529fedfa801378ccf58f9bbd54a Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 14:50:42 +0100 Subject: [PATCH 51/76] awsbindings: Add missing question mark --- sns/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sns/README.md b/sns/README.md index 124cdac8..62e3e8ea 100644 --- a/sns/README.md +++ b/sns/README.md @@ -111,7 +111,7 @@ We support an array of consumers via the **consumers** field. This allows you to | Field Name | Type | Description | |---|:---:|---| -| `protocol` |string, one of: http, https, email, email-json, sms, sqs, application, lambda, firehose | **Required.** What protocol will this endpoint receive messages by.| +| `protocol` |string, one of: http, https, email, email-json, sms, sqs, application, lambda, firehose | **Required.** What protocol will this endpoint receive messages by? | | `endpoint` |[identifier](#identifier)| **Required.** Where are messages being delivered to?| | `filterPolicy` | [filterPolicy](#filter-policy) | **Optional.** Only receive a subset of messages from the channel, determined by this policy.| | `rawMessageDelivery` | boolean | **Required.** If *true* AWS SNS attributes are removed from the body, and for SQS, SNS message attributes are copied to SQS message attributes. If *false* the SNS attributes are included in the body. | From c988dbdf9031f2c3db13d4b90f79b60ee5fc8a58 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 19 Apr 2023 14:51:56 +0100 Subject: [PATCH 52/76] awsbindings: Keep ref and descriptor consistent --- sns/json_schemas/operation.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sns/json_schemas/operation.json b/sns/json_schemas/operation.json index d8079b05..ac246856 100644 --- a/sns/json_schemas/operation.json +++ b/sns/json_schemas/operation.json @@ -81,8 +81,8 @@ ] }, "endpoint": { + "description": "Where are messages being delivered to?", "$ref": "#/definitions/identifier", - "description": "Where are messages being delivered to?" }, "filterPolicy": { "$ref": "#/definitions/filterPolicy" From e9d29793e354787e43074dd55dfe84e3168e2b6a Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Thu, 20 Apr 2023 10:07:55 +0100 Subject: [PATCH 53/76] awsbindings: Make redrive policy casing consistent --- sns/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sns/README.md b/sns/README.md index 62e3e8ea..f55d59d9 100644 --- a/sns/README.md +++ b/sns/README.md @@ -115,7 +115,7 @@ We support an array of consumers via the **consumers** field. This allows you to | `endpoint` |[identifier](#identifier)| **Required.** Where are messages being delivered to?| | `filterPolicy` | [filterPolicy](#filter-policy) | **Optional.** Only receive a subset of messages from the channel, determined by this policy.| | `rawMessageDelivery` | boolean | **Required.** If *true* AWS SNS attributes are removed from the body, and for SQS, SNS message attributes are copied to SQS message attributes. If *false* the SNS attributes are included in the body. | -| `reDrivePolicy` | [redrivePolicy](#redrive-policy) | **Optional.** Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue. | +| `redrivePolicy` | [redrivePolicy](#redrive-policy) | **Optional.** Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue. | | `deliveryPolicy` | [deliveryPolicy](#delivery-policy) | **Optional.** Policy for retries to HTTP. The parameter is for that [SNS Subscription](https://docs.aws.amazon.com/sns/latest/api/API_Subscribe.html)and overrides any policy on the [SNS Topic](https://docs.aws.amazon.com/sns/latest/api/API_CreateTopic.html).| | `displayName` | string |**Optional.** The display name to use with an SMS subscription | From 26993860ae7f87832b7793589cbbf1bdaa74ba41 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Thu, 20 Apr 2023 10:11:48 +0100 Subject: [PATCH 54/76] awsbindings: Correct MRC description --- sns/json_schemas/operation.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sns/json_schemas/operation.json b/sns/json_schemas/operation.json index ac246856..574bedab 100644 --- a/sns/json_schemas/operation.json +++ b/sns/json_schemas/operation.json @@ -191,7 +191,8 @@ }, "maxReceiveCount": { "type": "integer", - "description": "The SQS queue to use as a dead letter queue (DLQ). Note that you may have a Redrive Policy to put messages that cannot be delivered to an SQS queue, even if you use another protocol to consume messages from the queue, so it is defined at the level of the SNS Operation Binding Object in a Consumer Object (and is applied as part of an SNS Subscription). The SQS Binding describes how to define an SQS Binding that supports defining the target SQS of the Redrive Policy." + "description": "The number of times a message is delivered to the source queue before being moved to the dead-letter queue.", + "default": 10 } }, "required": [ From 4bb2c4f49393ad71326126007a5aa88e2da46c5b Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Thu, 20 Apr 2023 10:12:51 +0100 Subject: [PATCH 55/76] awsbindings: Fix DLQ descriptions --- sns/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sns/README.md b/sns/README.md index f55d59d9..32583610 100644 --- a/sns/README.md +++ b/sns/README.md @@ -152,8 +152,8 @@ We provide an Identifer Object to support providing the identifier of an externa |Field Name | Type | Description| |---|:---:|---| -| `deadLetterQueue` |[Identifier](#identifier)| **Required.** The SQS queue to use as a dead letter queue (DLQ) | -| `maxReceiveCount` |integer| **Optional.** The SQS queue to use as a dead letter queue (DLQ). Note that you may have a Redrive Policy to put messages that cannot be delivered to an SQS queue, even if you use another protocol to consume messages from the queue, so it is defined at the level of the SNS Operation Binding Object in a Consumer Object (and is applied as part of an [SNS Subscription](https://docs.aws.amazon.com/sns/latest/dg/sns-create-subscribe-endpoint-to-topic.html)). The SQS Binding describes how to define an SQS Binding that supports defining the target SQS of the Redrive Policy. | +| `deadLetterQueue` |[Identifier](#identifier)| **Required.** The SQS queue to use as a dead letter queue (DLQ). Note that you may have a Redrive Policy to put messages that cannot be delivered to an SQS queue, even if you use another protocol to consume messages from the queue, so it is defined at the level of the SNS Operation Binding Object in a Consumer Object (and is applied as part of an [SNS Subscription](https://docs.aws.amazon.com/sns/latest/dg/sns-create-subscribe-endpoint-to-topic.html)). The SQS Binding describes how to define an SQS Binding that supports defining the target SQS of the Redrive Policy. | +| `maxReceiveCount` |integer| **Optional.** The number of times a message is delivered to the source queue before being moved to the dead-letter queue. Defaults to 10. | ### Examples From df95b2f034e7d08851fb7802c2e6faed97386585 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Thu, 20 Apr 2023 10:18:23 +0100 Subject: [PATCH 56/76] awsbindings: Fix spacing --- sns/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sns/README.md b/sns/README.md index 32583610..8d103e8f 100644 --- a/sns/README.md +++ b/sns/README.md @@ -116,7 +116,7 @@ We support an array of consumers via the **consumers** field. This allows you to | `filterPolicy` | [filterPolicy](#filter-policy) | **Optional.** Only receive a subset of messages from the channel, determined by this policy.| | `rawMessageDelivery` | boolean | **Required.** If *true* AWS SNS attributes are removed from the body, and for SQS, SNS message attributes are copied to SQS message attributes. If *false* the SNS attributes are included in the body. | | `redrivePolicy` | [redrivePolicy](#redrive-policy) | **Optional.** Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue. | -| `deliveryPolicy` | [deliveryPolicy](#delivery-policy) | **Optional.** Policy for retries to HTTP. The parameter is for that [SNS Subscription](https://docs.aws.amazon.com/sns/latest/api/API_Subscribe.html)and overrides any policy on the [SNS Topic](https://docs.aws.amazon.com/sns/latest/api/API_CreateTopic.html).| +| `deliveryPolicy` | [deliveryPolicy](#delivery-policy) | **Optional.** Policy for retries to HTTP. The parameter is for that [SNS Subscription](https://docs.aws.amazon.com/sns/latest/api/API_Subscribe.html) and overrides any policy on the [SNS Topic](https://docs.aws.amazon.com/sns/latest/api/API_CreateTopic.html). | | `displayName` | string |**Optional.** The display name to use with an SMS subscription | From 1dedbbe60c757fb68f2a571d2d45d0c99d80faa9 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Thu, 20 Apr 2023 10:21:22 +0100 Subject: [PATCH 57/76] awsbindings: Fix casing --- sqs/json_schemas/operation.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqs/json_schemas/operation.json b/sqs/json_schemas/operation.json index 6d6e1236..5b3f432c 100644 --- a/sqs/json_schemas/operation.json +++ b/sqs/json_schemas/operation.json @@ -47,7 +47,7 @@ }, "deliveryDelay": { "type": "integer", - "description": "The number of seconds to delay before a message sent to the queue can be received. used to create a delay queue.", + "description": "The number of seconds to delay before a message sent to the queue can be received. Used to create a delay queue.", "minimum": 0, "maximum": 15, "default": 0 From 2912e3b33623b92c13d317d24d90b98c6f89a6bf Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Thu, 20 Apr 2023 10:23:19 +0100 Subject: [PATCH 58/76] awsbindings: Fix casing on spec --- sqs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqs/README.md b/sqs/README.md index bb962ddb..9061e425 100644 --- a/sqs/README.md +++ b/sqs/README.md @@ -49,7 +49,7 @@ An SQS queue can set up a Dead Letter Queue as part of a Redelivery Policy. To s |$ref | `string` | Allows for an external definition of a queue. The referenced structure MUST be in the format of a [Queue](#queue). If there are conflicts between the referenced definition and this Queue's definition, the behavior is *undefined*.| | `name` | string | **Required.** The name of the queue. When an [SNS Operation Binding Object]() references an SQS queue by name, the identifier should be the one in this field.| | `fifoQueue` | boolean | **Required.** Is this a FIFO queue? | -| `deliveryDelay` | integer | **Optional.** The number of seconds to delay before a message sent to the queue can be received. used to create a *delay queue*. Range is 0 to 15 minutes. Defaults to 0. | +| `deliveryDelay` | integer | **Optional.** The number of seconds to delay before a message sent to the queue can be received. Used to create a *delay queue*. Range is 0 to 15 minutes. Defaults to 0. | | `visibilityTimeout` |integer| **Optional.** The length of time, in seconds, that a consumer locks a message - hiding it from reads - before it is unlocked and can be read again. Range from 0 to 12 hours (43200 seconds). Defaults to 30 seconds. | | `receiveMessageWaitTime` |integer| **Optional.** Determines if the queue uses [short polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html) or [long polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html). Set to zero (the default) the queue reads available messages and returns immediately. Set to a non-zero integer, long polling waits the specified number of seconds for messages to arrive before returning. | | `messageRetentionPeriod` |integer| **Optional.** How long to retain a message on the queue in seconds, unless deleted. The range is 60 (1 minute) to 1,209,600 (14 days). The default is 345,600 (4 days). | From bd26fa4ca322e9c45f741cc863319f0783d89f8f Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Mon, 15 May 2023 15:43:27 +0100 Subject: [PATCH 59/76] change SNS type property to ordering --- sns/README.md | 2 +- sns/json_schemas/channel.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sns/README.md b/sns/README.md index 8d103e8f..53cf3e81 100644 --- a/sns/README.md +++ b/sns/README.md @@ -30,7 +30,7 @@ SNS supports many optional properties. To mark a channel as SNS, but use default |Field Name | Type | Description| |---|:---:|---| | `name` | string | **Required.** The name of the topic. Can be different from the channel name to allow flexibility around AWS resource naming limitations.| -| `type` | [ordering](#ordering)| **Optional.** By default, we assume an unordered SNS topic. This field allows configuration of a FIFO SNS Topic. | +| `ordering` | [ordering](#ordering)| **Optional.** By default, we assume an unordered SNS topic. This field allows configuration of a FIFO SNS Topic. | | `policy` |[policy](#policy) | **Optional.** The security policy for the SNS Topic | | `tags` |Object | **Optional.** Key-value pairs that represent AWS tags on the topic. | |`bindingVersion` | string | **Optional**, defaults to `latest`. The version of this binding.| diff --git a/sns/json_schemas/channel.json b/sns/json_schemas/channel.json index f330c699..68fd9492 100644 --- a/sns/json_schemas/channel.json +++ b/sns/json_schemas/channel.json @@ -15,7 +15,7 @@ "type": "string", "description": "The name of the topic. Can be different from the channel name to allow flexibility around AWS resource naming limitations." }, - "type": { + "ordering": { "$ref": "#/definitions/ordering" }, "policy": { From f5b60608b9fb211b426cda14873e04d1a3cd524a Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Mon, 15 May 2023 15:45:44 +0100 Subject: [PATCH 60/76] update consumer protocol description --- sns/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sns/README.md b/sns/README.md index 53cf3e81..d2cf1241 100644 --- a/sns/README.md +++ b/sns/README.md @@ -111,7 +111,7 @@ We support an array of consumers via the **consumers** field. This allows you to | Field Name | Type | Description | |---|:---:|---| -| `protocol` |string, one of: http, https, email, email-json, sms, sqs, application, lambda, firehose | **Required.** What protocol will this endpoint receive messages by? | +| `protocol` | string | **Required.** The protocol that this endpoint receives messages by. Can be `http`, `https`, `email`, `email-json`, `sms`, `sqs`, `application`, `lambda` or `firehose` | | `endpoint` |[identifier](#identifier)| **Required.** Where are messages being delivered to?| | `filterPolicy` | [filterPolicy](#filter-policy) | **Optional.** Only receive a subset of messages from the channel, determined by this policy.| | `rawMessageDelivery` | boolean | **Required.** If *true* AWS SNS attributes are removed from the body, and for SQS, SNS message attributes are copied to SQS message attributes. If *false* the SNS attributes are included in the body. | From a9fbb732d920fbe6e2354fec97e4c608baeb074b Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Mon, 15 May 2023 15:50:15 +0100 Subject: [PATCH 61/76] correct fifo requirement --- sns/README.md | 2 +- sns/json_schemas/channel.json | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/sns/README.md b/sns/README.md index d2cf1241..89eb2395 100644 --- a/sns/README.md +++ b/sns/README.md @@ -40,7 +40,7 @@ SNS supports many optional properties. To mark a channel as SNS, but use default #### Ordering |Field Name | Type | Description| |---|:---:|---| -| `type` | string one of: standard or FIFO | **Required.** What type of SNS Topic is this? | +| `type` | string | **Required.** Defines the type of SNS Topic. Can be either `standard` or `FIFO`. | | `contentBasedDeduplication` | boolean | **Optional.** True to turn on de-duplication of messages for a channel.| #### Policy diff --git a/sns/json_schemas/channel.json b/sns/json_schemas/channel.json index 68fd9492..49dba9dc 100644 --- a/sns/json_schemas/channel.json +++ b/sns/json_schemas/channel.json @@ -41,7 +41,7 @@ "properties": { "type": { "type": "string", - "description": "What type of SNS Topic is this?", + "description": "Defines the type of SNS Topic.", "enum": [ "standard", "FIFO" @@ -51,7 +51,10 @@ "type": "boolean", "description": "True to turn on de-duplication of messages for a channel." } - } + }, + "required": [ + "type" + ] }, "policy": { "type": "object", From 8c637f4c17182619622ef96e123d28ffaad1e0da Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Mon, 15 May 2023 15:51:20 +0100 Subject: [PATCH 62/76] address deduplication wording --- sns/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sns/README.md b/sns/README.md index 89eb2395..e7fd5ce4 100644 --- a/sns/README.md +++ b/sns/README.md @@ -41,7 +41,7 @@ SNS supports many optional properties. To mark a channel as SNS, but use default |Field Name | Type | Description| |---|:---:|---| | `type` | string | **Required.** Defines the type of SNS Topic. Can be either `standard` or `FIFO`. | -| `contentBasedDeduplication` | boolean | **Optional.** True to turn on de-duplication of messages for a channel.| +| `contentBasedDeduplication` | boolean | **Optional.** Whether the de-duplication of messages should be turned on. Defaults to `false`| #### Policy |Field Name | Type | Description| From 0f947a64376861c87fbb69044074a1ac91a11f24 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Mon, 15 May 2023 15:52:39 +0100 Subject: [PATCH 63/76] fix statements list link --- sns/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sns/README.md b/sns/README.md index e7fd5ce4..a5dbec21 100644 --- a/sns/README.md +++ b/sns/README.md @@ -46,7 +46,7 @@ SNS supports many optional properties. To mark a channel as SNS, but use default #### Policy |Field Name | Type | Description| |---|:---:|---| -| `statements` | [Statement](#statement) | **Required.** An array of Statement objects, each of which controls a permission for this topic | +| `statements` | [[Statement](#statement)] | **Required.** An array of Statement objects, each of which controls a permission for this topic | #### Statement |Field Name | Type | Description| From 343fe184395b56d009bf73d676af67fcad55a645 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Mon, 15 May 2023 15:58:50 +0100 Subject: [PATCH 64/76] add example for sns operation --- sns/json_schemas/operation.json | 51 ++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/sns/json_schemas/operation.json b/sns/json_schemas/operation.json index 574bedab..9174e54a 100644 --- a/sns/json_schemas/operation.json +++ b/sns/json_schemas/operation.json @@ -199,5 +199,54 @@ "deadLetterQueue" ] } - } + }, + "examples": [ + { + "topic": { + "name": "someTopic" + }, + "consumers": [ + { + "protocol": "sqs", + "endpoint": { + "name": "someQueue" + }, + "filterPolicy": { + "attributes": { + "store": [ + "asyncapi_corp" + ], + "event": [ + { + "anything-but": "order_cancelled" + } + ], + "customer_interests": [ + "rugby", + "football", + "baseball" + ] + } + }, + "rawMessageDelivery": false, + "redrivePolicy": { + "deadLetterQueue": { + "arn": "arn:aws:SQS:eu-west-1:0000000:123456789" + }, + "maxReceiveCount": 25 + }, + "deliveryPolicy": { + "minDelayTarget": 10, + "maxDelayTarget": 100, + "numRetries": 5, + "numNoDelayRetries": 2, + "numMinDelayRetries": 3, + "numMaxDelayRetries": 5, + "backoffFunction": "linear", + "maxReceivesPerSecond": 2 + } + } + ] + } + ] } From bd462c526aa370783b5fc3de2fb8796ffc3b872a Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Mon, 15 May 2023 15:59:13 +0100 Subject: [PATCH 65/76] remove trailing comma --- sns/json_schemas/operation.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sns/json_schemas/operation.json b/sns/json_schemas/operation.json index 9174e54a..53758a2c 100644 --- a/sns/json_schemas/operation.json +++ b/sns/json_schemas/operation.json @@ -82,7 +82,7 @@ }, "endpoint": { "description": "Where are messages being delivered to?", - "$ref": "#/definitions/identifier", + "$ref": "#/definitions/identifier" }, "filterPolicy": { "$ref": "#/definitions/filterPolicy" From 891a4ec39a91e8bfe3dbbba6336eecbf60bd90cc Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Mon, 15 May 2023 16:01:24 +0100 Subject: [PATCH 66/76] add SQS channel example --- sqs/json_schemas/channel.json | 43 ++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/sqs/json_schemas/channel.json b/sqs/json_schemas/channel.json index b0dacae4..dec86779 100644 --- a/sqs/json_schemas/channel.json +++ b/sqs/json_schemas/channel.json @@ -179,5 +179,46 @@ "action" ] } - } + }, + "examples": [ + { + "queue": { + "name": "myQueue", + "fifoQueue": true, + "deliveryDelay": 30, + "visibilityTimeout": 60, + "receiveMessageWaitTime": 0, + "messageRetentionPeriod": 86400, + "redrivePolicy": { + "deadLetterQueue": { + "arn": "arn:aws:SQS:eu-west-1:0000000:123456789" + }, + "maxReceiveCount": 15 + }, + "policy": { + "statements": [ + { + "effect": "deny", + "principal": "arn:aws:iam::123456789012:user/dec.kolakowski", + "action": [ + "sqs:SendMessage", + "sqs:ReceiveMessage" + ] + } + ] + }, + "tags": { + "owner": "AsyncAPI.NET", + "platform": "AsyncAPIOrg" + } + }, + "deadLetterQueue": { + "name": "myQueue_error", + "deliveryDelay": 0, + "visibilityTimeout": 0, + "receiveMessageWaitTime": 0, + "messageRetentionPeriod": 604800 + } + } + ] } From 45a51815b39297318f5cf1f4e7b2b72d426860f9 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Mon, 15 May 2023 16:10:49 +0100 Subject: [PATCH 67/76] add examples --- sns/json_schemas/operation.json | 82 ++++++++++++++++----------------- sqs/json_schemas/channel.json | 66 +++++++++++++------------- sqs/json_schemas/operation.json | 34 +++++++++++++- 3 files changed, 107 insertions(+), 75 deletions(-) diff --git a/sns/json_schemas/operation.json b/sns/json_schemas/operation.json index 53758a2c..adf47d71 100644 --- a/sns/json_schemas/operation.json +++ b/sns/json_schemas/operation.json @@ -203,50 +203,50 @@ "examples": [ { "topic": { - "name": "someTopic" + "name": "someTopic" }, "consumers": [ - { - "protocol": "sqs", - "endpoint": { - "name": "someQueue" - }, - "filterPolicy": { - "attributes": { - "store": [ - "asyncapi_corp" - ], - "event": [ - { - "anything-but": "order_cancelled" - } - ], - "customer_interests": [ - "rugby", - "football", - "baseball" - ] - } - }, - "rawMessageDelivery": false, - "redrivePolicy": { - "deadLetterQueue": { - "arn": "arn:aws:SQS:eu-west-1:0000000:123456789" - }, - "maxReceiveCount": 25 - }, - "deliveryPolicy": { - "minDelayTarget": 10, - "maxDelayTarget": 100, - "numRetries": 5, - "numNoDelayRetries": 2, - "numMinDelayRetries": 3, - "numMaxDelayRetries": 5, - "backoffFunction": "linear", - "maxReceivesPerSecond": 2 - } + { + "protocol": "sqs", + "endpoint": { + "name": "someQueue" + }, + "filterPolicy": { + "attributes": { + "store": [ + "asyncapi_corp" + ], + "event": [ + { + "anything-but": "order_cancelled" + } + ], + "customer_interests": [ + "rugby", + "football", + "baseball" + ] + } + }, + "rawMessageDelivery": false, + "redrivePolicy": { + "deadLetterQueue": { + "arn": "arn:aws:SQS:eu-west-1:0000000:123456789" + }, + "maxReceiveCount": 25 + }, + "deliveryPolicy": { + "minDelayTarget": 10, + "maxDelayTarget": 100, + "numRetries": 5, + "numNoDelayRetries": 2, + "numMinDelayRetries": 3, + "numMaxDelayRetries": 5, + "backoffFunction": "linear", + "maxReceivesPerSecond": 2 } + } ] } ] -} +} \ No newline at end of file diff --git a/sqs/json_schemas/channel.json b/sqs/json_schemas/channel.json index dec86779..77c22210 100644 --- a/sqs/json_schemas/channel.json +++ b/sqs/json_schemas/channel.json @@ -92,7 +92,7 @@ "description": "Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue.", "properties": { "deadLetterQueue": { - "$ref": "#/definitions/identifier" + "$ref": "#/definitions/identifier" }, "maxReceiveCount": { "type": "integer", @@ -183,42 +183,42 @@ "examples": [ { "queue": { - "name": "myQueue", - "fifoQueue": true, - "deliveryDelay": 30, - "visibilityTimeout": 60, - "receiveMessageWaitTime": 0, - "messageRetentionPeriod": 86400, - "redrivePolicy": { - "deadLetterQueue": { - "arn": "arn:aws:SQS:eu-west-1:0000000:123456789" - }, - "maxReceiveCount": 15 + "name": "myQueue", + "fifoQueue": true, + "deliveryDelay": 30, + "visibilityTimeout": 60, + "receiveMessageWaitTime": 0, + "messageRetentionPeriod": 86400, + "redrivePolicy": { + "deadLetterQueue": { + "arn": "arn:aws:SQS:eu-west-1:0000000:123456789" }, - "policy": { - "statements": [ - { - "effect": "deny", - "principal": "arn:aws:iam::123456789012:user/dec.kolakowski", - "action": [ - "sqs:SendMessage", - "sqs:ReceiveMessage" - ] - } + "maxReceiveCount": 15 + }, + "policy": { + "statements": [ + { + "effect": "deny", + "principal": "arn:aws:iam::123456789012:user/dec.kolakowski", + "action": [ + "sqs:SendMessage", + "sqs:ReceiveMessage" ] - }, - "tags": { - "owner": "AsyncAPI.NET", - "platform": "AsyncAPIOrg" - } + } + ] + }, + "tags": { + "owner": "AsyncAPI.NET", + "platform": "AsyncAPIOrg" + } }, "deadLetterQueue": { - "name": "myQueue_error", - "deliveryDelay": 0, - "visibilityTimeout": 0, - "receiveMessageWaitTime": 0, - "messageRetentionPeriod": 604800 + "name": "myQueue_error", + "deliveryDelay": 0, + "visibilityTimeout": 0, + "receiveMessageWaitTime": 0, + "messageRetentionPeriod": 604800 } } ] -} +} \ No newline at end of file diff --git a/sqs/json_schemas/operation.json b/sqs/json_schemas/operation.json index 5b3f432c..34114887 100644 --- a/sqs/json_schemas/operation.json +++ b/sqs/json_schemas/operation.json @@ -178,5 +178,37 @@ "action" ] } - } + }, + "examples": [ + { + "queues": [ + { + "name": "myQueue", + "deliveryDelay": 10, + "redrivePolicy": { + "deadLetterQueue": { + "name": "myQueue_error" + }, + "maxReceiveCount": 15 + }, + "policy": { + "statements": [ + { + "effect": "deny", + "principal": "arn:aws:iam::123456789012:user/dec.kolakowski", + "action": [ + "sqs:SendMessage", + "sqs:ReceiveMessage" + ] + } + ] + } + }, + { + "name": "myQueue_error", + "deliveryDelay": 10 + } + ] + } + ] } From 279a08c3e35ed65982809a681e7ef7c4ed7dde4f Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Thu, 18 May 2023 14:32:14 +0100 Subject: [PATCH 68/76] make binding definitions extensible --- sns/json_schemas/channel.json | 15 +++++++++++++++ sns/json_schemas/operation.json | 25 +++++++++++++++++++++++++ sqs/json_schemas/channel.json | 25 +++++++++++++++++++++++++ sqs/json_schemas/operation.json | 25 +++++++++++++++++++++++++ 4 files changed, 90 insertions(+) diff --git a/sns/json_schemas/channel.json b/sns/json_schemas/channel.json index 49dba9dc..6ab5e2f6 100644 --- a/sns/json_schemas/channel.json +++ b/sns/json_schemas/channel.json @@ -38,6 +38,11 @@ "ordering": { "type": "object", "description": "By default, we assume an unordered SNS topic. This field allows configuration of a FIFO SNS Topic.", + "patternProperties": { + "^x-[\\w\\d\\.\\-\\_]+$": { + "$ref": "https://raw.githubusercontent.com/asyncapi/spec-json-schemas/v2.14.0/schemas/2.4.0.json#/definitions/specificationExtension" + } + }, "properties": { "type": { "type": "string", @@ -59,6 +64,11 @@ "policy": { "type": "object", "description": "The security policy for the SNS Topic.", + "patternProperties": { + "^x-[\\w\\d\\.\\-\\_]+$": { + "$ref": "https://raw.githubusercontent.com/asyncapi/spec-json-schemas/v2.14.0/schemas/2.4.0.json#/definitions/specificationExtension" + } + }, "properties": { "statements": { "type": "array", @@ -74,6 +84,11 @@ }, "statement": { "type": "object", + "patternProperties": { + "^x-[\\w\\d\\.\\-\\_]+$": { + "$ref": "https://raw.githubusercontent.com/asyncapi/spec-json-schemas/v2.14.0/schemas/2.4.0.json#/definitions/specificationExtension" + } + }, "properties": { "effect": { "type": "string", diff --git a/sns/json_schemas/operation.json b/sns/json_schemas/operation.json index adf47d71..c8408cf8 100644 --- a/sns/json_schemas/operation.json +++ b/sns/json_schemas/operation.json @@ -39,6 +39,11 @@ "definitions": { "identifier": { "type": "object", + "patternProperties": { + "^x-[\\w\\d\\.\\-\\_]+$": { + "$ref": "https://raw.githubusercontent.com/asyncapi/spec-json-schemas/v2.14.0/schemas/2.4.0.json#/definitions/specificationExtension" + } + }, "properties": { "url": { "type": "string", @@ -64,6 +69,11 @@ }, "consumer": { "type": "object", + "patternProperties": { + "^x-[\\w\\d\\.\\-\\_]+$": { + "$ref": "https://raw.githubusercontent.com/asyncapi/spec-json-schemas/v2.14.0/schemas/2.4.0.json#/definitions/specificationExtension" + } + }, "properties": { "protocol": { "description": "What protocol will this endpoint receive messages by?", @@ -111,6 +121,11 @@ }, "deliveryPolicy": { "type": "object", + "patternProperties": { + "^x-[\\w\\d\\.\\-\\_]+$": { + "$ref": "https://raw.githubusercontent.com/asyncapi/spec-json-schemas/v2.14.0/schemas/2.4.0.json#/definitions/specificationExtension" + } + }, "properties": { "minDelayTarget": { "type": "integer", @@ -155,6 +170,11 @@ "filterPolicy": { "type": "object", "description": "Only receive a subset of messages from the channel, determined by this policy.", + "patternProperties": { + "^x-[\\w\\d\\.\\-\\_]+$": { + "$ref": "https://raw.githubusercontent.com/asyncapi/spec-json-schemas/v2.14.0/schemas/2.4.0.json#/definitions/specificationExtension" + } + }, "properties": { "attributes": { "type": "object", @@ -184,6 +204,11 @@ "redrivePolicy": { "type": "object", "description": "Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue.", + "patternProperties": { + "^x-[\\w\\d\\.\\-\\_]+$": { + "$ref": "https://raw.githubusercontent.com/asyncapi/spec-json-schemas/v2.14.0/schemas/2.4.0.json#/definitions/specificationExtension" + } + }, "properties": { "deadLetterQueue": { "$ref": "#/definitions/identifier", diff --git a/sqs/json_schemas/channel.json b/sqs/json_schemas/channel.json index 77c22210..ea163b75 100644 --- a/sqs/json_schemas/channel.json +++ b/sqs/json_schemas/channel.json @@ -32,6 +32,11 @@ "queue": { "type": "object", "description": "A definition of a queue.", + "patternProperties": { + "^x-[\\w\\d\\.\\-\\_]+$": { + "$ref": "https://raw.githubusercontent.com/asyncapi/spec-json-schemas/v2.14.0/schemas/2.4.0.json#/definitions/specificationExtension" + } + }, "properties": { "$ref": { "type": "string", @@ -90,6 +95,11 @@ "redrivePolicy": { "type": "object", "description": "Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue.", + "patternProperties": { + "^x-[\\w\\d\\.\\-\\_]+$": { + "$ref": "https://raw.githubusercontent.com/asyncapi/spec-json-schemas/v2.14.0/schemas/2.4.0.json#/definitions/specificationExtension" + } + }, "properties": { "deadLetterQueue": { "$ref": "#/definitions/identifier" @@ -107,6 +117,11 @@ "identifier": { "type": "object", "description": "The SQS queue to use as a dead letter queue (DLQ).", + "patternProperties": { + "^x-[\\w\\d\\.\\-\\_]+$": { + "$ref": "https://raw.githubusercontent.com/asyncapi/spec-json-schemas/v2.14.0/schemas/2.4.0.json#/definitions/specificationExtension" + } + }, "properties": { "arn": { "type": "string", @@ -121,6 +136,11 @@ "policy": { "type": "object", "description": "The security policy for the SQS Queue", + "patternProperties": { + "^x-[\\w\\d\\.\\-\\_]+$": { + "$ref": "https://raw.githubusercontent.com/asyncapi/spec-json-schemas/v2.14.0/schemas/2.4.0.json#/definitions/specificationExtension" + } + }, "properties": { "statements": { "type": "array", @@ -136,6 +156,11 @@ }, "statement": { "type": "object", + "patternProperties": { + "^x-[\\w\\d\\.\\-\\_]+$": { + "$ref": "https://raw.githubusercontent.com/asyncapi/spec-json-schemas/v2.14.0/schemas/2.4.0.json#/definitions/specificationExtension" + } + }, "properties": { "effect": { "type": "string", diff --git a/sqs/json_schemas/operation.json b/sqs/json_schemas/operation.json index 34114887..8fab8779 100644 --- a/sqs/json_schemas/operation.json +++ b/sqs/json_schemas/operation.json @@ -31,6 +31,11 @@ "queue": { "type": "object", "description": "A definition of a queue.", + "patternProperties": { + "^x-[\\w\\d\\.\\-\\_]+$": { + "$ref": "https://raw.githubusercontent.com/asyncapi/spec-json-schemas/v2.14.0/schemas/2.4.0.json#/definitions/specificationExtension" + } + }, "properties": { "$ref": { "type": "string", @@ -89,6 +94,11 @@ "redrivePolicy": { "type": "object", "description": "Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue.", + "patternProperties": { + "^x-[\\w\\d\\.\\-\\_]+$": { + "$ref": "https://raw.githubusercontent.com/asyncapi/spec-json-schemas/v2.14.0/schemas/2.4.0.json#/definitions/specificationExtension" + } + }, "properties": { "deadLetterQueue": { "$ref": "#/definitions/identifier" @@ -106,6 +116,11 @@ "identifier": { "type": "object", "description": "The SQS queue to use as a dead letter queue (DLQ).", + "patternProperties": { + "^x-[\\w\\d\\.\\-\\_]+$": { + "$ref": "https://raw.githubusercontent.com/asyncapi/spec-json-schemas/v2.14.0/schemas/2.4.0.json#/definitions/specificationExtension" + } + }, "properties": { "arn": { "type": "string", @@ -120,6 +135,11 @@ "policy": { "type": "object", "description": "The security policy for the SQS Queue", + "patternProperties": { + "^x-[\\w\\d\\.\\-\\_]+$": { + "$ref": "https://raw.githubusercontent.com/asyncapi/spec-json-schemas/v2.14.0/schemas/2.4.0.json#/definitions/specificationExtension" + } + }, "properties": { "statements": { "type": "array", @@ -135,6 +155,11 @@ }, "statement": { "type": "object", + "patternProperties": { + "^x-[\\w\\d\\.\\-\\_]+$": { + "$ref": "https://raw.githubusercontent.com/asyncapi/spec-json-schemas/v2.14.0/schemas/2.4.0.json#/definitions/specificationExtension" + } + }, "properties": { "effect": { "type": "string", From 5491c71d760b660f2becd3d3619e38772fc86da1 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Fri, 19 May 2023 12:04:27 +0100 Subject: [PATCH 69/76] correct binding examples --- sqs/json_schemas/channel.json | 7 ++++--- sqs/json_schemas/operation.json | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/sqs/json_schemas/channel.json b/sqs/json_schemas/channel.json index ea163b75..179d4035 100644 --- a/sqs/json_schemas/channel.json +++ b/sqs/json_schemas/channel.json @@ -89,7 +89,8 @@ } }, "required": [ - "name" + "name", + "fifoQueue" ] }, "redrivePolicy": { @@ -210,7 +211,7 @@ "queue": { "name": "myQueue", "fifoQueue": true, - "deliveryDelay": 30, + "deliveryDelay": 15, "visibilityTimeout": 60, "receiveMessageWaitTime": 0, "messageRetentionPeriod": 86400, @@ -223,7 +224,7 @@ "policy": { "statements": [ { - "effect": "deny", + "effect": "Deny", "principal": "arn:aws:iam::123456789012:user/dec.kolakowski", "action": [ "sqs:SendMessage", diff --git a/sqs/json_schemas/operation.json b/sqs/json_schemas/operation.json index 8fab8779..9f26e977 100644 --- a/sqs/json_schemas/operation.json +++ b/sqs/json_schemas/operation.json @@ -219,7 +219,7 @@ "policy": { "statements": [ { - "effect": "deny", + "effect": "Deny", "principal": "arn:aws:iam::123456789012:user/dec.kolakowski", "action": [ "sqs:SendMessage", From 3e131919a61d27c11f536f59f3e9bb3a0795e93b Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Fri, 19 May 2023 12:04:40 +0100 Subject: [PATCH 70/76] add dpwdec as sns/sqs codeowner --- CODEOWNERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CODEOWNERS b/CODEOWNERS index 2feaec97..ca50f0c4 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -14,4 +14,6 @@ /googlepubsub/ @whitlockjc /solace/ @damaru-inc @CameronRushton /pulsar/ @VisualBean +/sns/ @dpwdec +/sqs/ @dpwdec *.json @KhudaDad414 From 604f8ff9f9f2dc3b921c80a0774b75fbd739ef62 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Fri, 19 May 2023 13:04:35 +0100 Subject: [PATCH 71/76] fix example --- sns/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sns/README.md b/sns/README.md index a5dbec21..6aede9c6 100644 --- a/sns/README.md +++ b/sns/README.md @@ -174,11 +174,11 @@ channels: description: send messages to the topic bindings: sns: - policy: - statements: - - effect : Allow - principal: * - action: SNS:Publish + consumers: + - protocol: sqs + endpoint: + name: myQueue + rawMessageDelivery: false ``` We are consuming an SNS channel, using an SQS queue. A separate file specifies the producer, and has the SNS Bindings for the channel. For this reason we do not repeat the SNS binding information for the channel here, to avoid duplicated definitions diverging. Instead we just define the **publish** Operation Binding. From bf3d591fee38f818b718fd02fa374a6d6d88bfbc Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Thu, 8 Jun 2023 10:54:01 +0100 Subject: [PATCH 72/76] remove queue ref --- sqs/README.md | 1 - sqs/json_schemas/channel.json | 4 ---- 2 files changed, 5 deletions(-) diff --git a/sqs/README.md b/sqs/README.md index 9061e425..1475139d 100644 --- a/sqs/README.md +++ b/sqs/README.md @@ -46,7 +46,6 @@ An SQS queue can set up a Dead Letter Queue as part of a Redelivery Policy. To s #### Queue |Field Name | Type | Description| |---|:---:|---| -|$ref | `string` | Allows for an external definition of a queue. The referenced structure MUST be in the format of a [Queue](#queue). If there are conflicts between the referenced definition and this Queue's definition, the behavior is *undefined*.| | `name` | string | **Required.** The name of the queue. When an [SNS Operation Binding Object]() references an SQS queue by name, the identifier should be the one in this field.| | `fifoQueue` | boolean | **Required.** Is this a FIFO queue? | | `deliveryDelay` | integer | **Optional.** The number of seconds to delay before a message sent to the queue can be received. Used to create a *delay queue*. Range is 0 to 15 minutes. Defaults to 0. | diff --git a/sqs/json_schemas/channel.json b/sqs/json_schemas/channel.json index 179d4035..3930780a 100644 --- a/sqs/json_schemas/channel.json +++ b/sqs/json_schemas/channel.json @@ -38,10 +38,6 @@ } }, "properties": { - "$ref": { - "type": "string", - "description": "Allows for an external definition of a queue. The referenced structure MUST be in the format of a Queue. If there are conflicts between the referenced definition and this Queue's definition, the behavior is undefined." - }, "name": { "type": "string", "description": "The name of the queue. When an SNS Operation Binding Object references an SQS queue by name, the identifier should be the one in this field." From 49dc0b2346a56ef167bcba7f91864844d9dab073 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Mon, 12 Jun 2023 10:12:06 +0100 Subject: [PATCH 73/76] reword descriptions to be declarative --- sns/README.md | 4 ++-- sns/json_schemas/operation.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sns/README.md b/sns/README.md index 6aede9c6..26a78576 100644 --- a/sns/README.md +++ b/sns/README.md @@ -112,8 +112,8 @@ We support an array of consumers via the **consumers** field. This allows you to | Field Name | Type | Description | |---|:---:|---| | `protocol` | string | **Required.** The protocol that this endpoint receives messages by. Can be `http`, `https`, `email`, `email-json`, `sms`, `sqs`, `application`, `lambda` or `firehose` | -| `endpoint` |[identifier](#identifier)| **Required.** Where are messages being delivered to?| -| `filterPolicy` | [filterPolicy](#filter-policy) | **Optional.** Only receive a subset of messages from the channel, determined by this policy.| +| `endpoint` |[identifier](#identifier)| **Required.** The endpoint messages are delivered to. | +| `filterPolicy` | [filterPolicy](#filter-policy) | **Optional.** Only receive a subset of messages from the channel, determined by this policy. | | `rawMessageDelivery` | boolean | **Required.** If *true* AWS SNS attributes are removed from the body, and for SQS, SNS message attributes are copied to SQS message attributes. If *false* the SNS attributes are included in the body. | | `redrivePolicy` | [redrivePolicy](#redrive-policy) | **Optional.** Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue. | | `deliveryPolicy` | [deliveryPolicy](#delivery-policy) | **Optional.** Policy for retries to HTTP. The parameter is for that [SNS Subscription](https://docs.aws.amazon.com/sns/latest/api/API_Subscribe.html) and overrides any policy on the [SNS Topic](https://docs.aws.amazon.com/sns/latest/api/API_CreateTopic.html). | diff --git a/sns/json_schemas/operation.json b/sns/json_schemas/operation.json index c8408cf8..df59a327 100644 --- a/sns/json_schemas/operation.json +++ b/sns/json_schemas/operation.json @@ -76,7 +76,7 @@ }, "properties": { "protocol": { - "description": "What protocol will this endpoint receive messages by?", + "description": "The protocol that this endpoint receives messages by.", "type": "string", "enum": [ "http", @@ -91,7 +91,7 @@ ] }, "endpoint": { - "description": "Where are messages being delivered to?", + "description": "The endpoint messages are delivered to.", "$ref": "#/definitions/identifier" }, "filterPolicy": { From 9b4d1749aedbbccd96c49f7ac1a67b74985012b1 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski <51292634+dpwdec@users.noreply.github.com> Date: Wed, 28 Jun 2023 11:11:47 +0100 Subject: [PATCH 74/76] Delete .DS_Store --- .DS_Store | Bin 8196 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index ea4dd271710dee1492830a432326f9b1cc97223e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHMNo*WN6#d_8R~B3jPVAoGWQdi-gfX!#Vta6wu|0|7EXp!o6BDOrx)Zl(ciYoF zo;b#6kU+T*1PH_?A)(wt$O#0waA8pdVi5|02;~45jtB%2C&aI=9+TLyxB*eRq^eg{ z|Np7_zg~Cww*dgVb9xIv9RMg)1@h(8+@=V*sEbNTFjG#5WDglD?Kl>7p>&aQI1xr5 zj6fKHFalu&!U+5?A|NhmD#{Y~zLbV-7=bVXcVz^``yonIU?RYRME})6jh_M#meI6d zsLw@*FdASYz=A}QP(f)*C`~a)F;JS*d^FHY1Xz$L%>jet1A~<@$WYKtLaJ0biL;0Z?UAbth}O9QI;vo zRxW!qHSXk7p62D;ZY_IUj1Ftwcsl6!(+7e1zLp*|jr2YjNGi@X58=Ja8Dx*WD ztvmT{Cui%f|2ruuP!y)HFgYM-5B!%xNR3 zd4@a2t6XxkFXPyUv&J;JG?a0y+=NY%>WpS(a-?i@SyswCYq-OnamEw9W3H3+dVIxU zlWfJ@7+)pq4^4WeW4nV!)+J=@tre^5H*9*adD|nqlGj$=Q^l)SF?Ni?VSDB&)5s3w zP2C$G(cFw->!y8rXxenmv}N?$+JsS!M;N=drnYXS8d2{niWZtEyg?bxrOm0F>CO0S ztXr?LQJr>v(9y*zI)7JTzNBHjsvZ}To~%Kwt|xMpWBrfOIdYe_ zAU598%G3c%OB)u~nKWx_XX?(yRG84=PhU8h|&BpT&m`(bEEG|LeecZ&)!*a>^!7-Wd+d3XlS!?W-j zT!72)4txNgz-RCUd^mihxieGj$h;V za)%{FvL2MlzxHTHCjG&7b6g zv%8r@K64~Be99Cl;UC^DJQSy`M%J?WrMNsmj5E$Cf;PNTYDXg*6k-bZsiHrv%3E2BLiFV2Qu;7!V?_ zFYYDwrLZ3daR^6MZ6I+6eHUi$n0o$O+`_b>us1pXlcSe8sByGd!Om%PZe zqf}2)6-DS3B>E=Q_~|&IpN Date: Mon, 3 Jul 2023 15:51:27 +0100 Subject: [PATCH 75/76] feat: migrate conventions to PR #211 --- Conventions.md | 301 ------------------------------------------------- 1 file changed, 301 deletions(-) delete mode 100644 Conventions.md diff --git a/Conventions.md b/Conventions.md deleted file mode 100644 index 30ddc573..00000000 --- a/Conventions.md +++ /dev/null @@ -1,301 +0,0 @@ -# Conventions -## What is this? -This document describes a set of conventions that implementers may adopt when describing [Channel](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#channelBindingsObject), [Operation](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#operationBindingsObject) or [Message](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#messageBindingsObject) bindings for different protocols. - -## Why Adopt These? -AsyncAPI does not constrain how Bindings are defined, beyond a valid JSON schema. This makes Bindings flexible extension points for implementers. This flexibility is powerful, but it comes at a price in that it can be hard for implementers to understand how to use Bindings consistently, which makes it difficult for those writing tools that work with AsyncAPI to support a range of protocols. - -## What Belongs on a Binding? -The Binding should be used to provide configuration data that a protocol requires. That configuration may be exposed via Message-Oriented-Middleware (MoM) using a Management API that allows code to configure the MoM as described. The fields in a Binding should represent protocol specific metadata, that is not exposed as an existing field on the Channel, Operation or Message objects. - -A Binding may also be used by the providers of SDKs for MoM to provide metadata to configure producers or consumers using that SDK. That is outside the scope of advice here, but SDK owners wishing to use Bindings may follow the general advice here. - -## Effective Bindings -### **Item 1** Use the Extensions Format -Prefer use of the [Bindings Extensions](https://github.com/asyncapi/extensions-catalog) format when defining a binding over raw JSON Schema. - -The Binding Extensions format works with tools because it indicates where in the specification the binding should be used via a Hook. Using a Hook signals clearly to the user of an extension on which of Channel, Operation or Message the binding can be used. Implementers may choose to use author a binding so that the only fields on the binding are those appropriate to the object identified by the Hook. It also makes it possible for tools to determine correctness of an AsyncAPI file by ensuring that the binding is only used where permitted. - -### **Item** 2 Prefer JSON for Bindings -Prefer the use of JSON to define a Binding. - -[The AsyncAPI specification is in JSON](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#format), so using JSON to define the Binding assures consistency of the format of the two. - -Whilst both JSON and YAML are human readable, YAML is more readable. As [YAML is a superset of JSON](https://yaml.org/spec/1.2/spec.html#id2759572) users may prefer to write AsyncAPI files in YAML, benefitting from the improved readability. - -However, as JSON is a subset of YAML, defining the Binding in YAML risks using parts of the specification not supported by JSON. As it is possible to use a binding defined in JSON from YAML (this is true of AsyncAPI in general), authoring a binding in JSON ensures that implementers stick to the subset defined by JSON when defining the Binding. - -Writing the Binding in JSON uses the common subset of JSON and YAML and should be preferred. - -### **Item 3** Support Infrastructure as Code -Design your binding to support Infrastructure as Code (IaC) scenarios, so that it is possible to use the Binding with a [Generator](https://github.com/asyncapi/generator) [template](https://github.com/asyncapi/template-for-generator-templates) to generate code that will allow repeatable infrastructure for asynchronous communication. At a minimum, the binding should support the variables required by the transport's management API to create required infrastructure. - -Not all uses of a Binding have Infrastructure as Code as a goal, and not all parameters to API calls tend to be required, so it is important to avoid using required fields on any bindings where the information is likely needed in IaC or Contract-First scenarios [see Item 4](#item-4-support-contract-first--scaffolding). - -Some transports do not provide a specification of a management API used to create infrastructure but instead have middleware specific APIs. To support a protocol that does not define infrastructure creation as part of its standard, consider a binding for the middleware in addition to the protocol i.e. AMQP 1-0-0. - -### **Item 4** Support Contract First && Scaffolding -Design your binding to support Contract First definition of an endpoint that is later used with [Scaffolding](https://en.wikipedia.org/wiki/Scaffold_(programming)) to generate the skeleton of an application. Contract Fist scenarios requires the binding to support the necessary parameters to either produce or consume messages via the API or SDK. - -Code generation from an AsyncAPI definition, particularly for consumers, is a use case that improves developer productivity and tends to drive adoption. Not all uses of a Binding have later generation of code via Scaffolding as a goal. - -There may be multiple SDKs for a particular protocol, for different languages and frameworks. In many cases the variables required by these targets remain common across the targets and can simply be inferred from the protocol. In this case it is possible to define a common set of fields for a binding that can be used by Scaffolding regardless of the SDK. In other cases, SDKs vary considerably for the middleware. In this case you may prefer to provide a binding for the middleware that facilitates code generation for that middleware. - -### **Item 5** Assume Separate Endpoints Have Separate AsyncAPI Files -Producers and consumers are usually separate apps, they may belong to separate teams, and under models such as pub-sub, there may an architectural goal to decouple producer and consumer by ensuring that each knows about the channel, but not the other. For this reason, you should assume that it will be common to define separate endpoints for the producer and consumer, but that the channel and the message schema will be shared. (Users may use $ref to prevent duplication, but that does not change these guidelines). - -### **Item 6** The Channel Binding Describes the 'Virtual Pipe' -Design your binding to support the separation of the definitions of producer and consumer endpoints. The [Channel Binding](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#channelBindingsObject) should contain the data required to create a channel via [Infrastructure as Code](#item-3-support-infrastructure-as-code). - -```yml -channels: - quux: - subscribe: - summary: Messages about quux - operationId: sendQuux - $ref: "#/components/messages/quuxEvent" - bindings: - amqp: - exchange: - name: myExchange - type: topic - durable: true - autoDelete: false - vhost: / - bindingVersion: 0.1.0 -``` - -```yml -channels: - quux: - subscribe: - summary: Messages about quux - operationId: sendQuux - $ref: "#/components/messages/quuxEvent" - bindings: - kafka: - topic: - partitioner: ConsistentRandom - numOfPartitions: 6 - replicationFactor: 3 -``` - -The Channel Binding should not contain the data required to create a subscription to the channel, or to publish to the channel. Note that the name of the channel for use by middleware is given by the name of the Channel object, which would be 'quux' in the example above. - - -### **Item 7** The Subscribe Operation Binding on a Producer Describes How We Send -Design your binding to support the separation of the definitions of producer and consumer endpoints. The Subscribe [Operation Binding](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#operationBindingsObject) on a producer should contain the data required to publish to a channel via [Infrastructure as Code](#item-3-support-infrastructure-as-code). Commonly, there may be reliability and security requirements for the producer. The binding should also contain any data required to support [Contract First](#item-4-support-contract-first--scaffolding) development. - -```yml -channels: - quux: - subscribe: - summary: Messages about quux - operationId: sendQuux - $ref: "#/components/messages/quuxEvent" - bindings: - amqp: - producer: - confirmSelect: true - bindings: - amqp: - exchange: - name: myExchange - type: topic - durable: true - autoDelete: false - vhost: / - bindingVersion: 0.1.0 -``` - -```yml -channels: - quux: - subscribe: - summary: Messages about quux - operationId: sendQuux - $ref: "#/components/messages/quuxEvent" - kafka: - producer: - transactionalId: Foo - replication: Acks.All - batchMessages: 10 - retries: 3 - queue_strategy: fifo - max_in_flight: 5 - - bindings: - kafka: - topic: - partitioner: ConsistentRandom - numOfPartitions: 6 - replicationFactor: 3 -``` - -Note that the producer defines what it exposes - a subscribe operation because it can be subscribed to - so the middleware 'publication' is defined on the consumer's publish operation. This catches out some users of AsyncAPI. - -### **Item 8** The Publish Operation Binding on a Consumer Describes How We Receive -Design your binding to support the separation of the definitions of producer and consumer endpoints. The Publish [Operation Binding](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#operationBindingsObject) on a consumer should contain the data required to receive from a channel via [Infrastructure as Code](#item-3-support-infrastructure-as-code). Commonly, a subscription must be made to the channel to route messages to the consumer. There may also be security requirements for the consumer to receive messages. Where middleware uses a queue, this will typically be defined as part of the Operation Binding on the consumer. The binding should also contain any data required to support [Contract First](#item-4-support-contract-first--scaffolding) development. - -```yml -channels: - quux: - publish: - summary: Messages about quux - operationId: sendQuux - $ref: "#/components/messages/quuxEvent" - bindings: - amqp: - queue: - name: myQueue - type: topic - durable: true - autoDelete: false - bindingVersion: 0.1.0 - bindings: - amqp: - exchange: - name: myExchange - type: topic - durable: true - autoDelete: false - vhost: / - bindingVersion: 0.1.0 -``` - -```yml -channels: - quux: - publish: - summary: Messages about quux - operationId: sendQuux - $ref: "#/components/messages/quuxEvent" - bindings: - kafka: - consumer: - group: myGroup - maxPollIntervalInMs: 100 - enableAutoOffsetStore: true - enableAutoCommit: true - bindings: - kafka: - topic: - partitioner: ConsistentRandom - numOfPartitions: 6 - replicationFactor: 3 -``` - - -Note that the consumer defines what it exposes - a publish operation because it can be published to - so the middleware 'subscription' is defined on the consumer's publish operation. This catches out some users of AsyncAPI. - -### **Item 9** Define Protocol Required Message Properties as Schema not Bindings -A [Message](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#messageBindingsObject) consists of headers (metadata) and payload (data); AsyncAPI also defines some common metadata values as fields of a Message, for example correlationId. The headers are defined as a [Schema](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#schemaObject) object under [Components](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#componentsObject). A payload may be of any type, but defaults to JSON Schema. [MessageTraits](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#messageTraitObject) allow the definition of metadata values related to a protocol once, rather than per message, and simplify the use of protocol related message metadata when defining message headers. - -Where a protocol defines metadata that forms part of the message sent via middleware it should be defined as part of the header schema (potentially as MessageTraits), and where the protocol defines data (or transmits metadata in the payload) it should be defined as part of the payload. Note that the payload does not support MessageTraits. - -Tooling to validate that messages match the schema will expect to verify against the schema of the message payload and headers, putting message metadata into a Message Binding makes this harder as tooling must know to look there as well. - -Implementers of producers or consumers are also likely to assume that the the can refer to #/Components/Schema to understand payloads and headers, and adding metadata into bindings in addition makes it harder to comprehend the schema of a message. - -A [Message Binding](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#messageBindingsObject) should be used to define metadata about the protocol's message format that is used for [Infrastructure as Code](#item-3-support-infrastructure-as-code) or [Scaffolding](#item-4-support-contract-first--scaffolding). Don't use the Message Bindings to describe what is sent; use the Message Binding to describe how it is sent, if required. - -```yml -channels: - quux: - subscribe: - summary: Messages about quux - operationId: sendQuux - $ref: "#/components/messages/quuxEvent" - -... - -components: - schemas: - quux: - type: object - properties: - quuxDetails: - type: string - amqpBasicProperties: - type: object - properties: - content_encoding: - type: string - delivery-mode: - type: integer - minimum: 0 - maximum: 1 - priority: - type: integer - minimum: 0 - maximum: 9 - correlation-id: - type: string - reply-to: - type: string - expiration: - type: string - message-id: - type: string - timestamp: - type: string - type: - type: string - user-id: - type: string - app-id: - type: string - - messages: - quuxEvent: - summary: Raised when a quux occurs. - description: When a quux happens, describes the quux - contentType: application/json - payload: - $ref: "#/components/schemas/quux" - traits: - $ref: "#/components/schemas/amqpBasicProperties" - - -``` - -### **Item 10** Be Consistent with Other Protocols -Design your binding with the possibility that a producer might expose a message over different bindings - so as to support a wider range of consumers. By following the guidelines in this document your binding should be compatible with other bindings, and simplify the development of tooling that supports those because they operate at the same level. - -```yml -channels: - quux: - subscribe: - summary: Messages about quux - operationId: sendQuux - $ref: "#/components/messages/quuxEvent" - bindings: - amqp: - producer: - confirmSelect: true - kafka: - producer: - transactionalId: Foo - replication: Acks.All - batchMessages: 10 - retries: 3 - queue_strategy: fifo - max_in_flight: 5 - - bindings: - amqp: - exchange: - name: myExchange - type: topic - durable: true - autoDelete: false - vhost: / - bindingVersion: 0.1.0 - kafka: - topic: - partitioner: ConsistentRandom - numOfPartitions: 6 - replicationFactor: 3 -``` - - From edf05632ff6a63e4fb84b4765b324fd298f13b72 Mon Sep 17 00:00:00 2001 From: Dec Kolakowski Date: Tue, 18 Jul 2023 15:05:10 +0100 Subject: [PATCH 76/76] feat: update CODEOWNERS to include iancooper --- CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 622691b1..b97cdeea 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -15,6 +15,6 @@ /googlepubsub/ @whitlockjc /solace/ @damaru-inc @CameronRushton /pulsar/ @VisualBean -/sns/ @dpwdec -/sqs/ @dpwdec +/sns/ @dpwdec @iancooper +/sqs/ @dpwdec @iancooper *.json @KhudaDad414