diff --git a/README.md b/README.md index 31a7cfd..e6f2aeb 100644 --- a/README.md +++ b/README.md @@ -7,21 +7,48 @@ - [Azure Service Bus Command Line Tool](#azure-service-bus-command-line-tool) - [Index](#index) - [**How to Use it**](#how-to-use-it) - - [**Topics**](#topics) - - [**List Topics**](#list-topics) - - [**Create Topic**](#create-topic) - - [**Delete Topic**](#delete-topic) - - [**List Subscription for a Topic**](#list-subscription-for-a-topic) - - [**Create Topic Subscription**](#create-topic-subscription) - - [**Delete Topic Subscription**](#delete-topic-subscription) + - [API Mode](#api-mode) + - [[GET] /topics](#get-topics) + - [[POST] /topics](#post-topics) + - [[GET] /topics/{topic_name}](#get-topicstopic_name) + - [[DELETE] /topics/{topic_name}](#delete-topicstopic_name) + - [[PUT] /topics/{topic_name}/send](#put-topicstopic_namesend) + - [[PUT] /topics/{topic_name}/sendbulk](#put-topicstopic_namesendbulk) + - [[PUT] /topics/{topic_name}/sendbulktemplate](#put-topicstopic_namesendbulktemplate) + - [[GET] /topics/{topic_name}/subscriptions](#get-topicstopic_namesubscriptions) + - [[POST] /topics/{topic_name}/subscriptions](#post-topicstopic_namesubscriptions) + - [[GET] /topics/{topic_name}/{subscription_name}](#get-topicstopic_namesubscription_name) + - [[DELETE] /topics/{topic_name}/{subscription_name}](#delete-topicstopic_namesubscription_name) + - [[GET] /topics/{topic_name}/{subscription_name}/deadletters](#get-topicstopic_namesubscription_namedeadletters) + - [[GET] /topics/{topic_name}/{subscription_name}/messages](#get-topicstopic_namesubscription_namemessages) + - [[GET] /topics/{topic_name}/{subscription_name}/rules](#get-topicstopic_namesubscription_namerules) + - [[POST] /topics/{topic_name}/{subscription_name}/rules](#post-topicstopic_namesubscription_namerules) + - [[GET] /topics/{topic_name}/{subscription_name}/rules/{rule_name}](#get-topicstopic_namesubscription_namerulesrule_name) + - [[DELETE] /topics/{topic_name}/{subscription_name}/rules/{rule_name}](#delete-topicstopic_namesubscription_namerulesrule_name) + - [[GET] /queues](#get-queues) + - [[POST] /queues](#post-queues) + - [[GET] /queues/{queue_name}](#get-queuesqueue_name) + - [[DELETE] /queues/{queue_name}](#delete-queuesqueue_name) + - [[PUT] /queues/{queue_name}/send](#put-queuesqueue_namesend) + - [[PUT] /topics/{queue_name}/sendbulk](#put-topicsqueue_namesendbulk) + - [[PUT] /topics/{queue_name}/sendbulktemplate](#put-topicsqueue_namesendbulktemplate) + - [[GET] /queues/{queue_name}/deadletters](#get-queuesqueue_namedeadletters) + - [[GET] /queues/{queue_name}/messages](#get-queuesqueue_namemessages) + - [Topics](#topics) + - [List Topics](#list-topics) + - [Create Topic](#create-topic) + - [Delete Topic](#delete-topic) + - [List Subscription for a Topic](#list-subscription-for-a-topic) + - [Create Topic Subscription](#create-topic-subscription) + - [Delete Topic Subscription](#delete-topic-subscription) - [Subscribe to a Topic Subscription](#subscribe-to-a-topic-subscription) - - [**Send a Message to a Topic**](#send-a-message-to-a-topic) - - [**Queues**](#queues) - - [**List Queues**](#list-queues) - - [**Create Queue**](#create-queue) - - [**Delete Queue**](#delete-queue) - - [**Subscribe to a Queue**](#subscribe-to-a-queue) - - [**Send a Message to a Queue**](#send-a-message-to-a-queue) + - [Send a Message to a Topic](#send-a-message-to-a-topic) + - [Queues](#queues) + - [List Queues](#list-queues) + - [Create Queue](#create-queue) + - [Delete Queue](#delete-queue) + - [Subscribe to a Queue](#subscribe-to-a-queue) + - [Send a Message to a Queue](#send-a-message-to-a-queue) This is a command line tool to help test service bus messages. @@ -37,9 +64,369 @@ you can also run the following command to display the help servicebus.exe --help ``` -## **Topics** +## API Mode -### **List Topics** +The ServiceBus Client contains an API mode that gives the same functionality but using a REST api +To start the client in API mode run the following command. + +```bash +servicebus.exe api +``` + +### [GET] /topics + +Returns all the topics in the namespace + +### [POST] /topics + +Creates a Topic in the namespace + +Example Payload: + +```json +{ + "name": "example", + "options": { + "autoDeleteOnIdle": "24h", + "enableBatchedOperation": true, + "enableDuplicateDetection": "30m", + "enableExpress": false, + "maxSizeInMegabytes": 10, + "defaultMessageTimeToLive": "1d", + "supportOrdering": true, + "enablePartitioning": true + } +} +``` + +### [GET] /topics/{topic_name} + +Returns the details of a specific topic in the namespace + +### [DELETE] /topics/{topic_name} + +Deletes a specific topic from the namespace, this will also delete any subscriptions and messages in the same topic + +### [PUT] /topics/{topic_name}/send + +Sends a message to the specific topic + +Example Payload: + +```json +{ + "label": "example", + "correlationId": "test", + "contentType": "application/json", + "data": { + "key": "value" + }, + "userProperties": { + "name": "test message" + } +} +``` + +### [PUT] /topics/{topic_name}/sendbulk + +Sends bulk messages to the specific topic + +Example Payload: + +```json +{ + "messages": [ + { + "label": "example", + "correlationId": "test", + "contentType": "application/json", + "data": { + "key": "value1" + }, + "userProperties": { + "name": "test message1" + } + }, + { + "label": "example", + "correlationId": "test", + "contentType": "application/json", + "data": { + "key": "value2" + }, + "userProperties": { + "name": "test message2" + } + } + ] +} +``` + +### [PUT] /topics/{topic_name}/sendbulktemplate + +Sends a templated bulk messages to the specific topic, it can set a wait time between batches +You can define in how many batches you want to send the amount of message and a wait time between each batches. + +**Attention**: if the volume of messages is big, the messages will be split in batches automatically, this also happens if the batch is too small for the maximum allowed size of a payload + +Example Payload: + +```json +{ + "totalMessages": 50, // Number of total messages to send, if not defined it will be set to 1 + "batchOf": 5, // send the total message in how many batches, if not defined it will be set to 1 + "waitBetweenBatchesInMilli": 500, // wait between any batches, if not defined it will be 0 + "template": { // Message template + "label": "example", + "correlationId": "test", + "contentType": "application/json", + "data": { + "key": "value2" + }, + "userProperties": { + "name": "test message2" + } + } +} +``` + +### [GET] /topics/{topic_name}/subscriptions + +Returns all the subscriptions in the specific topic + +### [POST] /topics/{topic_name}/subscriptions + +Creates a subscription in the specific topic + +Example Payload: + +```json +{ + "name": "wiretap", + "topicName": "example", + "maxDeliveryCount": 5, + "forward": { + "to": "otherTopic", + "in": "Topic" + }, + "forwardDeadLetter": { + "to": "otherQueue", + "in": "Queue" + }, + "rules": [ + { + "name": "example_rule", + "sqlFilter": "2=2", + "sqlAction": "SET A='one'" + } + ], + "options":{ + "autoDeleteOnIdle": "24h", + "defaultMessageTimeToLive": "1d", + "lockDuration": "30s", + "enableBatchedOperation": true, + "deadLetteringOnMessageExpiration": false, + "requireSession": false + } +} +``` + +### [GET] /topics/{topic_name}/{subscription_name} + +Returns a subscription detail from a specific topic + +### [DELETE] /topics/{topic_name}/{subscription_name} + +Deletes a subscription from a specific topic + +### [GET] /topics/{topic_name}/{subscription_name}/deadletters + +Gets the dead letters from a subscription in a topic + +**Query Attributes** +*qty*, *integer*: amount of messages to collect, defaults to all with a maximum of 100 messages +*peek*, *bool*: sets the collection mode to peek, messages will remain in the subscription, defaults to false + +### [GET] /topics/{topic_name}/{subscription_name}/messages + +Gets the dead letters from a subscription in a topic + +**Query Attributes** +*qty*, *integer*: amount of messages to collect, defaults to all with a maximum of 100 messages +*peek*, *bool*: sets the collection mode to peek, messages will remain in the subscription, defaults to false + +### [GET] /topics/{topic_name}/{subscription_name}/rules + +Gets all the rules in a subscription + +### [POST] /topics/{topic_name}/{subscription_name}/rules + +Creates a rule in a subscription + +Example Payload: + +```json +{ + "name": "example_rule", + "sqlFilter": "2=2", + "sqlAction": "SET A='one'" +} +``` + +### [GET] /topics/{topic_name}/{subscription_name}/rules/{rule_name} + +Gets the details of a specific rule in a subscription + +### [DELETE] /topics/{topic_name}/{subscription_name}/rules/{rule_name} + +Deletes a specific rule in a subscription + +### [GET] /queues + +Returns all the queues in the namespace + +### [POST] /queues + +Creates a queue in the namespace + +Example Payload: + +```json +{ + "name": "example", + "maxDeliveryCount": 5, + "forward": { + "to": "otherTopic", + "in": "Topic" + }, + "forwardDeadLetter": { + "to": "otherQueue", + "in": "Queue" + }, + "options": { + "autoDeleteOnIdle": "24h", + "enableDuplicateDetection": "30m", + "maxSizeInMegabytes": 10, + "defaultMessageTimeToLive": "1d", + "lockDuration": "30s", + "supportOrdering": true, + "enablePartitioning": true, + "requireSession": false, + "deadLetteringOnMessageExpiration": false + } +} +``` + +### [GET] /queues/{queue_name} + +Returns the details of a specific queue in the namespace + +### [DELETE] /queues/{queue_name} + +Deletes a specific queue from the namespace, this will also delete any subscriptions and messages in the same topic + +### [PUT] /queues/{queue_name}/send + +Sends a message to the specific queue + +Example Payload: + +```json +{ + "label": "example", + "correlationId": "test", + "contentType": "application/json", + "data": { + "key": "value" + }, + "userProperties": { + "name": "test message" + } +} +``` + +### [PUT] /topics/{queue_name}/sendbulk + +Sends bulk messages to the specific queue + +Example Payload: + +```json +{ + "messages": [ + { + "label": "example", + "correlationId": "test", + "contentType": "application/json", + "data": { + "key": "value1" + }, + "userProperties": { + "name": "test message1" + } + }, + { + "label": "example", + "correlationId": "test", + "contentType": "application/json", + "data": { + "key": "value2" + }, + "userProperties": { + "name": "test message2" + } + } + ] +} +``` + +### [PUT] /topics/{queue_name}/sendbulktemplate + +Sends a templated bulk messages to the specific queue, it can set a wait time between batches +You can define in how many batches you want to send the amount of message and a wait time between each batches. + +**Attention**: if the volume of messages is big, the messages will be split in batches automatically, this also happens if the batch is too small for the maximum allowed size of a payload + +Example Payload: + +```json +{ + "totalMessages": 50, // Number of total messages to send, if not defined it will be set to 1 + "batchOf": 5, // send the total message in how many batches, if not defined it will be set to 1 + "waitBetweenBatchesInMilli": 500, // wait between any batches, if not defined it will be 0 + "template": { // Message template + "label": "example", + "correlationId": "test", + "contentType": "application/json", + "data": { + "key": "value2" + }, + "userProperties": { + "name": "test message2" + } + } +} +``` + +### [GET] /queues/{queue_name}/deadletters + +Gets the dead letters from a queue + +**Query Attributes** +*qty*, *integer*: amount of messages to collect, defaults to all with a maximum of 100 messages +*peek*, *bool*: sets the collection mode to peek, messages will remain in the subscription, defaults to false + +### [GET] /queues/{queue_name}/messages + +Gets the dead letters from a queue + +**Query Attributes** +*qty*, *integer*: amount of messages to collect, defaults to all with a maximum of 100 messages +*peek*, *bool*: sets the collection mode to peek, messages will remain in the subscription, defaults to false + +## Topics + +### List Topics This will list all topics in a namespace @@ -47,7 +434,7 @@ This will list all topics in a namespace servicebus.exe topic list ``` -### **Create Topic** +### Create Topic This will create a topic in a namespace @@ -55,7 +442,7 @@ This will create a topic in a namespace servicebus.exe topic create --name="topic_name" ``` -### **Delete Topic** +### Delete Topic This will delete a topic and all subscriptions in a namespace @@ -63,13 +450,13 @@ This will delete a topic and all subscriptions in a namespace servicebus.exe topic delete --name="topic_name" ``` -### **List Subscription for a Topic** +### List Subscription for a Topic ```bash servicebus.exe topic list-subscriptions --topic="example.topic" ``` -### **Create Topic Subscription** +### Create Topic Subscription This will create a subscription to a specific topic in a namespace @@ -115,7 +502,7 @@ servicebus.exe topic create-subscription --name="new.topic" --subscription="rule in this example it will create a sql filter **1=1** and a action **SET sys.label='example.com'** named *example_rule* -### **Delete Topic Subscription** +### Delete Topic Subscription This will delete a topic subscription for a topic in a namespace @@ -150,7 +537,7 @@ Multiple Subscriber creating a wiretap servicebus.exe topic subscribe --topic="example.topic1" --topic="example.topic2" --wiretap ``` -### **Send a Message to a Topic** +### Send a Message to a Topic ```bash servicebus.exe topic send --topic="topic.name" @@ -160,35 +547,23 @@ servicebus.exe topic send --topic="topic.name" ```--topic``` Name of the topic where to send the message -```--tenant``` Id of the tenant +```--file``` File path with the MessageRequest entity to send, use this instead on inline --body flag ```--body``` Message body in json (please escape the json correctly as this is validated) -```--domain``` Forwarding topology Message Domain - -```--name``` Forwarding topology Message Name - -```--version``` Forwarding topology Version - -```--sender``` Forwarding topology Sender - ```--label``` Message Label ```--property``` Add a User property to the message, this flag can be repeated to add more than one property. **format:** the format will be **[key]:[value]** -```--default``` With this flag the tool will generate a default TimeService sample using the forwarding topology format - -```--uno``` With this flag the tool will convert the default TimeService sample message to Uno format - *Examples*: ```bash -servicebus.exe topic send --topic="example.topic" --body='{\"example\":\"document\"}' --domain="ExampleService" --name="Example" --version=\"2.1\" --sender="ExampleSender" --label="ExampleLabel" +servicebus.exe topic send --topic="example.topic" --body='{\"example\":\"document\"}' --label="ExampleLabel" ``` -## **Queues** +## Queues -### **List Queues** +### List Queues This will list all topics in a namespace @@ -196,7 +571,7 @@ This will list all topics in a namespace servicebus.exe topic list ``` -### **Create Queue** +### Create Queue This will create a Queue in a Namespace @@ -226,7 +601,7 @@ servicebus.exe topic create-subscription --name="new.queue" --forward-deadletter in this case it will forward all dead letters in the *queue* **new.queue** to the *topic* **example.topic** -### **Delete Queue** +### Delete Queue This will delete a topic and all subscriptions in a namespace @@ -234,7 +609,7 @@ This will delete a topic and all subscriptions in a namespace servicebus.exe queue delete --name="queue.name" ``` -### **Subscribe to a Queue** +### Subscribe to a Queue ```bash servicebus.exe queue subscribe --queue="queue.name" --wiretap --peek @@ -261,7 +636,7 @@ Multiple Subscriber creating a wiretap servicebus.exe queue subscribe --queue="example.queue" --queue="example.queue" --wiretap ``` -### **Send a Message to a Queue** +### Send a Message to a Queue ```bash servicebus.exe queue send --queue="queue.name" @@ -271,28 +646,16 @@ servicebus.exe queue send --queue="queue.name" ```--queue``` Name of the queue where to send the message -```--tenant``` Id of the tenant +```--file``` File path with the MessageRequest entity to send, use this instead on inline --body flag ```--body``` Message body in json (please escape the json correctly as this is validated) -```--domain``` Forwarding topology Message Domain - -```--name``` Forwarding topology Message Name - -```--version``` Forwarding topology Version - -```--sender``` Forwarding topology Sender - ```--label``` Message Label ```--property``` Add a User property to the message, this flag can be repeated to add more than one property. **format:** the format will be **[key]:[value]** -```--default``` With this flag the tool will generate a default TimeService sample using the forwarding topology format - -```--uno``` With this flag the tool will convert the default TimeService sample message to Uno format - *Examples*: ```bash -servicebus.exe queue send --queue="example.queue" --body='{\"example\":\"document\"}' --domain=ExampleService --name=Example --version=\"2.1\" --sender=ExampleSender --label=ExampleLabel +servicebus.exe queue send --queue="example.queue" --body='{\"example\":\"document\"}' --label=ExampleLabel ``` diff --git a/ServiceBus Client.postman_collection.json b/ServiceBus Client.postman_collection.json new file mode 100644 index 0000000..0eedbc9 --- /dev/null +++ b/ServiceBus Client.postman_collection.json @@ -0,0 +1,3677 @@ +{ + "info": { + "_postman_id": "3509c1b1-2eda-4979-ac09-e65fc2e414cb", + "name": "ServiceBus Client", + "description": "This API will allow you do manage your service bus Queues/Topics/Subscriptions CURD operations as well as reading or peeking messages or dead letters in them.\n\nThe objective of this is to help developers to test their message handlers more effectively and faster allowing to mock messages and peek results", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Config", + "item": [ + { + "name": "Set Config", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"connectionString\": \"Endpoint=sb://sb-defaul-0x0-9171460417.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=8VrM2rCOME0POXnMGpXWbk7dbrmuJC2ikf59kbfybNE=\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/config", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "config" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Topics", + "item": [ + { + "name": "Subscriptions", + "item": [ + { + "name": "Get All Subscriptions", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/subscriptions", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "subscriptions" + ] + } + }, + "response": [ + { + "name": "Ok Result", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/subscriptions", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "subscriptions" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Fri, 30 Apr 2021 07:07:34 GMT" + }, + { + "key": "Content-Length", + "value": "753" + } + ], + "cookie": [], + "body": "[\n {\n \"name\": \"bar\",\n \"url\": \"https://foo.servicebus.windows.net/temp.topic/subscriptions/bar?api-version=2017-04\",\n \"countDetails\": {\n \"activeMessageCount\": 3,\n \"deadLetterMessageCount\": 0,\n \"scheduledMessageCount\": 0,\n \"transferDeadLetterMessageCount\": 0,\n \"transferMessageCount\": 0\n },\n \"lockDuration\": \"PT1M\",\n \"requiresSession\": false,\n \"defaultMessageTimeToLive\": \"P10675199DT2H48M5.4775807S\",\n \"deadLetteringOnMessageExpiration\": false,\n \"deadLetteringOnFilterEvaluationExceptions\": false,\n \"messageCount\": 3,\n \"maxDeliveryCount\": 10,\n \"enableBatchedOperations\": false,\n \"status\": \"Active\",\n \"createdAt\": \"2021-04-29T08:47:54.7222311Z\",\n \"updatedAt\": \"2021-04-29T08:47:54.7222311Z\",\n \"accessedAt\": \"2021-04-29T08:50:34.807Z\",\n \"forwardTo\": null,\n \"forwardDeadLetteredMessagesTo\": null\n }\n]" + }, + { + "name": "Error Result", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/er/subscriptions", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "er", + "subscriptions" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Fri, 30 Apr 2021 07:07:59 GMT" + }, + { + "key": "Content-Length", + "value": "122" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Some Error\",\n \"message\": \"Some Error Message\"\n}" + }, + { + "name": "NotFound Result", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/er/subscriptions", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "er", + "subscriptions" + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Fri, 30 Apr 2021 07:07:59 GMT" + }, + { + "key": "Content-Length", + "value": "122" + } + ], + "cookie": [], + "body": "{\n \"code\": 404,\n \"error\": \"Topic not found\",\n \"message\": \"The Topic bar was not found in the service bus foo\"\n}" + } + ] + }, + { + "name": "Create Subscription", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"foo\",\r\n \"maxDeliveryCount\": 15,\r\n \"forward\": {\r\n \"to\": \"otherTopic\",\r\n \"in\": \"Topic\"\r\n },\r\n \"forwardDeadLetter\": {\r\n \"to\": \"otherQueue\",\r\n \"in\": \"Queue\"\r\n },\r\n \"rules\": [\r\n {\r\n \"name\": \"example_rule\",\r\n \"sqlFilter\": \"2=2\",\r\n \"sqlAction\": \"SET A='one'\"\r\n }\r\n ], \r\n \"options\": {\r\n \"autoDeleteOnIdle\": \"24h\",\r\n \"defaultMessageTimeToLive\": \"24h\",\r\n \"lockDuration\": \"30s\",\r\n \"enableBatchedOperation\": true,\r\n \"deadLetteringOnMessageExpiration\": false,\r\n \"requireSession\": false\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/subscriptions", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "subscriptions" + ] + } + }, + "response": [ + { + "name": "Ok Result", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"foo\",\r\n \"maxDeliveryCount\": 15,\r\n \"forward\": {\r\n \"to\": \"temp.topic2\",\r\n \"in\": \"Topic\"\r\n },\r\n \"forwardDeadLetter\": {\r\n \"to\": \"foo\",\r\n \"in\": \"Queue\"\r\n },\r\n \"rules\": [\r\n {\r\n \"name\": \"example_rule\",\r\n \"sqlFilter\": \"2=2\",\r\n \"sqlAction\": \"SET A='one'\"\r\n }\r\n ],\r\n \"options\": {\r\n \"autoDeleteOnIdle\": \"24h\",\r\n \"defaultMessageTimeToLive\": \"24h\",\r\n \"lockDuration\": \"30s\",\r\n \"enableBatchedOperation\": true,\r\n \"deadLetteringOnMessageExpiration\": false,\r\n \"requireSession\": false\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/subscriptions", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "subscriptions" + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Fri, 30 Apr 2021 07:59:55 GMT" + }, + { + "key": "Content-Length", + "value": "716" + } + ], + "cookie": [], + "body": "{\n \"name\": \"bar\",\n \"url\": \"sb://foo.servicebus.windows.net/temp.topic/subscriptions/bar?api-version=2017-04\",\n \"countDetails\": {\n \"activeMessageCount\": 0,\n \"deadLetterMessageCount\": 0,\n \"scheduledMessageCount\": 0,\n \"transferDeadLetterMessageCount\": 0,\n \"transferMessageCount\": 0\n },\n \"lockDuration\": \"PT30S\",\n \"requiresSession\": false,\n \"defaultMessageTimeToLive\": \"P1D\",\n \"deadLetteringOnMessageExpiration\": false,\n \"deadLetteringOnFilterEvaluationExceptions\": true,\n \"messageCount\": 0,\n \"maxDeliveryCount\": 10,\n \"enableBatchedOperations\": true,\n \"status\": \"Active\",\n \"createdAt\": \"2021-04-30T07:59:55.0122186Z\",\n \"updatedAt\": \"2021-04-30T07:59:55.0122186Z\",\n \"accessedAt\": \"2021-04-30T07:59:55.013Z\",\n \"forwardTo\": null,\n \"forwardDeadLetteredMessagesTo\": null\n}" + }, + { + "name": "Error Result", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"foo\",\r\n \"maxDeliveryCount\": 15,\r\n \"forward\": {\r\n \"to\": \"temp.topic2\",\r\n \"in\": \"Topic\"\r\n },\r\n \"forwardDeadLetter\": {\r\n \"to\": \"foo\",\r\n \"in\": \"Queue\"\r\n },\r\n \"rules\": [\r\n {\r\n \"name\": \"example_rule\",\r\n \"sqlFilter\": \"2=2\",\r\n \"sqlAction\": \"SET A='one'\"\r\n }\r\n ],\r\n \"options\": {\r\n \"autoDeleteOnIdle\": \"24h\",\r\n \"defaultMessageTimeToLive\": \"1d\",\r\n \"lockDuration\": \"30s\",\r\n \"enableBatchedOperation\": true,\r\n \"deadLetteringOnMessageExpiration\": false,\r\n \"requireSession\": false\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/subscriptions", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "subscriptions" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Fri, 30 Apr 2021 08:24:58 GMT" + }, + { + "key": "Content-Length", + "value": "127" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Some Error\",\n \"message\": \"Some Error Message\"\n}" + } + ] + }, + { + "name": "Get Subscription", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/{{subscriptionName}}", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "{{subscriptionName}}" + ] + } + }, + "response": [ + { + "name": "Ok Result", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/subscriptions", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "subscriptions" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Fri, 30 Apr 2021 07:07:34 GMT" + }, + { + "key": "Content-Length", + "value": "753" + } + ], + "cookie": [], + "body": "{\n \"name\": \"bar\",\n \"url\": \"https://foo.servicebus.windows.net/temp.topic/subscriptions/bar?api-version=2017-04\",\n \"countDetails\": {\n \"activeMessageCount\": 3,\n \"deadLetterMessageCount\": 0,\n \"scheduledMessageCount\": 0,\n \"transferDeadLetterMessageCount\": 0,\n \"transferMessageCount\": 0\n },\n \"lockDuration\": \"PT1M\",\n \"requiresSession\": false,\n \"defaultMessageTimeToLive\": \"P10675199DT2H48M5.4775807S\",\n \"deadLetteringOnMessageExpiration\": false,\n \"deadLetteringOnFilterEvaluationExceptions\": false,\n \"messageCount\": 3,\n \"maxDeliveryCount\": 10,\n \"enableBatchedOperations\": false,\n \"status\": \"Active\",\n \"createdAt\": \"2021-04-29T08:47:54.7222311Z\",\n \"updatedAt\": \"2021-04-29T08:47:54.7222311Z\",\n \"accessedAt\": \"2021-04-29T08:50:34.807Z\",\n \"forwardTo\": null,\n \"forwardDeadLetteredMessagesTo\": null\n}" + }, + { + "name": "Error Result", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/er/subscriptions", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "er", + "subscriptions" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Fri, 30 Apr 2021 07:07:59 GMT" + }, + { + "key": "Content-Length", + "value": "122" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Some Error\",\n \"message\": \"Some Error Message\"\n}" + }, + { + "name": "NotFound Result", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/er/subscriptions", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "er", + "subscriptions" + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Fri, 30 Apr 2021 07:07:59 GMT" + }, + { + "key": "Content-Length", + "value": "122" + } + ], + "cookie": [], + "body": "{\n \"code\": 404,\n \"error\": \"Topic not found\",\n \"message\": \"The Topic bar was not found in the service bus foo\"\n}" + } + ] + }, + { + "name": "Delete Subscription", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/{{subscriptionName}}1", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "{{subscriptionName}}1" + ] + } + }, + "response": [ + { + "name": "Ok Result", + "originalRequest": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/foo", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "foo" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Fri, 30 Apr 2021 09:00:05 GMT" + }, + { + "key": "Content-Length", + "value": "0" + } + ], + "cookie": [], + "body": null + }, + { + "name": "NotFound Result", + "originalRequest": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/{{subscriptionName}}", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "{{subscriptionName}}" + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Fri, 30 Apr 2021 08:28:52 GMT" + }, + { + "key": "Content-Length", + "value": "155" + } + ], + "cookie": [], + "body": "{\n \"code\": 404,\n \"error\": \"Subscription not found\",\n \"message\": \"The Subscription bar was not found on topic foo in the service bus foo\"\n}" + }, + { + "name": "Error Result", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"foo\",\r\n \"maxDeliveryCount\": 15,\r\n \"forward\": {\r\n \"to\": \"temp.topic2\",\r\n \"in\": \"Topic\"\r\n },\r\n \"forwardDeadLetter\": {\r\n \"to\": \"foo\",\r\n \"in\": \"Queue\"\r\n },\r\n \"rules\": [\r\n {\r\n \"name\": \"example_rule\",\r\n \"sqlFilter\": \"2=2\",\r\n \"sqlAction\": \"SET A='one'\"\r\n }\r\n ],\r\n \"options\": {\r\n \"autoDeleteOnIdle\": \"24h\",\r\n \"defaultMessageTimeToLive\": \"1d\",\r\n \"lockDuration\": \"30s\",\r\n \"enableBatchedOperation\": true,\r\n \"deadLetteringOnMessageExpiration\": false,\r\n \"requireSession\": false\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/subscriptions", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "subscriptions" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Fri, 30 Apr 2021 08:24:58 GMT" + }, + { + "key": "Content-Length", + "value": "127" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Some Error\",\n \"message\": \"Some Error Message\"\n}" + } + ] + }, + { + "name": "Get All Subscription Rules", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/{{subscriptionName}}/rules", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "{{subscriptionName}}", + "rules" + ] + } + }, + "response": [ + { + "name": "Ok Result", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/{{subscriptionName}}/rules", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "{{subscriptionName}}", + "rules" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Fri, 30 Apr 2021 09:07:50 GMT" + }, + { + "key": "Content-Length", + "value": "491" + } + ], + "cookie": [], + "body": "[\n {\n \"name\": \"$Default\",\n \"id\": \"https://foo.servicebus.windows.net/temp.topic/subscriptions/wiretap/rules/$Default?api-version=2017-04\",\n \"filter\": {\n \"correlationID\": null,\n \"messageID\": null,\n \"to\": null,\n \"replyTo\": null,\n \"label\": null,\n \"sessionID\": null,\n \"replyToSessionID\": null,\n \"contentType\": null,\n \"properties\": null,\n \"type\": \"SqlFilter\",\n \"sqlExpression\": \"1=1\",\n \"compatibilityLevel\": 20\n },\n \"action\": {\n \"type\": \"EmptyRuleAction\",\n \"requiresPreprocessing\": false,\n \"sqlExpression\": \"\",\n \"compatibilityLevel\": 0\n }\n }\n]" + }, + { + "name": "Error Result", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/er/subscriptions", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "er", + "subscriptions" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Fri, 30 Apr 2021 07:07:59 GMT" + }, + { + "key": "Content-Length", + "value": "122" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Some Error\",\n \"message\": \"Some Error Message\"\n}" + } + ] + }, + { + "name": "Create Subscription Rule", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"example_rule\",\r\n \"sqlFilter\": \"2=2\",\r\n \"sqlAction\": \"SET A='one'\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/{{subscriptionName}}/rules", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "{{subscriptionName}}", + "rules" + ] + } + }, + "response": [ + { + "name": "Error Result", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"foo\",\r\n \"maxDeliveryCount\": 15,\r\n \"forward\": {\r\n \"to\": \"temp.topic2\",\r\n \"in\": \"Topic\"\r\n },\r\n \"forwardDeadLetter\": {\r\n \"to\": \"foo\",\r\n \"in\": \"Queue\"\r\n },\r\n \"rules\": [\r\n {\r\n \"name\": \"example_rule\",\r\n \"sqlFilter\": \"2=2\",\r\n \"sqlAction\": \"SET A='one'\"\r\n }\r\n ],\r\n \"options\": {\r\n \"autoDeleteOnIdle\": \"24h\",\r\n \"defaultMessageTimeToLive\": \"1d\",\r\n \"lockDuration\": \"30s\",\r\n \"enableBatchedOperation\": true,\r\n \"deadLetteringOnMessageExpiration\": false,\r\n \"requireSession\": false\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/subscriptions", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "subscriptions" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Fri, 30 Apr 2021 08:24:58 GMT" + }, + { + "key": "Content-Length", + "value": "127" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Some Error\",\n \"message\": \"Some Error Message\"\n}" + }, + { + "name": "Ok Result", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"example_rule1\",\r\n \"sqlFilter\": \"2=2\",\r\n \"sqlAction\": \"SET A='one'\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/{{subscriptionName}}/rules", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "{{subscriptionName}}", + "rules" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Fri, 30 Apr 2021 13:32:05 GMT" + }, + { + "key": "Content-Length", + "value": "509" + } + ], + "cookie": [], + "body": "{\n \"name\": \"bar\",\n \"id\": \"https://foo.servicebus.windows.net/temp.topic/subscriptions/example/rules/example_rule1?api-version=2017-04\",\n \"filter\": {\n \"correlationID\": null,\n \"messageID\": null,\n \"to\": null,\n \"replyTo\": null,\n \"label\": null,\n \"sessionID\": null,\n \"replyToSessionID\": null,\n \"contentType\": null,\n \"properties\": null,\n \"type\": \"SqlFilter\",\n \"sqlExpression\": \"2=2\",\n \"compatibilityLevel\": 20\n },\n \"action\": {\n \"type\": \"SqlRuleAction\",\n \"requiresPreprocessing\": false,\n \"sqlExpression\": \"SET A='one'\",\n \"compatibilityLevel\": 20\n }\n}" + } + ] + }, + { + "name": "Get Subscription Rule", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/{{subscriptionName}}/rules/{{subscriptionRuleName}}", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "{{subscriptionName}}", + "rules", + "{{subscriptionRuleName}}" + ] + } + }, + "response": [ + { + "name": "Ok Result", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/{{subscriptionName}}/rules/{{subscriptionRuleName}}", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "{{subscriptionName}}", + "rules", + "{{subscriptionRuleName}}" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Fri, 30 Apr 2021 09:15:49 GMT" + }, + { + "key": "Content-Length", + "value": "489" + } + ], + "cookie": [], + "body": "{\n \"name\": \"$Default\",\n \"id\": \"https://sb-defaul-0x0-4172098119.servicebus.windows.net/temp.topic/subscriptions/wiretap/rules/$Default?api-version=2017-04\",\n \"filter\": {\n \"correlationID\": null,\n \"messageID\": null,\n \"to\": null,\n \"replyTo\": null,\n \"label\": null,\n \"sessionID\": null,\n \"replyToSessionID\": null,\n \"contentType\": null,\n \"properties\": null,\n \"type\": \"SqlFilter\",\n \"sqlExpression\": \"1=1\",\n \"compatibilityLevel\": 20\n },\n \"action\": {\n \"type\": \"EmptyRuleAction\",\n \"requiresPreprocessing\": false,\n \"sqlExpression\": \"\",\n \"compatibilityLevel\": 0\n }\n}" + }, + { + "name": "Error Result", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/er/subscriptions", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "er", + "subscriptions" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Fri, 30 Apr 2021 07:07:59 GMT" + }, + { + "key": "Content-Length", + "value": "122" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Some Error\",\n \"message\": \"Some Error Message\"\n}" + }, + { + "name": "NotFound Result", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/er/subscriptions", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "er", + "subscriptions" + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Fri, 30 Apr 2021 07:07:59 GMT" + }, + { + "key": "Content-Length", + "value": "122" + } + ], + "cookie": [], + "body": "{\n \"code\": 404,\n \"error\": \"Topic not found\",\n \"message\": \"The Topic bar was not found in the service bus foo\"\n}" + } + ] + }, + { + "name": "Delete Subscription Rule", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/{{subscriptionName}}/rules/{{subscriptionRuleName}}", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "{{subscriptionName}}", + "rules", + "{{subscriptionRuleName}}" + ] + } + }, + "response": [ + { + "name": "Ok Result", + "originalRequest": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/{{subscriptionName}}/rules/example_rule1", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "{{subscriptionName}}", + "rules", + "example_rule1" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Fri, 30 Apr 2021 14:08:38 GMT" + }, + { + "key": "Content-Length", + "value": "0" + } + ], + "cookie": [], + "body": null + }, + { + "name": "Error Result", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/er/subscriptions", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "er", + "subscriptions" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Fri, 30 Apr 2021 07:07:59 GMT" + }, + { + "key": "Content-Length", + "value": "122" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Some Error\",\n \"message\": \"Some Error Message\"\n}" + }, + { + "name": "NotFound Result", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/er/subscriptions", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "er", + "subscriptions" + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Fri, 30 Apr 2021 07:07:59 GMT" + }, + { + "key": "Content-Length", + "value": "122" + } + ], + "cookie": [], + "body": "{\n \"code\": 404,\n \"error\": \"Topic not found\",\n \"message\": \"The Topic bar was not found in the service bus foo\"\n}" + } + ] + }, + { + "name": "Get Subscription Messages", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/{{subscriptionName}}/messages?qty=10&peek=true", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "{{subscriptionName}}", + "messages" + ], + "query": [ + { + "key": "qty", + "value": "10", + "description": "Quantity of messages to return" + }, + { + "key": "peek", + "value": "true", + "description": "Should it only peek the messages?" + } + ] + } + }, + "response": [ + { + "name": "Ok Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\"\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:19:17 GMT" + }, + { + "key": "Content-Length", + "value": "88" + } + ], + "cookie": [], + "body": "{\n \"message\": \"Message example was sent successfully to foo queue\",\n \"data\": {\n \"key\": \"value\"\n }\n}" + }, + { + "name": "Error Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\",\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:20:00 GMT" + }, + { + "key": "Content-Length", + "value": "120" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Some Error\",\n \"message\": \"Some Error Message\"\n}" + } + ] + }, + { + "name": "Get Subscription Dead Letters", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/{{subscriptionName}}/deadletters?qty=10&peek=true", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "{{subscriptionName}}", + "deadletters" + ], + "query": [ + { + "key": "qty", + "value": "10", + "description": "Quantity of messages to return" + }, + { + "key": "peek", + "value": "true", + "description": "Should it only peek the messages?" + } + ] + } + }, + "response": [ + { + "name": "Ok Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\"\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:19:17 GMT" + }, + { + "key": "Content-Length", + "value": "88" + } + ], + "cookie": [], + "body": "{\n \"message\": \"Message example was sent successfully to foo queue\",\n \"data\": {\n \"key\": \"value\"\n }\n}" + }, + { + "name": "Error Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\",\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:20:00 GMT" + }, + { + "key": "Content-Length", + "value": "120" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Some Error\",\n \"message\": \"Some Error Message\"\n}" + }, + { + "name": "NoContent Result", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/{{subscriptionName}}/deadletters?qty=10&peek=true", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "{{subscriptionName}}", + "deadletters" + ], + "query": [ + { + "key": "qty", + "value": "10", + "description": "Quantity of messages to return" + }, + { + "key": "peek", + "value": "true", + "description": "Should it only peek the messages?" + } + ] + } + }, + "status": "No Content", + "code": 204, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Fri, 30 Apr 2021 14:21:18 GMT" + } + ], + "cookie": [], + "body": null + } + ] + } + ] + }, + { + "name": "Get All Topics", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics" + ] + }, + "description": "This will list all the topics in a specific namespace" + }, + "response": [] + }, + { + "name": "Set Config", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}" + ] + } + }, + "response": [ + { + "name": "Topic", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:10000/topics/example", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "10000", + "path": [ + "topics", + "example" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": null, + "cookie": [], + "body": "{\n \"name\": \"example\",\n \"id\": \"https://example.servicebus.windows.net/example?api-version=2017-04\",\n \"countDetails\": {\n \"activeMessageCount\": 0,\n \"deadLetterMessageCount\": 0,\n \"scheduledMessageCount\": 0,\n \"transferDeadLetterMessageCount\": 0,\n \"transferMessageCount\": 0\n },\n \"defaultMessageTimeToLive\": \"P10675199DT2H48M5.4775807S\",\n \"maxSizeInMegabytes\": 1024,\n \"requiresDuplicateDetection\": false,\n \"duplicateDetectionHistoryTimeWindow\": \"PT10M\",\n \"enableBatchedOperations\": false,\n \"sizeInBytes\": 0,\n \"filteringMessagesBeforePublishing\": false,\n \"isAnonymousAccessible\": false,\n \"status\": \"Active\",\n \"createdAt\": \"2021-04-13T16:22:28.713Z\",\n \"updatedAt\": \"2021-04-13T16:26:44.537Z\",\n \"supportOrdering\": false,\n \"autoDeleteOnIdle\": \"P10675199DT2H48M5.4775807S\",\n \"enablePartitioning\": false,\n \"enableSubscriptionPartitioning\": false,\n \"enableExpress\": false\n}" + } + ] + }, + { + "name": "Send Topic Message", + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value1\"\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message1\"\r\n }\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "send" + ] + } + }, + "response": [ + { + "name": "Ok Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\"\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:19:17 GMT" + }, + { + "key": "Content-Length", + "value": "88" + } + ], + "cookie": [], + "body": "{\n \"message\": \"Message example was sent successfully to foo queue\",\n \"data\": {\n \"key\": \"value\"\n }\n}" + }, + { + "name": "Error Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\",\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:20:00 GMT" + }, + { + "key": "Content-Length", + "value": "120" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Some Error\",\n \"message\": \"Some Error Message\"\n}" + } + ] + }, + { + "name": "Send Bulk Topic Messages", + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"messages\": [\r\n {\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value1\"\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message1\"\r\n }\r\n },\r\n {\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value2\"\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message2\"\r\n }\r\n }\r\n ]\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/sendbulk", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "sendbulk" + ] + } + }, + "response": [ + { + "name": "Ok Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\"\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:19:17 GMT" + }, + { + "key": "Content-Length", + "value": "88" + } + ], + "cookie": [], + "body": "{\n \"message\": \"Message example was sent successfully to foo queue\",\n \"data\": {\n \"key\": \"value\"\n }\n}" + }, + { + "name": "Error Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\",\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:20:00 GMT" + }, + { + "key": "Content-Length", + "value": "120" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Some Error\",\n \"message\": \"Some Error Message\"\n}" + } + ] + }, + { + "name": "Send Bulk Template Topic Message", + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"totalMessages\": 10,\r\n \"WaitBetweenBatchesInMilli\":10,\r\n \"batchOf\": 5,\r\n \"template\": {\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value1\"\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message1\"\r\n }\r\n }\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/topics/{{topicName}}/sendbulktemplate", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "{{topicName}}", + "sendbulktemplate" + ] + } + }, + "response": [ + { + "name": "Ok Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\"\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:19:17 GMT" + }, + { + "key": "Content-Length", + "value": "88" + } + ], + "cookie": [], + "body": "{\n \"message\": \"Sent 10 Messages in 5 batches successfully to temp-aaa-gmt topic\"\n}" + }, + { + "name": "Error Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\",\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:20:00 GMT" + }, + { + "key": "Content-Length", + "value": "120" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Some Error\",\n \"message\": \"Some Error Message\"\n}" + } + ] + } + ], + "description": "CURD operations in topics for a specific namespace controlled by the API" + }, + { + "name": "Queues", + "item": [ + { + "name": "Get All Queues", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/queues", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues" + ] + } + }, + "response": [ + { + "name": "OK Result", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/queues", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 13:21:07 GMT" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + } + ], + "cookie": [], + "body": "[\n {\n \"name\": \"example1\",\n \"id\": \"\",\n \"countDetails\": {\n \"activeMessageCount\": 0,\n \"deadLetterMessageCount\": 0,\n \"scheduledMessageCount\": 0,\n \"transferDeadLetterMessageCount\": 0,\n \"transferMessageCount\": 0\n },\n \"lockDuration\": {\n \"Years\": 0,\n \"Weeks\": 0,\n \"Days\": 0,\n \"Hours\": 0,\n \"Minutes\": 5,\n \"Seconds\": 0,\n \"MilliSeconds\": 0\n },\n \"maxSizeInMegabytes\": 1024,\n \"requiresDuplicateDetection\": false,\n \"requiresSession\": false,\n \"defaultMessageTimeToLive\": {\n \"Years\": 0,\n \"Weeks\": 0,\n \"Days\": 10675199,\n \"Hours\": 2,\n \"Minutes\": 48,\n \"Seconds\": 5,\n \"MilliSeconds\": 477\n },\n \"deadLetteringOnMessageExpiration\": false,\n \"duplicateDetectionHistoryTimeWindow\": {\n \"Years\": 0,\n \"Weeks\": 0,\n \"Days\": 0,\n \"Hours\": 0,\n \"Minutes\": 10,\n \"Seconds\": 0,\n \"MilliSeconds\": 0\n },\n \"maxDeliveryCount\": 10,\n \"enableBatchedOperations\": true,\n \"sizeInBytes\": 0,\n \"messageCount\": null,\n \"isAnonymousAccessible\": false,\n \"status\": \"Active\",\n \"createdAt\": \"2021-03-19T11:00:52.16Z\",\n \"updatedAt\": \"2021-03-19T11:00:52.343Z\",\n \"supportOrdering\": true,\n \"autoDeleteOnIdle\": {\n \"Years\": 0,\n \"Weeks\": 0,\n \"Days\": 10675199,\n \"Hours\": 2,\n \"Minutes\": 48,\n \"Seconds\": 5,\n \"MilliSeconds\": 477\n },\n \"enablePartitioning\": false,\n \"enableExpress\": false,\n \"forwardTo\": null,\n \"forwardDeadLetteredMessagesTo\": null\n },\n {\n \"name\": \"example2\",\n \"id\": \"\",\n \"countDetails\": {\n \"activeMessageCount\": 0,\n \"deadLetterMessageCount\": 0,\n \"scheduledMessageCount\": 0,\n \"transferDeadLetterMessageCount\": 0,\n \"transferMessageCount\": 0\n },\n \"lockDuration\": {\n \"Years\": 0,\n \"Weeks\": 0,\n \"Days\": 0,\n \"Hours\": 0,\n \"Minutes\": 5,\n \"Seconds\": 0,\n \"MilliSeconds\": 0\n },\n \"maxSizeInMegabytes\": 1024,\n \"requiresDuplicateDetection\": false,\n \"requiresSession\": false,\n \"defaultMessageTimeToLive\": {\n \"Years\": 0,\n \"Weeks\": 0,\n \"Days\": 10675199,\n \"Hours\": 2,\n \"Minutes\": 48,\n \"Seconds\": 5,\n \"MilliSeconds\": 477\n },\n \"deadLetteringOnMessageExpiration\": false,\n \"duplicateDetectionHistoryTimeWindow\": {\n \"Years\": 0,\n \"Weeks\": 0,\n \"Days\": 0,\n \"Hours\": 0,\n \"Minutes\": 10,\n \"Seconds\": 0,\n \"MilliSeconds\": 0\n },\n \"maxDeliveryCount\": 10,\n \"enableBatchedOperations\": true,\n \"sizeInBytes\": 0,\n \"messageCount\": null,\n \"isAnonymousAccessible\": false,\n \"status\": \"Active\",\n \"createdAt\": \"2021-04-28T09:19:06.903Z\",\n \"updatedAt\": \"2021-04-28T09:19:06.947Z\",\n \"supportOrdering\": true,\n \"autoDeleteOnIdle\": {\n \"Years\": 0,\n \"Weeks\": 0,\n \"Days\": 10675199,\n \"Hours\": 2,\n \"Minutes\": 48,\n \"Seconds\": 5,\n \"MilliSeconds\": 477\n },\n \"enablePartitioning\": false,\n \"enableExpress\": false,\n \"forwardTo\": null,\n \"forwardDeadLetteredMessagesTo\": null\n }\n]" + }, + { + "name": "Error Result", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/queues", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 13:33:03 GMT" + }, + { + "key": "Content-Length", + "value": "274" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Server Error\",\n \"message\": \"Some error message\"\n}" + } + ] + }, + { + "name": "Create Queue", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"foo\",\r\n \"maxDeliveryCount\": 5,\r\n \"forward\": {\r\n \"to\": \"otherTopic\",\r\n \"in\": \"Topic\"\r\n },\r\n \"forwardDeadLetter\": {\r\n \"to\": \"otherQueue\",\r\n \"in\": \"Queue\"\r\n },\r\n \"options\": {\r\n \"autoDeleteOnIdle\": \"24h\",\r\n \"enableDuplicateDetection\": \"30m\",\r\n \"maxSizeInMegabytes\": 1024,\r\n \"defaultMessageTimeToLive\": \"1h\",\r\n \"lockDuration\": \"30s\",\r\n \"supportOrdering\": true,\r\n \"enablePartitioning\": true,\r\n \"requireSession\": false,\r\n \"deadLetteringOnMessageExpiration\": false\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues" + ] + } + }, + "response": [ + { + "name": "Error Result", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"foo\",\r\n \"maxDeliveryCount\": 5,\r\n \"forward\": {\r\n \"to\": \"otherTopic\",\r\n \"in\": \"Topic\"\r\n },\r\n \"forwardDeadLetter\": {\r\n \"to\": \"otherQueue\",\r\n \"in\": \"Queue\"\r\n },\r\n \"options\": {\r\n \"autoDeleteOnIdle\": \"24h\",\r\n \"enableDuplicateDetection\": \"30m\",\r\n \"maxSizeInMegabytes\": 10,\r\n \"defaultMessageTimeToLive\": \"1h\",\r\n \"lockDuration\": \"30s\",\r\n \"supportOrdering\": true,\r\n \"enablePartitioning\": true,\r\n \"requireSession\": false,\r\n \"deadLetteringOnMessageExpiration\": false\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 14:01:38 GMT" + }, + { + "key": "Content-Length", + "value": "88" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Error Creating Queue\",\n \"message\": \"some error message\"\n}" + }, + { + "name": "Ok Result", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"name\": \"foo1\",\r\n \"maxDeliveryCount\": 5,\r\n \"options\": {\r\n \"autoDeleteOnIdle\": \"24h\",\r\n \"enableDuplicateDetection\": \"30m\",\r\n \"maxSizeInMegabytes\": 1024,\r\n \"defaultMessageTimeToLive\": \"1h\",\r\n \"lockDuration\": \"30s\",\r\n \"supportOrdering\": true,\r\n \"enablePartitioning\": true,\r\n \"requireSession\": false,\r\n \"deadLetteringOnMessageExpiration\": false\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues" + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 14:17:43 GMT" + }, + { + "key": "Content-Length", + "value": "1149" + } + ], + "cookie": [], + "body": "{\n \"name\": \"bar\",\n \"id\": \"https://foo.windows.net/bar?api-version=2017-04\",\n \"countDetails\": {\n \"activeMessageCount\": 0,\n \"deadLetterMessageCount\": 0,\n \"scheduledMessageCount\": 0,\n \"transferDeadLetterMessageCount\": 0,\n \"transferMessageCount\": 0\n },\n \"lockDuration\": {\n \"Years\": 0,\n \"Weeks\": 0,\n \"Days\": 0,\n \"Hours\": 0,\n \"Minutes\": 0,\n \"Seconds\": 0,\n \"MilliSeconds\": 0\n },\n \"maxSizeInMegabytes\": 16384,\n \"requiresDuplicateDetection\": true,\n \"requiresSession\": false,\n \"defaultMessageTimeToLive\": {\n \"Years\": 0,\n \"Weeks\": 0,\n \"Days\": 0,\n \"Hours\": 1,\n \"Minutes\": 0,\n \"Seconds\": 0,\n \"MilliSeconds\": 0\n },\n \"deadLetteringOnMessageExpiration\": false,\n \"duplicateDetectionHistoryTimeWindow\": {\n \"Years\": 0,\n \"Weeks\": 0,\n \"Days\": 1,\n \"Hours\": 0,\n \"Minutes\": 0,\n \"Seconds\": 0,\n \"MilliSeconds\": 0\n },\n \"maxDeliveryCount\": 5,\n \"enableBatchedOperations\": true,\n \"sizeInBytes\": 0,\n \"messageCount\": null,\n \"isAnonymousAccessible\": false,\n \"status\": \"Active\",\n \"createdAt\": \"2021-04-29T14:17:42.503Z\",\n \"updatedAt\": \"2021-04-29T14:17:42.62Z\",\n \"supportOrdering\": false,\n \"autoDeleteOnIdle\": {\n \"Years\": 0,\n \"Weeks\": 0,\n \"Days\": 1,\n \"Hours\": 0,\n \"Minutes\": 0,\n \"Seconds\": 0,\n \"MilliSeconds\": 0\n },\n \"enablePartitioning\": true,\n \"enableExpress\": false,\n \"forwardTo\": null,\n \"forwardDeadLetteredMessagesTo\": null\n}" + } + ] + }, + { + "name": "Get Queue", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}" + ] + } + }, + "response": [ + { + "name": "Ok Result", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 13:30:06 GMT" + }, + { + "key": "Content-Length", + "value": "1266" + } + ], + "cookie": [], + "body": "{\n \"name\": \"bar\",\n \"id\": \"https://foo.windows.net/bar?api-version=2017-04\",\n \"countDetails\": {\n \"activeMessageCount\": 0,\n \"deadLetterMessageCount\": 0,\n \"scheduledMessageCount\": 0,\n \"transferDeadLetterMessageCount\": 0,\n \"transferMessageCount\": 0\n },\n \"lockDuration\": {\n \"Years\": 0,\n \"Weeks\": 0,\n \"Days\": 0,\n \"Hours\": 0,\n \"Minutes\": 1,\n \"Seconds\": 0,\n \"MilliSeconds\": 0\n },\n \"maxSizeInMegabytes\": 5120,\n \"requiresDuplicateDetection\": false,\n \"requiresSession\": false,\n \"defaultMessageTimeToLive\": {\n \"Years\": 0,\n \"Weeks\": 0,\n \"Days\": 10675199,\n \"Hours\": 2,\n \"Minutes\": 48,\n \"Seconds\": 5,\n \"MilliSeconds\": 477\n },\n \"deadLetteringOnMessageExpiration\": false,\n \"duplicateDetectionHistoryTimeWindow\": {\n \"Years\": 0,\n \"Weeks\": 0,\n \"Days\": 0,\n \"Hours\": 0,\n \"Minutes\": 10,\n \"Seconds\": 0,\n \"MilliSeconds\": 0\n },\n \"maxDeliveryCount\": 10,\n \"enableBatchedOperations\": true,\n \"sizeInBytes\": 0,\n \"messageCount\": null,\n \"isAnonymousAccessible\": false,\n \"status\": \"Active\",\n \"createdAt\": \"2020-12-02T09:46:35.6735156Z\",\n \"updatedAt\": \"2020-12-02T09:46:35.6735156Z\",\n \"supportOrdering\": true,\n \"autoDeleteOnIdle\": {\n \"Years\": 0,\n \"Weeks\": 0,\n \"Days\": 10675199,\n \"Hours\": 2,\n \"Minutes\": 48,\n \"Seconds\": 5,\n \"MilliSeconds\": 477\n },\n \"enablePartitioning\": false,\n \"enableExpress\": false,\n \"forwardTo\": null,\n \"forwardDeadLetteredMessagesTo\": null\n}" + }, + { + "name": "NotFound Result", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}" + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 13:33:38 GMT" + }, + { + "key": "Content-Length", + "value": "157" + } + ], + "cookie": [], + "body": "{\n \"code\": 404,\n \"error\": \"Queue Not Found\",\n \"message\": \"Queue with name foo was not found in sb-defaul-0x0-4172098119\"\n}" + }, + { + "name": "Error Result", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 13:36:45 GMT" + }, + { + "key": "Content-Length", + "value": "304" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Server Error\",\n \"message\": \"Some Error Message\"\n}" + } + ] + }, + { + "name": "Delete Queue", + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}" + ] + } + }, + "response": [ + { + "name": "NotFound Result", + "originalRequest": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/queues/foo1", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "foo1" + ] + } + }, + "status": "Not Found", + "code": 404, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 14:28:42 GMT" + }, + { + "key": "Content-Length", + "value": "116" + } + ], + "cookie": [], + "body": "{\n \"code\": 404,\n \"error\": \"Queue Not Found\",\n \"message\": \"Queue with name foo123 was not found in sb-defaul-0x0-4172098119\"\n}" + }, + { + "name": "Ok Result", + "originalRequest": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/queues/foo", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "foo" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 14:34:03 GMT" + }, + { + "key": "Content-Length", + "value": "0" + } + ], + "cookie": [], + "body": null + } + ] + }, + { + "name": "Send Queue Message", + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\"\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "response": [ + { + "name": "Ok Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\"\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:19:17 GMT" + }, + { + "key": "Content-Length", + "value": "88" + } + ], + "cookie": [], + "body": "{\n \"message\": \"Message example was sent successfully to foo queue\",\n \"data\": {\n \"key\": \"value\"\n }\n}" + }, + { + "name": "Error Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\",\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:20:00 GMT" + }, + { + "key": "Content-Length", + "value": "120" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Some Error\",\n \"message\": \"Some Error Message\"\n}" + } + ] + }, + { + "name": "Send Bulk Queue Messages", + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"messages\": [\r\n {\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value1\"\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message1\"\r\n }\r\n },\r\n {\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value2\"\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message2\"\r\n }\r\n }\r\n ]\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/sendbulk", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "sendbulk" + ] + } + }, + "response": [ + { + "name": "Ok Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\"\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:19:17 GMT" + }, + { + "key": "Content-Length", + "value": "88" + } + ], + "cookie": [], + "body": "{\n \"message\": \"Message example was sent successfully to foo queue\",\n \"data\": {\n \"key\": \"value\"\n }\n}" + }, + { + "name": "Error Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\",\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:20:00 GMT" + }, + { + "key": "Content-Length", + "value": "120" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Some Error\",\n \"message\": \"Some Error Message\"\n}" + } + ] + }, + { + "name": "Send Bulk Template Topic Message Copy", + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"totalMessages\": 10,\r\n \"WaitBetweenBatchesInMilli\":10,\r\n \"batchOf\": 5,\r\n \"template\": {\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value1\"\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message1\"\r\n }\r\n }\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/sendbulktemplate", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "sendbulktemplate" + ] + } + }, + "response": [ + { + "name": "Ok Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\"\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:19:17 GMT" + }, + { + "key": "Content-Length", + "value": "88" + } + ], + "cookie": [], + "body": "{\n \"message\": \"Sent 10 Messages in 5 batches successfully to temp-aaa-gmt topic\"\n}" + }, + { + "name": "Error Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\",\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:20:00 GMT" + }, + { + "key": "Content-Length", + "value": "120" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Some Error\",\n \"message\": \"Some Error Message\"\n}" + } + ] + }, + { + "name": "Get Queue Messages", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/messages?qty=10&peek=true", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "messages" + ], + "query": [ + { + "key": "qty", + "value": "10", + "description": "Quantity of messages to return" + }, + { + "key": "peek", + "value": "true", + "description": "Should it only peek the messages?" + } + ] + } + }, + "response": [ + { + "name": "Ok Result", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/messages?qty=2&peek=true", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "messages" + ], + "query": [ + { + "key": "qty", + "value": "2", + "description": "Quantity of messages to return" + }, + { + "key": "peek", + "value": "true", + "description": "Should it only peek the messages?" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Fri, 30 Apr 2021 06:29:51 GMT" + }, + { + "key": "Content-Length", + "value": "372" + } + ], + "cookie": [], + "body": "[\n {\n \"id\": \"51c65e9d-cec1-4ad4-9553-205c5fa48ee9\",\n \"label\": \"example4\",\n \"correlationId\": \"test\",\n \"contentType\": \"application/json\",\n \"data\": {\n \"key\": \"value\"\n },\n \"userProperties\": {\n \"name\": \"test message\"\n }\n },\n {\n \"id\": \"4d56b3e2-7fd8-4afb-9486-5d584c3f6874\",\n \"label\": \"example3\",\n \"correlationId\": \"test\",\n \"contentType\": \"application/json\",\n \"data\": {\n \"key\": \"value\"\n },\n \"userProperties\": {\n \"name\": \"test message\"\n }\n }\n]" + }, + { + "name": "Error Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\",\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:20:00 GMT" + }, + { + "key": "Content-Length", + "value": "120" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Some Error\",\n \"message\": \"Some Error Message\"\n}" + } + ] + }, + { + "name": "Get Queue Dead Letters", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/deadletters?qty=10&peek=true", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "deadletters" + ], + "query": [ + { + "key": "qty", + "value": "10", + "description": "Quantity of messages to return" + }, + { + "key": "peek", + "value": "true", + "description": "Should it only peek the messages?" + } + ] + } + }, + "response": [ + { + "name": "Ok Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\"\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:19:17 GMT" + }, + { + "key": "Content-Length", + "value": "88" + } + ], + "cookie": [], + "body": "{\n \"message\": \"Message example was sent successfully to foo queue\",\n \"data\": {\n \"key\": \"value\"\n }\n}" + }, + { + "name": "Error Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\",\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:20:00 GMT" + }, + { + "key": "Content-Length", + "value": "120" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Some Error\",\n \"message\": \"Some Error Message\"\n}" + } + ] + } + ] + }, + { + "name": "DslMock", + "item": [ + { + "name": "Send RecognitionProgramChangeEvent", + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"Dsl.RecognitionProgramChangeEvent\",\r\n \"correlationId\": \"d7c963a2923242eb9b609aa8296f4a4d\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"Title\": \"Software program for Integration Test\",\r\n \"Version\": \"4.5.6\",\r\n \"TenantId\": \"11111111-1111-1111-1111-555555550001\",\r\n \"ChangeType\": 2\r\n },\r\n \"userProperties\": {\r\n \"X-MsgTypeVersion\": \"1.0\",\r\n \"X-MsgDomain\": \"Dsl\",\r\n \"X-MsgName\": \"RecognitionProgramChangeEvent\",\r\n \"X-Sender\": \"GlobalOutboxSender\",\r\n \"X-TenantId\": \"11111111-1111-1111-1111-555555550001\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/topics/aaa-gmt/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "aaa-gmt", + "send" + ] + } + }, + "response": [ + { + "name": "Ok Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\"\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:19:17 GMT" + }, + { + "key": "Content-Length", + "value": "88" + } + ], + "cookie": [], + "body": "{\n \"message\": \"Message example was sent successfully to foo queue\",\n \"data\": {\n \"key\": \"value\"\n }\n}" + }, + { + "name": "Error Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\",\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:20:00 GMT" + }, + { + "key": "Content-Length", + "value": "120" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Some Error\",\n \"message\": \"Some Error Message\"\n}" + } + ] + }, + { + "name": "Send Bulk RecognitionProgramChangeEvent", + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"messages\": [\r\n {\r\n \"label\": \"Dsl.RecognitionProgramChangeEvent\",\r\n \"correlationId\": \"d7c963a2923242eb9b609aa8296f4a4d\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"Title\": \"Software program for Integration Test\",\r\n \"Version\": \"4.5.6\",\r\n \"TenantId\": \"11111111-1111-1111-1111-555555550001\",\r\n \"ChangeType\": 0\r\n },\r\n \"userProperties\": {\r\n \"X-MsgTypeVersion\": \"1.0\",\r\n \"X-MsgDomain\": \"Dsl\",\r\n \"X-MsgName\": \"RecognitionProgramChangeEvent\",\r\n \"X-Sender\": \"GlobalOutboxSender\",\r\n \"X-TenantId\": \"11111111-1111-1111-1111-555555550001\"\r\n }\r\n },\r\n {\r\n \"label\": \"Dsl.RecognitionProgramChangeEvent\",\r\n \"correlationId\": \"d7c963a2923242eb9b609aa8296f4a4d\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"Title\": \"Software program for Integration Test\",\r\n \"Version\": \"4.5.6\",\r\n \"TenantId\": \"11111111-1111-1111-1111-555555550001\",\r\n \"ChangeType\": 0\r\n },\r\n \"userProperties\": {\r\n \"X-MsgTypeVersion\": \"1.0\",\r\n \"X-MsgDomain\": \"Dsl\",\r\n \"X-MsgName\": \"RecognitionProgramChangeEvent\",\r\n \"X-Sender\": \"GlobalOutboxSender\",\r\n \"X-TenantId\": \"11111111-1111-1111-1111-555555550001\"\r\n }\r\n }\r\n ]\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/topics/aaa-gmt/sendbulk", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "aaa-gmt", + "sendbulk" + ] + } + }, + "response": [ + { + "name": "Ok Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\"\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:19:17 GMT" + }, + { + "key": "Content-Length", + "value": "88" + } + ], + "cookie": [], + "body": "{\n \"message\": \"Message example was sent successfully to foo queue\",\n \"data\": {\n \"key\": \"value\"\n }\n}" + }, + { + "name": "Error Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\",\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:20:00 GMT" + }, + { + "key": "Content-Length", + "value": "120" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Some Error\",\n \"message\": \"Some Error Message\"\n}" + } + ] + }, + { + "name": "Send Bulk RecognitionProgramChangeEvent (500 Messages)", + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"totalMessages\": 10,\r\n \"WaitBetweenBatchesInMilli\":10,\r\n \"batchOf\": 5,\r\n \"template\": {\r\n \"label\": \"Dsl.RecognitionProgramChangeEvent\",\r\n \"correlationId\": \"d7c963a2923242eb9b609aa8296f4a4d\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"Title\": \"Software program for Integration Test\",\r\n \"Version\": \"4.5.6\",\r\n \"TenantId\": \"11111111-1111-1111-1111-555555550001\",\r\n \"ChangeType\": 0\r\n },\r\n \"userProperties\": {\r\n \"X-MsgTypeVersion\": \"1.0\",\r\n \"X-MsgDomain\": \"Dsl\",\r\n \"X-MsgName\": \"RecognitionProgramChangeEvent\",\r\n \"X-Sender\": \"GlobalOutboxSender\",\r\n \"X-TenantId\": \"11111111-1111-1111-1111-555555550001\"\r\n }\r\n }\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/topics/aaa-gmt/sendbulktemplate", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "aaa-gmt", + "sendbulktemplate" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "DataServiceMock", + "item": [ + { + "name": "Send RecognitionProgramChangeEvent", + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"Dsl.RecognitionProgramChangeEvent\",\r\n \"correlationId\": \"d7c963a2923242eb9b609aa8296f4a4d\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"Title\": \"\",\r\n \"Version\": \"4.5.6\",\r\n \"TenantId\": \"00000000-1111-1111-200d-03a37c5709ba\",\r\n \"ChangeType\": 2\r\n },\r\n \"userProperties\": {\r\n \"X-MsgTypeVersion\": \"1.0\",\r\n \"X-MsgDomain\": \"Dsl\",\r\n \"X-MsgName\": \"RecognitionProgramChangeEvent\",\r\n \"X-Sender\": \"GlobalOutboxSender\",\r\n \"X-TenantId\": \"00000000-1111-1111-200d-03a37c5709ba\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/topics/aaa-gmt/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "aaa-gmt", + "send" + ] + } + }, + "response": [ + { + "name": "Ok Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\"\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:19:17 GMT" + }, + { + "key": "Content-Length", + "value": "88" + } + ], + "cookie": [], + "body": "{\n \"message\": \"Message example was sent successfully to foo queue\",\n \"data\": {\n \"key\": \"value\"\n }\n}" + }, + { + "name": "Error Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\",\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:20:00 GMT" + }, + { + "key": "Content-Length", + "value": "120" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Some Error\",\n \"message\": \"Some Error Message\"\n}" + } + ] + } + ] + }, + { + "name": "LcmMock", + "item": [ + { + "name": "Send SaaSApplicationsDetailsEvent", + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"LCM.SaaSApplicationsDetailsEvent\",\r\n \"correlationId\": \"d7c963a2923242eb9b609aa8296f4a4d\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"TenantId\": \"00000000-1111-1111-200d-0491f2995d6d\",\r\n \"ApplicationDetails\": [\r\n {\r\n \"ApplicationId\": \"0oat7lvlfmgeW5lgt0g7\",\r\n \"TotalSubscriptions\": \"2\",\r\n \"SpendInLast365Days\": \"1234.4\"\r\n },\r\n {\r\n \"ApplicationId\": \"0oat7mm58kAmgR8ry0g9\",\r\n \"TotalSubscriptions\": \"4\",\r\n \"SpendInLast365Days\": \"2056.4\"\r\n },\r\n {\r\n \"ApplicationId\": \"0oat7mo58kAmgT7tt0g7\",\r\n \"TotalSubscriptions\": \"4\",\r\n \"SpendInLast365Days\": \"30880.4\"\r\n }\r\n ]\r\n },\r\n \"userProperties\": {\r\n \"X-MsgTypeVersion\": \"1.0\",\r\n \"X-MsgDomain\": \"LCM\",\r\n \"X-MsgName\": \"SaaSApplicationsDetailsEvent\",\r\n \"X-Sender\": \"GlobalOutboxSender\",\r\n \"X-TenantId\": \"00000000-1111-1111-200d-0491f2995d6d\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/topics/aaa-gmt/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "topics", + "aaa-gmt", + "send" + ] + } + }, + "response": [ + { + "name": "Ok Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\"\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:19:17 GMT" + }, + { + "key": "Content-Length", + "value": "88" + } + ], + "cookie": [], + "body": "{\n \"message\": \"Message example was sent successfully to foo queue\",\n \"data\": {\n \"key\": \"value\"\n }\n}" + }, + { + "name": "Error Result", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"label\": \"example\",\r\n \"correlationId\": \"test\",\r\n \"contentType\": \"application/json\",\r\n \"data\": {\r\n \"key\": \"value\",\r\n },\r\n \"userProperties\": {\r\n \"name\": \"test message\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{protocol}}://{{url}}/queues/{{queueName}}/send", + "protocol": "{{protocol}}", + "host": [ + "{{url}}" + ], + "path": [ + "queues", + "{{queueName}}", + "send" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Date", + "value": "Thu, 29 Apr 2021 15:20:00 GMT" + }, + { + "key": "Content-Length", + "value": "120" + } + ], + "cookie": [], + "body": "{\n \"code\": 400,\n \"error\": \"Some Error\",\n \"message\": \"Some Error Message\"\n}" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/controller/main.go b/controller/main.go index 4a36c4e..16e359e 100644 --- a/controller/main.go +++ b/controller/main.go @@ -1,6 +1,7 @@ package controller import ( + "encoding/json" "io/ioutil" "log" "os" @@ -9,6 +10,7 @@ import ( cjlog "github.com/cjlapao/common-go/log" "github.com/cjlapao/common-go/version" + "github.com/cjlapao/servicebuscli-go/entities" "github.com/cjlapao/servicebuscli-go/servicebus" "github.com/gomarkdown/markdown" "github.com/gomarkdown/markdown/parser" @@ -37,12 +39,12 @@ func handleRequests() { port = "10000" } - logger.Info("Starting Api Server on port " + port) + logger.Info("Api Server starting on port " + port + ".") router := mux.NewRouter().StrictSlash(true) router.Use(commonMiddleware) router.HandleFunc("/", homePage) _ = NewAPIController(router) - logger.Success("Finished Init") + logger.Success("API Server ready on port " + port + ".") log.Fatal(http.ListenAndServe(":"+port, router)) } @@ -78,7 +80,7 @@ func commonMiddleware(next http.Handler) http.Handler { func ServiceBusConnectionMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - logger.Info("[%v] %v route...", r.Method, r.URL.Path) + logger.Info("[%v] %v route requested by %v.", r.Method, r.URL.Path, r.RemoteAddr) if connStr == "" { w.WriteHeader(http.StatusBadRequest) w.Write([]byte("No Azure Service Bus Connection String defined")) @@ -98,12 +100,15 @@ func NewAPIController(router *mux.Router) Controller { controller.Router.Use(ServiceBusConnectionMiddleware) controller.Router.Use(commonMiddleware) // Topics Controllers + controller.Router.HandleFunc("/config", controller.SetConnectionString).Methods("POST") controller.Router.HandleFunc("/topics", controller.GetTopics).Methods("GET") controller.Router.HandleFunc("/topics", controller.CreateTopic).Methods("POST") controller.Router.HandleFunc("/topics", controller.CreateTopic).Methods("PUT") controller.Router.HandleFunc("/topics/{topicName}", controller.GetTopic).Methods("GET") controller.Router.HandleFunc("/topics/{topicName}", controller.DeleteTopic).Methods("DELETE") controller.Router.HandleFunc("/topics/{topicName}/send", controller.SendTopicMessage).Methods("PUT") + controller.Router.HandleFunc("/topics/{topicName}/sendbulk", controller.SendBulkTopicMessage).Methods("PUT") + controller.Router.HandleFunc("/topics/{topicName}/sendbulktemplate", controller.SendBulkTemplateTopicMessage).Methods("PUT") // Subscriptions Controllers controller.Router.HandleFunc("/topics/{topicName}/subscriptions", controller.GetTopicSubscriptions).Methods("GET") controller.Router.HandleFunc("/topics/{topicName}/subscriptions", controller.UpsertTopicSubscription).Methods("POST") @@ -119,11 +124,64 @@ func NewAPIController(router *mux.Router) Controller { // Queues Controllers controller.Router.HandleFunc("/queues", controller.GetQueues).Methods("GET") controller.Router.HandleFunc("/queues", controller.UpsertQueue).Methods("POST") + controller.Router.HandleFunc("/queues", controller.UpsertQueue).Methods("PUT") controller.Router.HandleFunc("/queues/{queueName}", controller.GetQueue).Methods("GET") controller.Router.HandleFunc("/queues/{queueName}", controller.DeleteQueue).Methods("DELETE") controller.Router.HandleFunc("/queues/{queueName}/send", controller.SendQueueMessage).Methods("PUT") + controller.Router.HandleFunc("/queues/{queueName}/sendbulk", controller.SendBulkQueueMessage).Methods("PUT") + controller.Router.HandleFunc("/queues/{queueName}/sendbulktemplate", controller.SendBulkTemplateQueueMessage).Methods("PUT") controller.Router.HandleFunc("/queues/{queueName}/deadletters", controller.GetQueueDeadLetterMessages).Methods("GET") controller.Router.HandleFunc("/queues/{queueName}/messages", controller.GetQueueMessages).Methods("GET") return controller } + +// GetTopics Gets all topics in the namespace +func (c *Controller) SetConnectionString(w http.ResponseWriter, r *http.Request) { + reqBody, err := ioutil.ReadAll(r.Body) + errorResponse := entities.ApiErrorResponse{} + + // Body cannot be null error + if err != nil { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Empty Body" + errorResponse.Message = "The body of the request is null or empty" + json.NewEncoder(w).Encode(errorResponse) + return + } + + connection := entities.ConfigRequest{} + err = json.Unmarshal(reqBody, &connection) + + // Body deserialization error + if err != nil { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Failed Body Deserialization" + errorResponse.Message = "There was an error deserializing the body of the request" + json.NewEncoder(w).Encode(errorResponse) + return + } + if connection.ConnectionString == "" { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Empty Connection String" + errorResponse.Message = "Connection string cannot be empty" + json.NewEncoder(w).Encode(errorResponse) + return + } + sbcli = servicebus.NewCli(connection.ConnectionString) + + if err != nil { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Error Creating Topic" + errorResponse.Message = "There was an error creating topic" + json.NewEncoder(w).Encode(errorResponse) + return + } + + os.Setenv("SERVICEBUS_CONNECTION_STRING", connection.ConnectionString) + w.WriteHeader(http.StatusAccepted) +} diff --git a/controller/queue.go b/controller/queue.go index 360123a..1ecc0c3 100644 --- a/controller/queue.go +++ b/controller/queue.go @@ -2,38 +2,50 @@ package controller import ( "encoding/json" + "fmt" "io/ioutil" "net/http" "strconv" + "strings" + "sync" + "time" "github.com/cjlapao/servicebuscli-go/entities" "github.com/gorilla/mux" ) -// GetQueues Gets all queues in the namespace +// GetQueues Gets all queues in the current namespace func (c *Controller) GetQueues(w http.ResponseWriter, r *http.Request) { errorResponse := entities.ApiErrorResponse{} azQueues, err := sbcli.ListQueues() if err != nil { w.WriteHeader(http.StatusBadRequest) errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Error Query" + errorResponse.Error = "Server Error" errorResponse.Message = err.Error() json.NewEncoder(w).Encode(errorResponse) return } - queues := make([]entities.QueueResponseEntity, 0) + queues := make([]entities.QueueResponse, 0) + + if len(azQueues) == 0 { + w.WriteHeader(http.StatusNoContent) + json.NewEncoder(w).Encode(queues) + return + } + for _, azQueue := range azQueues { - queue := entities.QueueResponseEntity{} + queue := entities.QueueResponse{} queue.FromServiceBus(azQueue) queues = append(queues, queue) } + w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(queues) } -// GetQueues Gets all queues in the namespace +// GetQueue Gets the details of a specific Queue in the current namespace func (c *Controller) GetQueue(w http.ResponseWriter, r *http.Request) { errorResponse := entities.ApiErrorResponse{} vars := mux.Vars(r) @@ -43,24 +55,33 @@ func (c *Controller) GetQueue(w http.ResponseWriter, r *http.Request) { if queueName == "" { w.WriteHeader(http.StatusBadRequest) errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "queue name is null" - errorResponse.Message = "queue name is null" + errorResponse.Error = "Server Error" + errorResponse.Message = "Queue name parameter cannot be null or empty" json.NewEncoder(w).Encode(errorResponse) return } queue, err := sbcli.GetQueueDetails(queueName) - if queue == nil || err != nil { + if queue == nil && strings.Contains(err.Error(), "not found") { w.WriteHeader(http.StatusNotFound) errorResponse.Code = http.StatusNotFound - errorResponse.Error = "queue not found" - errorResponse.Message = "queue with name " + queueName + " was not found in " + sbcli.Namespace.Name + errorResponse.Error = "Queue Not Found" + errorResponse.Message = "Queue with name " + queueName + " was not found in " + sbcli.Namespace.Name json.NewEncoder(w).Encode(errorResponse) return } - response := entities.QueueResponseEntity{} + if queue == nil && err != nil { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Server Error" + errorResponse.Message = err.Error() + json.NewEncoder(w).Encode(errorResponse) + return + } + + response := entities.QueueResponse{} response.FromServiceBus(queue) json.NewEncoder(w).Encode(response) } @@ -69,6 +90,10 @@ func (c *Controller) GetQueue(w http.ResponseWriter, r *http.Request) { func (c *Controller) UpsertQueue(w http.ResponseWriter, r *http.Request) { reqBody, err := ioutil.ReadAll(r.Body) errorResponse := entities.ApiErrorResponse{} + upsert := false + if r.Method == "PUT" { + upsert = true + } // Body cannot be null error if err != nil { @@ -80,7 +105,7 @@ func (c *Controller) UpsertQueue(w http.ResponseWriter, r *http.Request) { return } - queueRequest := entities.QueueRequestEntity{} + queueRequest := entities.QueueRequest{} err = json.Unmarshal(reqBody, &queueRequest) // Body deserialization error @@ -105,6 +130,19 @@ func (c *Controller) UpsertQueue(w http.ResponseWriter, r *http.Request) { } } + if !upsert { + queueExists, _ := sbcli.GetQueue(queueRequest.Name) + + if queueExists != nil { + w.WriteHeader(http.StatusBadRequest) + found := entities.ApiSuccessResponse{ + Message: "The Queue " + queueRequest.Name + " already exists in " + sbcli.Namespace.Name + ", ignoring", + } + json.NewEncoder(w).Encode(found) + return + } + } + err = sbcli.CreateQueue(queueRequest) if err != nil { @@ -127,13 +165,13 @@ func (c *Controller) UpsertQueue(w http.ResponseWriter, r *http.Request) { return } - response := entities.QueueResponseEntity{} + response := entities.QueueResponse{} response.FromServiceBus(createdQueue) w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(response) } -// DeleteTopicSubscription Deletes subscription from a topic in the namespace +// DeleteQueue Deletes a Queue in the namespace func (c *Controller) DeleteQueue(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) queueName := vars["queueName"] @@ -142,18 +180,27 @@ func (c *Controller) DeleteQueue(w http.ResponseWriter, r *http.Request) { if queueName == "" { w.WriteHeader(http.StatusBadRequest) errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Topic name is null" - errorResponse.Message = "Topic name cannot be null" + errorResponse.Error = "Server Error" + errorResponse.Message = "Queue name parameter cannot be null or empty" json.NewEncoder(w).Encode(errorResponse) return } queue, err := sbcli.GetQueueDetails(queueName) - if queue == nil || err != nil { + if queue == nil && strings.Contains(err.Error(), "not found") { w.WriteHeader(http.StatusNotFound) errorResponse.Code = http.StatusNotFound - errorResponse.Error = "Topic not found" - errorResponse.Message = "The Topic " + queueName + " was not found in the service bus " + sbcli.Namespace.Name + errorResponse.Error = "Queue Not Found" + errorResponse.Message = "Queue with name " + queueName + " was not found in " + sbcli.Namespace.Name + json.NewEncoder(w).Encode(errorResponse) + return + } + + if queue == nil && err != nil { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Server Error" + errorResponse.Message = err.Error() json.NewEncoder(w).Encode(errorResponse) return } @@ -162,30 +209,27 @@ func (c *Controller) DeleteQueue(w http.ResponseWriter, r *http.Request) { if err != nil { w.WriteHeader(http.StatusNotFound) errorResponse.Code = http.StatusNotFound - errorResponse.Error = "Error Deleting Subscription" + errorResponse.Error = "Server Error" errorResponse.Message = err.Error() json.NewEncoder(w).Encode(errorResponse) return } - response := entities.QueueResponseEntity{} - response.FromServiceBus(queue) w.WriteHeader(http.StatusAccepted) - json.NewEncoder(w).Encode(response) } +// SendQueueMessage Sends a Message to a Queue in the current namespace func (c *Controller) SendQueueMessage(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) queueName := vars["queueName"] reqBody, err := ioutil.ReadAll(r.Body) errorResponse := entities.ApiErrorResponse{} - // Topic Name cannot be nil if queueName == "" { w.WriteHeader(http.StatusBadRequest) errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Queue name is null" - errorResponse.Message = "Queue name cannot be null" + errorResponse.Error = "Server Error" + errorResponse.Message = "Queue name parameter cannot be null or empty" json.NewEncoder(w).Encode(errorResponse) return } @@ -200,7 +244,7 @@ func (c *Controller) SendQueueMessage(w http.ResponseWriter, r *http.Request) { return } - message := entities.ServiceBusMessageRequest{} + message := entities.MessageRequest{} err = json.Unmarshal(reqBody, &message) // Body deserialization error @@ -229,7 +273,7 @@ func (c *Controller) SendQueueMessage(w http.ResponseWriter, r *http.Request) { if err != nil { w.WriteHeader(http.StatusBadRequest) errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Error Sending Topic Message" + errorResponse.Error = "Error Sending Queue Message" errorResponse.Message = "There was an error sending message to queue " + queueName json.NewEncoder(w).Encode(errorResponse) return @@ -244,7 +288,196 @@ func (c *Controller) SendQueueMessage(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(response) } -// GetSubscriptionMessages Gets messages from a topic subscription +// SendBulkQueueMessage Sends a Message to a Queue in the current namespace +func (c *Controller) SendBulkQueueMessage(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + queueName := vars["queueName"] + reqBody, err := ioutil.ReadAll(r.Body) + errorResponse := entities.ApiErrorResponse{} + + if queueName == "" { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Server Error" + errorResponse.Message = "Queue name parameter cannot be null or empty" + json.NewEncoder(w).Encode(errorResponse) + return + } + + // Body cannot be nil error + if err != nil { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Empty Body" + errorResponse.Message = "The body of the request is null or empty" + json.NewEncoder(w).Encode(errorResponse) + return + } + + bulk := entities.BulkMessageRequest{} + err = json.Unmarshal(reqBody, &bulk) + + // Body deserialization error + if err != nil { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Failed Body Deserialization" + errorResponse.Message = "There was an error deserializing the body of the request" + json.NewEncoder(w).Encode(errorResponse) + return + } + + err = sbcli.SendBulkQueueMessage(queueName, bulk.Messages...) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Error Sending Queue Message" + errorResponse.Message = "There was an error sending bulk messages to queue " + queueName + json.NewEncoder(w).Encode(errorResponse) + return + } + + response := entities.ApiSuccessResponse{ + Message: "Sent " + fmt.Sprint(len(bulk.Messages)) + " Messages successfully to " + queueName + " queue", + } + + w.WriteHeader(http.StatusAccepted) + json.NewEncoder(w).Encode(response) +} + +// SendBulkQueueMessage Sends a Message to a Queue in the current namespace +func (c *Controller) SendBulkTemplateQueueMessage(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + queueName := vars["queueName"] + reqBody, err := ioutil.ReadAll(r.Body) + errorResponse := entities.ApiErrorResponse{} + maxSizeOfPayload := 262144 + + if queueName == "" { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Server Error" + errorResponse.Message = "Queue name parameter cannot be null or empty" + json.NewEncoder(w).Encode(errorResponse) + return + } + + // Body cannot be nil error + if err != nil { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Empty Body" + errorResponse.Message = "The body of the request is null or empty" + json.NewEncoder(w).Encode(errorResponse) + return + } + + bulk := entities.BulkTemplateMessageRequest{} + err = json.Unmarshal(reqBody, &bulk) + + // Body deserialization error + if err != nil { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Failed Body Deserialization" + errorResponse.Message = "There was an error deserializing the body of the request" + json.NewEncoder(w).Encode(errorResponse) + return + } + + if bulk.BatchOf > bulk.TotalMessages { + bulk.BatchOf = 1 + } + + totalMessageSent := 0 + + messageTemplate, err := json.Marshal(bulk.Template) + + if err != nil { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = err.Error() + errorResponse.Message = "There was an error checking the templated message payload size" + json.NewEncoder(w).Encode(errorResponse) + return + } + + messageTemplateSize := len(messageTemplate) + totalMessagePayloadSize := messageTemplateSize * bulk.TotalMessages + minimumBatchSize := totalMessagePayloadSize / maxSizeOfPayload + if minimumBatchSize > bulk.BatchOf { + bulk.BatchOf = minimumBatchSize + 5 + logger.Info("The total payload was too big for the given batch size, increasing it to the minimum of " + fmt.Sprint(bulk.BatchOf)) + } + + batchSize := bulk.TotalMessages / bulk.BatchOf + messages := make([]entities.MessageRequest, 0) + for i := 0; i < batchSize; i++ { + messages = append(messages, bulk.Template) + } + + if bulk.WaitBetweenBatchesInMilli > 0 { + for i := 0; i < bulk.BatchOf; i++ { + if i > 0 && bulk.WaitBetweenBatchesInMilli > 0 { + logger.Info("Waiting " + fmt.Sprint(bulk.WaitBetweenBatchesInMilli) + "ms for next batch") + time.Sleep(time.Duration(bulk.WaitBetweenBatchesInMilli) * time.Millisecond) + } + + err = sbcli.SendBulkQueueMessage(queueName, messages...) + + if err != nil { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = err.Error() + errorResponse.Message = "There was an error sending bulk messages to queue " + queueName + json.NewEncoder(w).Encode(errorResponse) + return + } + totalMessageSent += len(messages) + } + } else { + logger.Info("Sending all batches without waiting") + var waitFor sync.WaitGroup + waitFor.Add(bulk.BatchOf) + for i := 0; i < bulk.BatchOf; i++ { + go sbcli.SendParallelBulkQueueMessage(&waitFor, queueName, messages...) + totalMessageSent += len(messages) + } + + waitFor.Wait() + logger.Success("Finished sending all the batches to service bus") + } + + if totalMessageSent < bulk.TotalMessages { + missingMessageCount := bulk.TotalMessages - totalMessageSent + logger.Info("Sending remaining " + fmt.Sprint(missingMessageCount) + " messages in the payload") + messages := make([]entities.MessageRequest, 0) + for x := 0; x < missingMessageCount; x++ { + messages = append(messages, bulk.Template) + } + + err = sbcli.SendBulkQueueMessage(queueName, messages...) + + if err != nil { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = err.Error() + errorResponse.Message = "There was an error sending bulk messages to queue " + queueName + json.NewEncoder(w).Encode(errorResponse) + return + } + bulk.BatchOf += 1 + } + + response := entities.ApiSuccessResponse{ + Message: "Sent " + fmt.Sprint(bulk.TotalMessages) + " Messages in " + fmt.Sprint(bulk.BatchOf) + " batches successfully to " + queueName + " queue", + } + + w.WriteHeader(http.StatusAccepted) + json.NewEncoder(w).Encode(response) +} + +// GetQueueMessages Gets messages from a Queue in the current namespace func (c *Controller) GetQueueMessages(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) queueName := vars["queueName"] @@ -267,7 +500,7 @@ func (c *Controller) GetQueueMessages(w http.ResponseWriter, r *http.Request) { errorResponse := entities.ApiErrorResponse{} - // Topic Name cannot be nil + // Queue Name cannot be nil if queueName == "" { w.WriteHeader(http.StatusBadRequest) errorResponse.Code = http.StatusBadRequest @@ -293,9 +526,9 @@ func (c *Controller) GetQueueMessages(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNoContent) return } else { - response := make([]entities.ServiceBusMessageRequest, 0) + response := make([]entities.MessageResponse, 0) for _, msg := range result { - entityMsg := entities.ServiceBusMessageRequest{} + entityMsg := entities.MessageResponse{} entityMsg.FromServiceBus(&msg) response = append(response, entityMsg) } @@ -305,7 +538,7 @@ func (c *Controller) GetQueueMessages(w http.ResponseWriter, r *http.Request) { } } -// GetSubscriptionMessages Gets messages from a topic subscription +// GetQueueDeadLetterMessages Gets dead letters from a Queue in the current namespace func (c *Controller) GetQueueDeadLetterMessages(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) queueName := vars["queueName"] @@ -328,12 +561,12 @@ func (c *Controller) GetQueueDeadLetterMessages(w http.ResponseWriter, r *http.R errorResponse := entities.ApiErrorResponse{} - // Topic Name cannot be nil + // Queue Name cannot be nil if queueName == "" { w.WriteHeader(http.StatusBadRequest) errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Topic name is null" - errorResponse.Message = "Topic name cannot be null" + errorResponse.Error = "Queue name is null" + errorResponse.Message = "Queue name cannot be null" json.NewEncoder(w).Encode(errorResponse) return } @@ -354,9 +587,9 @@ func (c *Controller) GetQueueDeadLetterMessages(w http.ResponseWriter, r *http.R w.WriteHeader(http.StatusNoContent) return } else { - response := make([]entities.ServiceBusMessageRequest, 0) + response := make([]entities.MessageResponse, 0) for _, msg := range result { - entityMsg := entities.ServiceBusMessageRequest{} + entityMsg := entities.MessageResponse{} entityMsg.FromServiceBus(&msg) response = append(response, entityMsg) } diff --git a/controller/subscription.go b/controller/subscription.go index e426426..30f61a1 100644 --- a/controller/subscription.go +++ b/controller/subscription.go @@ -5,12 +5,13 @@ import ( "io/ioutil" "net/http" "strconv" + "strings" "github.com/cjlapao/servicebuscli-go/entities" "github.com/gorilla/mux" ) -// GetTopicSubscriptions Gets All the subscriptions in a topic +// GetTopicSubscriptions Gets all of the subscriptions from a topic in the current namespace func (c *Controller) GetTopicSubscriptions(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) topicName := vars["topicName"] @@ -45,17 +46,18 @@ func (c *Controller) GetTopicSubscriptions(w http.ResponseWriter, r *http.Reques return } - subscriptions := make([]entities.SubscriptionResponseEntity, 0) + subscriptions := make([]entities.SubscriptionResponse, 0) for _, azSubscription := range azTopicSubscriptions { - result := entities.SubscriptionResponseEntity{} + result := entities.SubscriptionResponse{} result.FromServiceBus(azSubscription) subscriptions = append(subscriptions, result) } + w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(subscriptions) } -// GetTopicSubscription Gets a subscription from a topic in the namespace +// GetTopicSubscription Gets the details of a subscription from a topic in the current namespace func (c *Controller) GetTopicSubscription(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) topicName := vars["topicName"] @@ -102,12 +104,12 @@ func (c *Controller) GetTopicSubscription(w http.ResponseWriter, r *http.Request return } - apiSubscription := entities.SubscriptionResponseEntity{} + apiSubscription := entities.SubscriptionResponse{} apiSubscription.FromServiceBus(azSubscription) json.NewEncoder(w).Encode(apiSubscription) } -// UpsertTopicSubscription Creates a subscription in a topic +// UpsertTopicSubscription Update or Insert a subscription in a topic in the current namespace func (c *Controller) UpsertTopicSubscription(w http.ResponseWriter, r *http.Request) { reqBody, err := ioutil.ReadAll(r.Body) vars := mux.Vars(r) @@ -118,28 +120,28 @@ func (c *Controller) UpsertTopicSubscription(w http.ResponseWriter, r *http.Requ upsert = true } - // Checking for null parameters - if topicName == "" { + // Body cannot be null error + if err != nil { w.WriteHeader(http.StatusBadRequest) errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Topic name is null" - errorResponse.Message = "Topic name cannot be null" + errorResponse.Error = "Empty Body" + errorResponse.Message = "The body of the request is null or empty" json.NewEncoder(w).Encode(errorResponse) return } - // Body cannot be null error - if err != nil { + // Checking for null parameters + if topicName == "" { w.WriteHeader(http.StatusBadRequest) errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Empty Body" - errorResponse.Message = "The body of the request is null or empty" + errorResponse.Error = "Topic name is null" + errorResponse.Message = "Topic name cannot be null" json.NewEncoder(w).Encode(errorResponse) return } - bodySubscription := entities.SubscriptionRequestEntity{} - err = json.Unmarshal(reqBody, &bodySubscription) + subscriptionRequest := entities.SubscriptionRequest{} + err = json.Unmarshal(reqBody, &subscriptionRequest) // Body deserialization error if err != nil { @@ -151,8 +153,8 @@ func (c *Controller) UpsertTopicSubscription(w http.ResponseWriter, r *http.Requ return } - bodySubscription.TopicName = topicName - isValid, validError := bodySubscription.ValidateSubscriptionRequest() + subscriptionRequest.TopicName = topicName + isValid, validError := subscriptionRequest.IsValid() if !isValid { if validError != nil { w.WriteHeader(int(validError.Code)) @@ -163,30 +165,20 @@ func (c *Controller) UpsertTopicSubscription(w http.ResponseWriter, r *http.Requ } } - _, errResp := bodySubscription.GetOptions() - - if errResp != nil { - w.WriteHeader(int(errResp.Code)) - json.NewEncoder(w).Encode(errResp) - return - - } - if !upsert { - subscriptionExists, _ := sbcli.GetSubscription(bodySubscription.TopicName, bodySubscription.Name) + subscriptionExists, _ := sbcli.GetSubscription(subscriptionRequest.TopicName, subscriptionRequest.Name) if subscriptionExists != nil { w.WriteHeader(http.StatusBadRequest) found := entities.ApiSuccessResponse{ - Message: "The Subscription " + bodySubscription.Name + " already exists in topic " + bodySubscription.TopicName + ", ignoring", + Message: "The Subscription " + subscriptionRequest.Name + " already exists in topic " + subscriptionRequest.TopicName + " in " + sbcli.Namespace.Name + ", ignoring", } json.NewEncoder(w).Encode(found) return } - } - err = sbcli.CreateSubscription(bodySubscription, upsert) + err = sbcli.CreateSubscription(subscriptionRequest, upsert) if err != nil { w.WriteHeader(http.StatusBadRequest) @@ -197,22 +189,23 @@ func (c *Controller) UpsertTopicSubscription(w http.ResponseWriter, r *http.Requ return } - subscriptionE := entities.SubscriptionResponseEntity{} - createdSubscription, err := sbcli.GetSubscription(bodySubscription.TopicName, bodySubscription.Name) + createdSubscription, err := sbcli.GetSubscription(subscriptionRequest.TopicName, subscriptionRequest.Name) if err != nil { w.WriteHeader(http.StatusBadRequest) errorResponse.Code = http.StatusBadRequest errorResponse.Error = "Error Creating Subscription" - errorResponse.Message = "There was an error creating subscription" + errorResponse.Message = err.Error() json.NewEncoder(w).Encode(errorResponse) return } - subscriptionE.FromServiceBus(createdSubscription) + + response := entities.SubscriptionResponse{} + response.FromServiceBus(createdSubscription) w.WriteHeader(http.StatusCreated) - json.NewEncoder(w).Encode(subscriptionE) + json.NewEncoder(w).Encode(response) } -// DeleteTopicSubscription Deletes subscription from a topic in the namespace +// DeleteTopicSubscription Deletes subscription from a topic in the current namespace func (c *Controller) DeleteTopicSubscription(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) topicName := vars["topicName"] @@ -248,32 +241,38 @@ func (c *Controller) DeleteTopicSubscription(w http.ResponseWriter, r *http.Requ } sbSubscription, err := sbcli.GetSubscription(topicName, subscriptionName) - if err != nil { + if sbSubscription == nil && strings.Contains(err.Error(), "not found") { w.WriteHeader(http.StatusNotFound) errorResponse.Code = http.StatusNotFound - errorResponse.Error = "Topic not found" + errorResponse.Error = "Subscription not found" errorResponse.Message = "The Subscription " + subscriptionName + " was not found on topic " + topicName + " in the service bus " + sbcli.Namespace.Name json.NewEncoder(w).Encode(errorResponse) return } + if sbSubscription == nil && err != nil { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Server Error" + errorResponse.Message = err.Error() + json.NewEncoder(w).Encode(errorResponse) + return + } + err = sbcli.DeleteSubscription(topicName, subscriptionName) if err != nil { w.WriteHeader(http.StatusNotFound) errorResponse.Code = http.StatusNotFound - errorResponse.Error = "Error Deleting Subscription" + errorResponse.Error = "Server Error" errorResponse.Message = err.Error() json.NewEncoder(w).Encode(errorResponse) return } - response := entities.SubscriptionResponseEntity{} - response.FromServiceBus(sbSubscription) w.WriteHeader(http.StatusAccepted) - json.NewEncoder(w).Encode(response) } -// GetSubscriptionMessages Gets messages from a topic subscription +// GetSubscriptionMessages Gets messages from a subscription in a topic in the current namespace func (c *Controller) GetSubscriptionMessages(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) topicName := vars["topicName"] @@ -311,8 +310,8 @@ func (c *Controller) GetSubscriptionMessages(w http.ResponseWriter, r *http.Requ if subscriptionName == "" { w.WriteHeader(http.StatusBadRequest) errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Topic name is null" - errorResponse.Message = "Topic name cannot be null" + errorResponse.Error = "Subscription name is null" + errorResponse.Message = "Subscription name cannot be null" json.NewEncoder(w).Encode(errorResponse) return } @@ -323,7 +322,7 @@ func (c *Controller) GetSubscriptionMessages(w http.ResponseWriter, r *http.Requ if err != nil { w.WriteHeader(http.StatusBadRequest) errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Failed Message Data Deserialization" + errorResponse.Error = "Server Error" errorResponse.Message = err.Error() json.NewEncoder(w).Encode(errorResponse) return @@ -333,9 +332,9 @@ func (c *Controller) GetSubscriptionMessages(w http.ResponseWriter, r *http.Requ w.WriteHeader(http.StatusNoContent) return } else { - response := make([]entities.ServiceBusMessageRequest, 0) + response := make([]entities.MessageResponse, 0) for _, msg := range result { - entityMsg := entities.ServiceBusMessageRequest{} + entityMsg := entities.MessageResponse{} entityMsg.FromServiceBus(&msg) response = append(response, entityMsg) } @@ -345,7 +344,7 @@ func (c *Controller) GetSubscriptionMessages(w http.ResponseWriter, r *http.Requ } } -// GetSubscriptionMessages Gets messages from a topic subscription +// GetSubscriptionMessages Gets dead letters from a subscription in a topic in the current namespace func (c *Controller) GetSubscriptionDeadLetterMessages(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) topicName := vars["topicName"] @@ -383,8 +382,8 @@ func (c *Controller) GetSubscriptionDeadLetterMessages(w http.ResponseWriter, r if subscriptionName == "" { w.WriteHeader(http.StatusBadRequest) errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Topic name is null" - errorResponse.Message = "Topic name cannot be null" + errorResponse.Error = "Subscription name is null" + errorResponse.Message = "Subscription name cannot be null" json.NewEncoder(w).Encode(errorResponse) return } @@ -395,7 +394,7 @@ func (c *Controller) GetSubscriptionDeadLetterMessages(w http.ResponseWriter, r if err != nil { w.WriteHeader(http.StatusBadRequest) errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Failed Message Data Deserialization" + errorResponse.Error = "Server Error" errorResponse.Message = err.Error() json.NewEncoder(w).Encode(errorResponse) return @@ -405,9 +404,9 @@ func (c *Controller) GetSubscriptionDeadLetterMessages(w http.ResponseWriter, r w.WriteHeader(http.StatusNoContent) return } else { - response := make([]entities.ServiceBusMessageRequest, 0) + response := make([]entities.MessageRequest, 0) for _, msg := range result { - entityMsg := entities.ServiceBusMessageRequest{} + entityMsg := entities.MessageRequest{} entityMsg.FromServiceBus(&msg) response = append(response, entityMsg) } @@ -438,19 +437,18 @@ func (c *Controller) GetSubscriptionRules(w http.ResponseWriter, r *http.Request if subscriptionName == "" { w.WriteHeader(http.StatusBadRequest) errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Topic name is null" - errorResponse.Message = "Topic name cannot be null" + errorResponse.Error = "Subscription name is null" + errorResponse.Message = "Subscription name cannot be null" json.NewEncoder(w).Encode(errorResponse) return } result, err := sbcli.GetSubscriptionRules(topicName, subscriptionName) - // Body deserialization error if err != nil { w.WriteHeader(http.StatusBadRequest) errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Failed to GET Subscription Rules" + errorResponse.Error = "Server Error" errorResponse.Message = err.Error() json.NewEncoder(w).Encode(errorResponse) return @@ -460,9 +458,9 @@ func (c *Controller) GetSubscriptionRules(w http.ResponseWriter, r *http.Request w.WriteHeader(http.StatusNoContent) return } else { - response := make([]entities.RuleResponseEntity, 0) + response := make([]entities.RuleResponse, 0) for _, msg := range result { - entityMsg := entities.RuleResponseEntity{} + entityMsg := entities.RuleResponse{} entityMsg.FromServiceBus(msg) response = append(response, entityMsg) } @@ -494,13 +492,13 @@ func (c *Controller) GetSubscriptionRule(w http.ResponseWriter, r *http.Request) if subscriptionName == "" { w.WriteHeader(http.StatusBadRequest) errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Topic name is null" - errorResponse.Message = "Topic name cannot be null" + errorResponse.Error = "Subscription name is null" + errorResponse.Message = "Subscription name cannot be null" json.NewEncoder(w).Encode(errorResponse) return } - // Subscription Name cannot be nil + // Rule Name cannot be nil if ruleName == "" { w.WriteHeader(http.StatusBadRequest) errorResponse.Code = http.StatusBadRequest @@ -512,23 +510,31 @@ func (c *Controller) GetSubscriptionRule(w http.ResponseWriter, r *http.Request) result, err := sbcli.GetSubscriptionRule(topicName, subscriptionName, ruleName) - // Body deserialization error - if err != nil { + if result == nil && strings.Contains(err.Error(), "was found") { w.WriteHeader(http.StatusNotFound) errorResponse.Code = http.StatusNotFound - errorResponse.Error = "Failed to GET Subscription Rule " + ruleName + errorResponse.Error = "Rule Not Found" + errorResponse.Message = "Rule with name " + ruleName + " was not found in subscription " + subscriptionName + " in topic " + topicName + " in " + sbcli.Namespace.Name + json.NewEncoder(w).Encode(errorResponse) + return + } + + if result == nil && err != nil { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Server Error" errorResponse.Message = err.Error() json.NewEncoder(w).Encode(errorResponse) return } - response := entities.RuleResponseEntity{} + response := entities.RuleResponse{} response.FromServiceBus(result) w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(response) } -// GetSubscriptionMessages Gets messages from a topic subscription +// CreateSubscriptionRule Creates a rule in a subscription func (c *Controller) CreateSubscriptionRule(w http.ResponseWriter, r *http.Request) { errorResponse := entities.ApiErrorResponse{} vars := mux.Vars(r) @@ -546,7 +552,7 @@ func (c *Controller) CreateSubscriptionRule(w http.ResponseWriter, r *http.Reque return } - ruleRequest := entities.RuleRequestEntity{} + ruleRequest := entities.RuleRequest{} err = json.Unmarshal(reqBody, &ruleRequest) // Body deserialization error @@ -573,34 +579,44 @@ func (c *Controller) CreateSubscriptionRule(w http.ResponseWriter, r *http.Reque if subscriptionName == "" { w.WriteHeader(http.StatusBadRequest) errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Topic name is null" - errorResponse.Message = "Topic name cannot be null" + errorResponse.Error = "Subscription name is null" + errorResponse.Message = "Subscription name cannot be null" json.NewEncoder(w).Encode(errorResponse) return } _, err = sbcli.GetSubscription(topicName, subscriptionName) - // Body deserialization error if err != nil { w.WriteHeader(http.StatusNotFound) errorResponse.Code = http.StatusNotFound - errorResponse.Error = "Failed to GET Subscription " + subscriptionName + errorResponse.Error = "Server Error" errorResponse.Message = err.Error() json.NewEncoder(w).Encode(errorResponse) return } - subscription := entities.SubscriptionRequestEntity{} + subscription := entities.SubscriptionRequest{} subscription.TopicName = topicName subscription.Name = subscriptionName + ruleExists, _ := sbcli.GetSubscriptionRule(topicName, subscriptionName, ruleRequest.Name) + if ruleExists != nil { + w.WriteHeader(http.StatusBadRequest) + found := entities.ApiErrorResponse{ + Code: http.StatusBadRequest, + Error: "Failed to CREATE Subscription Rule" + ruleRequest.Name, + Message: "The Rule " + ruleRequest.Name + " already exists in " + subscriptionName + " subscription, ignoring", + } + json.NewEncoder(w).Encode(found) + return + } + err = sbcli.CreateSubscriptionRule(subscription, ruleRequest) - // Body deserialization error if err != nil { - w.WriteHeader(http.StatusNotFound) - errorResponse.Code = http.StatusNotFound + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest errorResponse.Error = "Failed to CREATE Subscription Rule" + ruleRequest.Name errorResponse.Message = err.Error() json.NewEncoder(w).Encode(errorResponse) @@ -611,13 +627,13 @@ func (c *Controller) CreateSubscriptionRule(w http.ResponseWriter, r *http.Reque if err != nil { w.WriteHeader(http.StatusNotFound) errorResponse.Code = http.StatusNotFound - errorResponse.Error = "Failed to CREATE Subscription Rule" + ruleRequest.Name + errorResponse.Error = "Server Error" errorResponse.Message = err.Error() json.NewEncoder(w).Encode(errorResponse) return } - response := entities.RuleResponseEntity{} + response := entities.RuleResponse{} response.FromServiceBus(rule) w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(response) @@ -645,13 +661,13 @@ func (c *Controller) DeleteSubscriptionRule(w http.ResponseWriter, r *http.Reque if subscriptionName == "" { w.WriteHeader(http.StatusBadRequest) errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Topic name is null" - errorResponse.Message = "Topic name cannot be null" + errorResponse.Error = "Subscription name is null" + errorResponse.Message = "Subscription name cannot be null" json.NewEncoder(w).Encode(errorResponse) return } - // Subscription Name cannot be nil + // Rule Name cannot be nil if ruleName == "" { w.WriteHeader(http.StatusBadRequest) errorResponse.Code = http.StatusBadRequest @@ -663,8 +679,16 @@ func (c *Controller) DeleteSubscriptionRule(w http.ResponseWriter, r *http.Reque result, err := sbcli.DeleteSubscriptionRule(topicName, subscriptionName, ruleName) - // Body deserialization error - if err != nil { + if result == nil && strings.Contains(err.Error(), "No rule was found") { + w.WriteHeader(http.StatusNotFound) + errorResponse.Code = http.StatusNotFound + errorResponse.Error = "Rule Not Found" + errorResponse.Message = "Rule with name " + ruleName + " was not found in subscription " + subscriptionName + " in topic " + topicName + " in " + sbcli.Namespace.Name + json.NewEncoder(w).Encode(errorResponse) + return + } + + if result == nil && err != nil { w.WriteHeader(http.StatusNotFound) errorResponse.Code = http.StatusNotFound errorResponse.Error = "Failed to DELETE Subscription Rule " + ruleName @@ -673,7 +697,5 @@ func (c *Controller) DeleteSubscriptionRule(w http.ResponseWriter, r *http.Reque return } - response := entities.RuleResponseEntity{} - response.FromServiceBus(result) w.WriteHeader(http.StatusAccepted) } diff --git a/controller/topic.go b/controller/topic.go index c175018..faafe46 100644 --- a/controller/topic.go +++ b/controller/topic.go @@ -2,8 +2,11 @@ package controller import ( "encoding/json" + "fmt" "io/ioutil" "net/http" + "sync" + "time" servicebus "github.com/Azure/azure-service-bus-go" "github.com/cjlapao/servicebuscli-go/entities" @@ -129,7 +132,7 @@ func (c *Controller) CreateTopic(w http.ResponseWriter, r *http.Request) { return } - isValid, validError := topic.IsValidate() + isValid, validError := topic.IsValid() var sbTopic *servicebus.TopicEntity if !isValid { if validError != nil { @@ -180,7 +183,7 @@ func (c *Controller) CreateTopic(w http.ResponseWriter, r *http.Request) { func (c *Controller) SendTopicMessage(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - topicName := vars["name"] + topicName := vars["topicName"] reqBody, err := ioutil.ReadAll(r.Body) errorResponse := entities.ApiErrorResponse{} @@ -204,7 +207,7 @@ func (c *Controller) SendTopicMessage(w http.ResponseWriter, r *http.Request) { return } - message := entities.ServiceBusMessageRequest{} + message := entities.MessageRequest{} err = json.Unmarshal(reqBody, &message) // Body deserialization error @@ -247,3 +250,191 @@ func (c *Controller) SendTopicMessage(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusAccepted) json.NewEncoder(w).Encode(response) } + +func (c *Controller) SendBulkTopicMessage(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + topicName := vars["topicName"] + reqBody, err := ioutil.ReadAll(r.Body) + errorResponse := entities.ApiErrorResponse{} + + // Topic Name cannot be nil + if topicName == "" { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Topic name is null" + errorResponse.Message = "Topic name cannot be null" + json.NewEncoder(w).Encode(errorResponse) + return + } + + // Body cannot be nil error + if err != nil { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Empty Body" + errorResponse.Message = "The body of the request is null or empty" + json.NewEncoder(w).Encode(errorResponse) + return + } + + bulk := entities.BulkMessageRequest{} + err = json.Unmarshal(reqBody, &bulk) + + // Body deserialization error + if err != nil { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Failed Body Deserialization" + errorResponse.Message = "There was an error deserializing the body of the request" + json.NewEncoder(w).Encode(errorResponse) + return + } + + err = sbcli.SendBulkTopicMessage(topicName, bulk.Messages...) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Error Sending Topic Message" + errorResponse.Message = "There was an error sending bulk messages to topic " + topicName + json.NewEncoder(w).Encode(errorResponse) + return + } + + response := entities.ApiSuccessResponse{ + Message: "Sent " + fmt.Sprint(len(bulk.Messages)) + " Messages successfully to " + topicName + " topic", + } + + w.WriteHeader(http.StatusAccepted) + json.NewEncoder(w).Encode(response) +} + +func (c *Controller) SendBulkTemplateTopicMessage(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + topicName := vars["topicName"] + reqBody, err := ioutil.ReadAll(r.Body) + errorResponse := entities.ApiErrorResponse{} + maxSizeOfPayload := 262144 + + // Topic Name cannot be nil + if topicName == "" { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Topic name is null" + errorResponse.Message = "Topic name cannot be null" + json.NewEncoder(w).Encode(errorResponse) + return + } + + // Body cannot be nil error + if err != nil { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Empty Body" + errorResponse.Message = "The body of the request is null or empty" + json.NewEncoder(w).Encode(errorResponse) + return + } + + bulk := entities.BulkTemplateMessageRequest{} + err = json.Unmarshal(reqBody, &bulk) + + // Body deserialization error + if err != nil { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Failed Body Deserialization" + errorResponse.Message = "There was an error deserializing the body of the request" + json.NewEncoder(w).Encode(errorResponse) + return + } + + if bulk.BatchOf > bulk.TotalMessages { + bulk.BatchOf = 1 + } + + totalMessageSent := 0 + + messageTemplate, err := json.Marshal(bulk.Template) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = err.Error() + errorResponse.Message = "There was an error checking the templated message payload size" + json.NewEncoder(w).Encode(errorResponse) + return + } + messageTemplateSize := len(messageTemplate) + totalMessagePayloadSize := messageTemplateSize * bulk.TotalMessages + minimumBatchSize := totalMessagePayloadSize / maxSizeOfPayload + if minimumBatchSize > bulk.BatchOf { + bulk.BatchOf = minimumBatchSize + 5 + logger.Info("The total payload was too big for the given batch size, increasing it to the minimum of " + fmt.Sprint(bulk.BatchOf)) + } + + batchSize := bulk.TotalMessages / bulk.BatchOf + messages := make([]entities.MessageRequest, 0) + + for i := 0; i < batchSize; i++ { + messages = append(messages, bulk.Template) + } + + if bulk.WaitBetweenBatchesInMilli > 0 { + for i := 0; i < bulk.BatchOf; i++ { + if i > 0 && bulk.WaitBetweenBatchesInMilli > 0 { + logger.Info("Waiting " + fmt.Sprint(bulk.WaitBetweenBatchesInMilli) + "ms for next batch") + time.Sleep(time.Duration(bulk.WaitBetweenBatchesInMilli) * time.Millisecond) + } + + err = sbcli.SendBulkTopicMessage(topicName, messages...) + + if err != nil { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = err.Error() + errorResponse.Message = "There was an error sending bulk messages to topic " + topicName + json.NewEncoder(w).Encode(errorResponse) + return + } + totalMessageSent += len(messages) + } + } else { + logger.Info("Sending all batches without waiting") + var waitFor sync.WaitGroup + waitFor.Add(bulk.BatchOf) + for i := 0; i < bulk.BatchOf; i++ { + go sbcli.SendParallelBulkTopicMessage(&waitFor, topicName, messages...) + totalMessageSent += len(messages) + } + + waitFor.Wait() + logger.Success("Finished sending all the batches to service bus") + } + + if totalMessageSent < bulk.TotalMessages { + missingMessageCount := bulk.TotalMessages - totalMessageSent + logger.Info("Sending remaining " + fmt.Sprint(missingMessageCount) + " messages in the payload") + messages := make([]entities.MessageRequest, 0) + for x := 0; x < missingMessageCount; x++ { + messages = append(messages, bulk.Template) + } + + err = sbcli.SendBulkTopicMessage(topicName, messages...) + + if err != nil { + w.WriteHeader(http.StatusBadRequest) + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = err.Error() + errorResponse.Message = "There was an error sending bulk messages to topic " + topicName + json.NewEncoder(w).Encode(errorResponse) + return + } + bulk.BatchOf += 1 + } + + response := entities.ApiSuccessResponse{ + Message: "Sent " + fmt.Sprint(bulk.TotalMessages) + " Messages in " + fmt.Sprint(bulk.BatchOf) + " batches successfully to " + topicName + " topic", + } + + w.WriteHeader(http.StatusAccepted) + json.NewEncoder(w).Encode(response) +} diff --git a/duration/main.go b/duration/main.go deleted file mode 100644 index 20cce30..0000000 --- a/duration/main.go +++ /dev/null @@ -1,127 +0,0 @@ -// Package duration provides a partial implementation of ISO8601 durations. (no months) -package duration - -import ( - "bytes" - "errors" - "fmt" - "math" - "regexp" - "strconv" - "text/template" - "time" -) - -var ( - // ErrBadFormat is returned when parsing fails - ErrBadFormat = errors.New("bad format string") - - // ErrNoMonth is raised when a month is in the format string - ErrNoMonth = errors.New("no months allowed") - - tmpl = template.Must(template.New("duration").Parse(`P{{if .Years}}{{.Years}}Y{{end}}{{if .Weeks}}{{.Weeks}}W{{end}}{{if .Days}}{{.Days}}D{{end}}{{if .HasTimePart}}T{{end }}{{if .Hours}}{{.Hours}}H{{end}}{{if .Minutes}}{{.Minutes}}M{{end}}{{if .Seconds}}{{.Seconds}}S{{end}}`)) - - full = regexp.MustCompile(`P((?P\d+)Y)?((?P\d+)M)?((?P\d+)D)?(T((?P\d+)H)?((?P\d+)M)?((?P\d+(?:\.\d+))S)?)?`) - week = regexp.MustCompile(`P((?P\d+)W)`) -) - -type Duration struct { - Years int - Weeks int - Days int - Hours int - Minutes int - Seconds int - MilliSeconds int -} - -func FromString(dur string) (*Duration, error) { - var ( - match []string - re *regexp.Regexp - ) - - if week.MatchString(dur) { - match = week.FindStringSubmatch(dur) - re = week - } else if full.MatchString(dur) { - match = full.FindStringSubmatch(dur) - re = full - } else { - return nil, ErrBadFormat - } - - d := &Duration{} - - for i, name := range re.SubexpNames() { - part := match[i] - if i == 0 || name == "" || part == "" { - continue - } - - val, err := strconv.ParseFloat(part, 10) - if err != nil { - return nil, err - } - switch name { - case "year": - d.Years = int(val) - case "month": - return nil, ErrNoMonth - case "week": - d.Weeks = int(val) - case "day": - d.Days = int(val) - case "hour": - c := time.Duration(val) * time.Hour - d.Hours = int(c.Hours()) - case "minute": - c := time.Duration(val) * time.Minute - d.Minutes = int(c.Minutes()) - case "second": - s, milli := math.Modf(val) - d.Seconds = int(s) - d.MilliSeconds = int(milli * 1000) - default: - return nil, errors.New(fmt.Sprintf("unknown field %s", name)) - } - } - - return d, nil -} - -// String prints out the value passed in. It's not strictly according to the -// ISO spec, but it's pretty close. In particular, to completely conform it -// would need to round up to the next largest unit. 61 seconds to 1 minute 1 -// second, for example. It would also need to disallow weeks mingling with -// other units. -func (d *Duration) String() string { - var s bytes.Buffer - - err := tmpl.Execute(&s, d) - if err != nil { - panic(err) - } - - return s.String() -} - -func (d *Duration) HasTimePart() bool { - return d.Hours != 0 || d.Minutes != 0 || d.Seconds != 0 -} - -func (d *Duration) ToDuration() time.Duration { - day := time.Hour * 24 - year := day * 365 - - tot := time.Duration(0) - - tot += year * time.Duration(d.Years) - tot += day * 7 * time.Duration(d.Weeks) - tot += day * time.Duration(d.Days) - tot += time.Hour * time.Duration(d.Hours) - tot += time.Minute * time.Duration(d.Minutes) - tot += time.Second * time.Duration(d.Seconds) - - return tot -} diff --git a/entities/api-error-response.go b/entities/api-error-response.go deleted file mode 100644 index 23de02b..0000000 --- a/entities/api-error-response.go +++ /dev/null @@ -1,8 +0,0 @@ -package entities - -// LoginErrorResponse entity -type ApiErrorResponse struct { - Code int32 `json:"code"` - Error string `json:"error"` - Message string `json:"message"` -} diff --git a/entities/api-success-response.go b/entities/api-success-response.go deleted file mode 100644 index fdda6e5..0000000 --- a/entities/api-success-response.go +++ /dev/null @@ -1,8 +0,0 @@ -package entities - -// LoginErrorResponse entity -type ApiSuccessResponse struct { - Code string `json:"code,omitempty"` - Message string `json:"message"` - Data map[string]interface{} `json:"data,omitempty"` -} diff --git a/entities/apiErrorResponse.go b/entities/apiErrorResponse.go new file mode 100644 index 0000000..e369a99 --- /dev/null +++ b/entities/apiErrorResponse.go @@ -0,0 +1,22 @@ +package entities + +// LoginErrorResponse entity +type ApiErrorResponse struct { + Code int64 `json:"code,omitempty"` + Error string `json:"error"` + Message string `json:"message,omitempty"` +} + +// NewApiSuccessResponse Creates a new API Success Response struct +func NewApiErrorResponse(code int64, err string, message string) *ApiErrorResponse { + if err == "" { + err = "Server Error" + } + result := ApiErrorResponse{ + Code: code, + Error: err, + Message: message, + } + + return &result +} diff --git a/entities/apiSuccessResponse.go b/entities/apiSuccessResponse.go new file mode 100644 index 0000000..7aa318a --- /dev/null +++ b/entities/apiSuccessResponse.go @@ -0,0 +1,19 @@ +package entities + +// ApiSuccessResponse entity +type ApiSuccessResponse struct { + Code int64 `json:"code,omitempty"` + Message string `json:"message"` + Data map[string]interface{} `json:"data,omitempty"` +} + +// NewApiSuccessResponse Creates a new API Success Response struct +func NewApiSuccessResponse(code int64, message string, data map[string]interface{}) *ApiSuccessResponse { + result := ApiSuccessResponse{ + Code: code, + Message: message, + Data: data, + } + + return &result +} diff --git a/entities/bulk-message-request.go b/entities/bulk-message-request.go new file mode 100644 index 0000000..e61775f --- /dev/null +++ b/entities/bulk-message-request.go @@ -0,0 +1,12 @@ +package entities + +type BulkMessageRequest struct { + Messages []MessageRequest `json:"messages"` +} + +type BulkTemplateMessageRequest struct { + TotalMessages int `json:"totalMessages"` + Template MessageRequest `json:"template"` + BatchOf int `json:"batchOf"` + WaitBetweenBatchesInMilli int `json:"waitBetweenBatchesInMilli"` +} diff --git a/entities/bulk-message-response.go b/entities/bulk-message-response.go new file mode 100644 index 0000000..698bf8a --- /dev/null +++ b/entities/bulk-message-response.go @@ -0,0 +1,6 @@ +package entities + +type BulkMessageResponse struct { + SuccessCount int `json:"successCount"` + ErrorCount int `json:"errorCount"` +} diff --git a/entities/configRequest.go b/entities/configRequest.go new file mode 100644 index 0000000..4a7b570 --- /dev/null +++ b/entities/configRequest.go @@ -0,0 +1,6 @@ +package entities + +// Forward struct +type ConfigRequest struct { + ConnectionString string `json:"connectionString"` +} diff --git a/entities/count-details.go b/entities/count-details.go index 79c834a..7cdc6f9 100644 --- a/entities/count-details.go +++ b/entities/count-details.go @@ -2,7 +2,7 @@ package entities import servicebus "github.com/Azure/azure-service-bus-go" -type CountDetailsEntity struct { +type CountDetails struct { ActiveMessageCount *int32 `json:"activeMessageCount"` DeadLetterMessageCount *int32 `json:"deadLetterMessageCount"` ScheduledMessageCount *int32 `json:"scheduledMessageCount"` @@ -10,7 +10,7 @@ type CountDetailsEntity struct { TransferMessageCount *int32 `json:"transferMessageCount"` } -func (c *CountDetailsEntity) FromServiceBus(countDetails *servicebus.CountDetails) { +func (c *CountDetails) FromServiceBus(countDetails *servicebus.CountDetails) { if countDetails == nil { return } diff --git a/entities/forward-destination.go b/entities/forward-destination.go new file mode 100644 index 0000000..07ffdf3 --- /dev/null +++ b/entities/forward-destination.go @@ -0,0 +1,53 @@ +package entities + +import ( + "bytes" + "encoding/json" +) + +// ForwardDestination Enum +type ForwardDestination int + +// ForwardingDestination Enum definition +const ( + ForwardToTopic ForwardDestination = iota + ForwardToQueue +) + +// String Gets the ForwardingDestinationEntity Enum string representation +func (s ForwardDestination) String() string { + return forwardingDestinationToString[s] +} + +var forwardingDestinationToString = map[ForwardDestination]string{ + ForwardToTopic: "Topic", + ForwardToQueue: "Queue", +} + +var forwardingDestinationToID = map[string]ForwardDestination{ + "Topic": ForwardToTopic, + "topic": ForwardToTopic, + "Queue": ForwardToQueue, + "queue": ForwardToQueue, +} + +// MarshalJSON Custom Marsheller of ForwardingDestinationEntity Enum to JSON +func (s ForwardDestination) MarshalJSON() ([]byte, error) { + buffer := bytes.NewBufferString(`"`) + buffer.WriteString(forwardingDestinationToString[s]) + buffer.WriteString(`"`) + return buffer.Bytes(), nil +} + +// UnmarshalJSON Custom UnMarsheller of ForwardingDestinationEntity Enum to JSON +func (s *ForwardDestination) UnmarshalJSON(b []byte) error { + var j string + err := json.Unmarshal(b, &j) + if err != nil { + return err + } + + *s = forwardingDestinationToID[j] + + return nil +} diff --git a/entities/forward.go b/entities/forward.go new file mode 100644 index 0000000..3e1092a --- /dev/null +++ b/entities/forward.go @@ -0,0 +1,7 @@ +package entities + +// Forward struct +type Forward struct { + To string + In ForwardDestination +} diff --git a/entities/login-error-response.go b/entities/login-error-response.go deleted file mode 100644 index a4ad29d..0000000 --- a/entities/login-error-response.go +++ /dev/null @@ -1,8 +0,0 @@ -package entities - -// LoginErrorResponse entity -type LoginErrorResponse struct { - Code string `json:"code"` - Error string `json:"error"` - Message string `json:"message"` -} diff --git a/entities/login-request.go b/entities/login-request.go deleted file mode 100644 index 78d95cf..0000000 --- a/entities/login-request.go +++ /dev/null @@ -1,7 +0,0 @@ -package entities - -// LoginRequest entity -type LoginRequest struct { - Email string `json:"email" bson:"email"` - Password string `json:"password" bson:"password"` -} diff --git a/entities/login-response.go b/entities/login-response.go deleted file mode 100644 index 23bd21f..0000000 --- a/entities/login-response.go +++ /dev/null @@ -1,7 +0,0 @@ -package entities - -// LoginResponse entity -type LoginResponse struct { - AccessToken string `json:"access_token"` - Expiring string `json:"expiring"` -} diff --git a/entities/service-bus-message.go b/entities/message-request.go similarity index 64% rename from entities/service-bus-message.go rename to entities/message-request.go index 0c72363..a86900b 100644 --- a/entities/service-bus-message.go +++ b/entities/message-request.go @@ -2,11 +2,14 @@ package entities import ( "encoding/json" + "errors" + "io/ioutil" servicebus "github.com/Azure/azure-service-bus-go" + "github.com/cjlapao/common-go/helper" ) -type ServiceBusMessageRequest struct { +type MessageRequest struct { Label string `json:"label"` CorrelationID string `json:"correlationId"` ContentType string `json:"contentType"` @@ -14,7 +17,7 @@ type ServiceBusMessageRequest struct { UserProperties map[string]interface{} `json:"userProperties"` } -func (m *ServiceBusMessageRequest) ToServiceBus() (*servicebus.Message, error) { +func (m *MessageRequest) ToServiceBus() (*servicebus.Message, error) { messageData, err := json.MarshalIndent(m.Data, "", " ") if err != nil { return nil, err @@ -31,6 +34,8 @@ func (m *ServiceBusMessageRequest) ToServiceBus() (*servicebus.Message, error) { if m.ContentType == "" { sbMessage.ContentType = "application/json" + } else { + sbMessage.ContentType = m.ContentType } if m.CorrelationID != "" { @@ -40,7 +45,7 @@ func (m *ServiceBusMessageRequest) ToServiceBus() (*servicebus.Message, error) { return &sbMessage, nil } -func (m *ServiceBusMessageRequest) FromServiceBus(msg *servicebus.Message) error { +func (m *MessageRequest) FromServiceBus(msg *servicebus.Message) error { m.Data = map[string]interface{}{} err := json.Unmarshal(msg.Data, &m.Data) if err != nil { @@ -62,3 +67,23 @@ func (m *ServiceBusMessageRequest) FromServiceBus(msg *servicebus.Message) error return nil } + +func (m *MessageRequest) FromFile(filePath string) error { + fileExists := helper.FileExists(filePath) + + if !fileExists { + err := errors.New("file " + filePath + " was not found") + return err + } + + fileContent, err := ioutil.ReadFile(filePath) + if err != nil { + return err + } + err = json.Unmarshal(fileContent, m) + if err != nil { + return err + } + + return nil +} diff --git a/entities/message-response.go b/entities/message-response.go new file mode 100644 index 0000000..9063357 --- /dev/null +++ b/entities/message-response.go @@ -0,0 +1,41 @@ +package entities + +import ( + "encoding/json" + + servicebus "github.com/Azure/azure-service-bus-go" +) + +type MessageResponse struct { + ID string `json:"id"` + Label string `json:"label"` + CorrelationID string `json:"correlationId"` + ContentType string `json:"contentType"` + Data map[string]interface{} `json:"data"` + UserProperties map[string]interface{} `json:"userProperties"` +} + +func (m *MessageResponse) FromServiceBus(msg *servicebus.Message) error { + m.Data = map[string]interface{}{} + err := json.Unmarshal(msg.Data, &m.Data) + if err != nil { + return err + } + + m.ID = msg.ID + m.UserProperties = msg.UserProperties + + if msg.Label != "" { + m.Label = msg.Label + } + + if msg.ContentType != "" { + m.ContentType = msg.ContentType + } + + if msg.CorrelationID != "" { + m.CorrelationID = msg.CorrelationID + } + + return nil +} diff --git a/entities/queue-request-options.go b/entities/queue-request-options.go new file mode 100644 index 0000000..19f042d --- /dev/null +++ b/entities/queue-request-options.go @@ -0,0 +1,13 @@ +package entities + +type QueueRequestOptions struct { + AutoDeleteOnIdle *string `json:"autoDeleteOnIdle,omitempty"` + EnableDuplicateDetection *string `json:"enableDuplicateDetection,omitempty"` + MaxSizeInMegabytes *int `json:"maxSizeInMegabytes,omitempty"` + DefaultMessageTimeToLive *string `json:"defaultMessageTimeToLive,omitempty"` + LockDuration *string `json:"lockDuration,omitempty"` + SupportOrdering *bool `json:"supportOrdering,omitempty"` + EnablePartitioning *bool `json:"enablePartitioning,omitempty"` + RequireSession *bool `json:"requireSession,omitempty"` + DeadLetteringOnMessageExpiration *bool `json:"deadLetteringOnMessageExpiration,omitempty"` +} diff --git a/entities/queue-request.go b/entities/queue-request.go new file mode 100644 index 0000000..af3a466 --- /dev/null +++ b/entities/queue-request.go @@ -0,0 +1,173 @@ +package entities + +import ( + "encoding/json" + "errors" + "io/ioutil" + "net/http" + "strings" + "time" + + servicebus "github.com/Azure/azure-service-bus-go" + "github.com/cjlapao/common-go/helper" +) + +// QueueEntity structure +type QueueRequest struct { + Name string `json:"name"` + MaxDeliveryCount int32 `json:"maxDeliveryCount"` + Forward *Forward `json:"forward"` + ForwardDeadLetter *Forward `json:"forwardDeadLetter"` + Options *QueueRequestOptions `json:"options,omitempty"` +} + +// NewQueue Creates a Queue entity +func NewQueueRequest(name string) *QueueRequest { + result := QueueRequest{ + MaxDeliveryCount: 10, + } + + result.Name = name + result.Forward.In = ForwardToQueue + result.ForwardDeadLetter.In = ForwardToQueue + + return &result +} + +// MapMessageForwardFlag Maps a forward flag string into it's sub components +func (q *QueueRequest) MapMessageForwardFlag(value string) { + if value != "" { + forwardMapped := strings.Split(value, ":") + if len(forwardMapped) == 1 { + q.Forward.To = forwardMapped[0] + } else if len(forwardMapped) == 2 { + q.Forward.To = forwardMapped[1] + switch strings.ToLower(forwardMapped[0]) { + case "topic": + q.Forward.In = ForwardToTopic + case "queue": + q.Forward.In = ForwardToQueue + } + } + } +} + +// MapDeadLetterForwardFlag Maps a forward dead letter flag string into it's sub components +func (q *QueueRequest) MapDeadLetterForwardFlag(value string) { + if value != "" { + forwardMapped := strings.Split(value, ":") + if len(forwardMapped) == 1 { + q.ForwardDeadLetter.To = forwardMapped[0] + } else if len(forwardMapped) == 2 { + q.ForwardDeadLetter.To = forwardMapped[1] + switch strings.ToLower(forwardMapped[0]) { + case "topic": + q.ForwardDeadLetter.In = ForwardToTopic + case "queue": + q.ForwardDeadLetter.In = ForwardToQueue + } + } + } +} + +func (q *QueueRequest) GetOptions() (*[]servicebus.QueueManagementOption, *ApiErrorResponse) { + var opts []servicebus.QueueManagementOption + opts = make([]servicebus.QueueManagementOption, 0) + var errorResponse ApiErrorResponse + + if q.Options != nil { + if q.Options.AutoDeleteOnIdle != nil { + d, err := time.ParseDuration(*q.Options.AutoDeleteOnIdle) + if err != nil { + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Duration Parse Error" + errorResponse.Message = "There was an error processing the AutoDeleteOnIdle from string" + return nil, &errorResponse + } + opts = append(opts, servicebus.QueueEntityWithAutoDeleteOnIdle(&d)) + } + if q.Options.DeadLetteringOnMessageExpiration != nil && *q.Options.DeadLetteringOnMessageExpiration { + opts = append(opts, servicebus.QueueEntityWithDeadLetteringOnMessageExpiration()) + } + if q.Options.EnableDuplicateDetection != nil { + d, err := time.ParseDuration(*q.Options.AutoDeleteOnIdle) + if err != nil { + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Duration Parse Error" + errorResponse.Message = "There was an error processing the EnableDuplicateDetection from string" + return nil, &errorResponse + } + opts = append(opts, servicebus.QueueEntityWithDuplicateDetection(&d)) + } + if q.Options.LockDuration != nil { + d, err := time.ParseDuration(*q.Options.LockDuration) + if err != nil { + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Duration Parse Error" + errorResponse.Message = "There was an error processing the LockDuration from string" + return nil, &errorResponse + } + opts = append(opts, servicebus.QueueEntityWithLockDuration(&d)) + } + if q.Options.MaxSizeInMegabytes != nil { + opts = append(opts, servicebus.QueueEntityWithMaxSizeInMegabytes(*q.Options.MaxSizeInMegabytes)) + } + if q.Options.DefaultMessageTimeToLive != nil { + d, err := time.ParseDuration(*q.Options.DefaultMessageTimeToLive) + if err != nil { + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Duration Parse Error" + errorResponse.Message = "There was an error processing the DefaultMessageTimeToLive from string" + return nil, &errorResponse + } + opts = append(opts, servicebus.QueueEntityWithMessageTimeToLive(&d)) + } + if q.Options.RequireSession != nil && *q.Options.RequireSession { + opts = append(opts, servicebus.QueueEntityWithRequiredSessions()) + } + if q.Options.EnablePartitioning != nil && *q.Options.EnablePartitioning { + opts = append(opts, servicebus.QueueEntityWithPartitioning()) + } + } + + return &opts, nil +} + +func (q *QueueRequest) IsValid() (bool, *ApiErrorResponse) { + var errorResponse ApiErrorResponse + + if q.Name == "" { + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Queue name is null" + errorResponse.Message = "Queue name cannot be null" + return false, &errorResponse + } + + _, errResp := q.GetOptions() + + if errResp != nil { + return false, errResp + } + + return true, nil +} + +func (q *QueueRequest) FromFile(filePath string) error { + fileExists := helper.FileExists(filePath) + + if !fileExists { + err := errors.New("file " + filePath + " was not found") + return err + } + + fileContent, err := ioutil.ReadFile(filePath) + if err != nil { + return err + } + err = json.Unmarshal(fileContent, q) + if err != nil { + return err + } + + return nil +} diff --git a/entities/queue-response.go b/entities/queue-response.go new file mode 100644 index 0000000..b7255f9 --- /dev/null +++ b/entities/queue-response.go @@ -0,0 +1,71 @@ +package entities + +import ( + "time" + + servicebus "github.com/Azure/azure-service-bus-go" + "github.com/cjlapao/common-go/duration" +) + +// QueueResponse +type QueueResponse struct { + Name string `json:"name"` + ID string `json:"id"` + CountDetails CountDetails `json:"countDetails"` + LockDuration *duration.Duration `json:"lockDuration"` + MaxSizeInMegabytes *int32 `json:"maxSizeInMegabytes"` + RequiresDuplicateDetection *bool `json:"requiresDuplicateDetection"` + RequiresSession *bool `json:"requiresSession"` + DefaultMessageTimeToLive *duration.Duration `json:"defaultMessageTimeToLive"` + DeadLetteringOnMessageExpiration *bool `json:"deadLetteringOnMessageExpiration"` + DuplicateDetectionHistoryTimeWindow *duration.Duration `json:"duplicateDetectionHistoryTimeWindow"` + MaxDeliveryCount *int32 `json:"maxDeliveryCount"` + EnableBatchedOperations *bool `json:"enableBatchedOperations"` + SizeInBytes *int64 `json:"sizeInBytes"` + MessageCount *int64 `json:"messageCount"` + IsAnonymousAccessible *bool `json:"isAnonymousAccessible"` + Status string `json:"status"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + SupportOrdering *bool `json:"supportOrdering"` + AutoDeleteOnIdle *duration.Duration `json:"autoDeleteOnIdle"` + EnablePartitioning *bool `json:"enablePartitioning"` + EnableExpress *bool `json:"enableExpress"` + ForwardTo *string `json:"forwardTo"` + ForwardDeadLetteredMessagesTo *string `json:"forwardDeadLetteredMessagesTo"` +} + +func (q *QueueResponse) FromServiceBus(queue *servicebus.QueueEntity) { + if queue == nil { + return + } + + q.Name = queue.Name + q.ID = queue.ID + lockDuration, _ := duration.FromString(*queue.LockDuration) + defaultMessageTimeToLive, _ := duration.FromString(*queue.DefaultMessageTimeToLive) + duplicateDetectionHistoryTimeWindow, _ := duration.FromString(*queue.DuplicateDetectionHistoryTimeWindow) + autoDeleteOnIdle, _ := duration.FromString(*queue.AutoDeleteOnIdle) + q.LockDuration = lockDuration + q.DefaultMessageTimeToLive = defaultMessageTimeToLive + q.MaxSizeInMegabytes = queue.MaxSizeInMegabytes + q.RequiresDuplicateDetection = queue.RequiresDuplicateDetection + q.RequiresSession = queue.RequiresSession + q.DeadLetteringOnMessageExpiration = queue.DeadLetteringOnMessageExpiration + q.DuplicateDetectionHistoryTimeWindow = duplicateDetectionHistoryTimeWindow + q.MaxDeliveryCount = queue.MaxDeliveryCount + q.EnableBatchedOperations = queue.EnableBatchedOperations + q.SizeInBytes = queue.SizeInBytes + q.IsAnonymousAccessible = queue.IsAnonymousAccessible + q.Status = string(*queue.Status) + q.CreatedAt = queue.CreatedAt.Time + q.UpdatedAt = queue.UpdatedAt.Time + q.SupportOrdering = queue.SupportOrdering + q.AutoDeleteOnIdle = autoDeleteOnIdle + q.EnablePartitioning = queue.EnablePartitioning + q.EnableExpress = queue.EnableExpress + q.ForwardTo = queue.ForwardTo + q.ForwardDeadLetteredMessagesTo = queue.ForwardDeadLetteredMessagesTo + q.CountDetails = CountDetails{} + q.CountDetails.FromServiceBus(queue.CountDetails) +} diff --git a/entities/queue.go b/entities/queue.go deleted file mode 100644 index 2a8008f..0000000 --- a/entities/queue.go +++ /dev/null @@ -1,225 +0,0 @@ -package entities - -import ( - "fmt" - "net/http" - "strings" - "time" - - servicebus "github.com/Azure/azure-service-bus-go" - "github.com/cjlapao/servicebuscli-go/duration" -) - -// QueueResponseEntity -type QueueResponseEntity struct { - Name string `json:"name"` - ID string `json:"id"` - CountDetails CountDetailsEntity `json:"countDetails"` - LockDuration *duration.Duration `json:"lockDuration"` - MaxSizeInMegabytes *int32 `json:"maxSizeInMegabytes"` - RequiresDuplicateDetection *bool `json:"requiresDuplicateDetection"` - RequiresSession *bool `json:"requiresSession"` - DefaultMessageTimeToLive *duration.Duration `json:"defaultMessageTimeToLive"` - DeadLetteringOnMessageExpiration *bool `json:"deadLetteringOnMessageExpiration"` - DuplicateDetectionHistoryTimeWindow *duration.Duration `json:"duplicateDetectionHistoryTimeWindow"` - MaxDeliveryCount *int32 `json:"maxDeliveryCount"` - EnableBatchedOperations *bool `json:"enableBatchedOperations"` - SizeInBytes *int64 `json:"sizeInBytes"` - MessageCount *int64 `json:"messageCount"` - IsAnonymousAccessible *bool `json:"isAnonymousAccessible"` - Status string `json:"status"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - SupportOrdering *bool `json:"supportOrdering"` - AutoDeleteOnIdle *duration.Duration `json:"autoDeleteOnIdle"` - EnablePartitioning *bool `json:"enablePartitioning"` - EnableExpress *bool `json:"enableExpress"` - ForwardTo *string `json:"forwardTo"` - ForwardDeadLetteredMessagesTo *string `json:"forwardDeadLetteredMessagesTo"` -} - -func (q *QueueResponseEntity) FromServiceBus(queue *servicebus.QueueEntity) { - if queue == nil { - return - } - - fmt.Println(*queue.AutoDeleteOnIdle) - lockDuration, _ := duration.FromString(*queue.LockDuration) - defaultMessageTimeToLive, _ := duration.FromString(*queue.DefaultMessageTimeToLive) - duplicateDetectionHistoryTimeWindow, _ := duration.FromString(*queue.DuplicateDetectionHistoryTimeWindow) - autoDeleteOnIdle, _ := duration.FromString(*queue.AutoDeleteOnIdle) - q.LockDuration = lockDuration - q.DefaultMessageTimeToLive = defaultMessageTimeToLive - q.MaxSizeInMegabytes = queue.MaxSizeInMegabytes - q.RequiresDuplicateDetection = queue.RequiresDuplicateDetection - q.RequiresSession = queue.RequiresSession - q.DeadLetteringOnMessageExpiration = queue.DeadLetteringOnMessageExpiration - q.DuplicateDetectionHistoryTimeWindow = duplicateDetectionHistoryTimeWindow - q.MaxDeliveryCount = queue.MaxDeliveryCount - q.EnableBatchedOperations = queue.EnableBatchedOperations - q.SizeInBytes = queue.SizeInBytes - q.IsAnonymousAccessible = queue.IsAnonymousAccessible - q.Status = string(*queue.Status) - q.CreatedAt = queue.CreatedAt.Time - q.UpdatedAt = queue.UpdatedAt.Time - q.SupportOrdering = queue.SupportOrdering - q.AutoDeleteOnIdle = autoDeleteOnIdle - q.EnablePartitioning = queue.EnablePartitioning - q.EnableExpress = queue.EnableExpress - q.ForwardTo = queue.ForwardTo - q.ForwardDeadLetteredMessagesTo = queue.ForwardDeadLetteredMessagesTo - q.CountDetails = CountDetailsEntity{} - q.CountDetails.FromServiceBus(queue.CountDetails) -} - -// QueueEntity structure -type QueueRequestEntity struct { - Name string `json:"name"` - MaxDeliveryCount int32 `json:"maxDeliveryCount"` - Forward *ForwardEntity `json:"forward"` - ForwardDeadLetter *ForwardEntity `json:"forwardDeadLetter"` - Options *QueueRequestOptions `json:"options,omitempty"` -} - -// NewQueue Creates a Queue entity -func NewQueueRequest(name string) *QueueRequestEntity { - result := QueueRequestEntity{ - MaxDeliveryCount: 10, - } - - result.Name = name - result.Forward.In = ForwardToQueue - result.ForwardDeadLetter.In = ForwardToQueue - - return &result -} - -// MapMessageForwardFlag Maps a forward flag string into it's sub components -func (s *QueueRequestEntity) MapMessageForwardFlag(value string) { - if value != "" { - forwardMapped := strings.Split(value, ":") - if len(forwardMapped) == 1 { - s.Forward.To = forwardMapped[0] - } else if len(forwardMapped) == 2 { - s.Forward.To = forwardMapped[1] - switch strings.ToLower(forwardMapped[0]) { - case "topic": - s.Forward.In = ForwardToTopic - case "queue": - s.Forward.In = ForwardToQueue - } - } - } -} - -// MapDeadLetterForwardFlag Maps a forward dead letter flag string into it's sub components -func (s *QueueRequestEntity) MapDeadLetterForwardFlag(value string) { - if value != "" { - forwardMapped := strings.Split(value, ":") - if len(forwardMapped) == 1 { - s.ForwardDeadLetter.To = forwardMapped[0] - } else if len(forwardMapped) == 2 { - s.ForwardDeadLetter.To = forwardMapped[1] - switch strings.ToLower(forwardMapped[0]) { - case "topic": - s.ForwardDeadLetter.In = ForwardToTopic - case "queue": - s.ForwardDeadLetter.In = ForwardToQueue - } - } - } -} - -func (qr *QueueRequestEntity) GetOptions() (*[]servicebus.QueueManagementOption, *ApiErrorResponse) { - var opts []servicebus.QueueManagementOption - opts = make([]servicebus.QueueManagementOption, 0) - var errorResponse ApiErrorResponse - - if qr.Options != nil { - if qr.Options.AutoDeleteOnIdle != nil { - d, err := time.ParseDuration(*qr.Options.AutoDeleteOnIdle) - if err != nil { - errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Duration Parse Error" - errorResponse.Message = "There was an error processing the AutoDeleteOnIdle from string" - return nil, &errorResponse - } - opts = append(opts, servicebus.QueueEntityWithAutoDeleteOnIdle(&d)) - } - if qr.Options.DeadLetteringOnMessageExpiration != nil && *qr.Options.DeadLetteringOnMessageExpiration { - opts = append(opts, servicebus.QueueEntityWithDeadLetteringOnMessageExpiration()) - } - if qr.Options.EnableDuplicateDetection != nil { - d, err := time.ParseDuration(*qr.Options.AutoDeleteOnIdle) - if err != nil { - errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Duration Parse Error" - errorResponse.Message = "There was an error processing the EnableDuplicateDetection from string" - return nil, &errorResponse - } - opts = append(opts, servicebus.QueueEntityWithDuplicateDetection(&d)) - } - if qr.Options.LockDuration != nil { - d, err := time.ParseDuration(*qr.Options.AutoDeleteOnIdle) - if err != nil { - errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Duration Parse Error" - errorResponse.Message = "There was an error processing the LockDuration from string" - return nil, &errorResponse - } - opts = append(opts, servicebus.QueueEntityWithLockDuration(&d)) - } - if qr.Options.MaxSizeInMegabytes != nil { - opts = append(opts, servicebus.QueueEntityWithMaxSizeInMegabytes(*qr.Options.MaxSizeInMegabytes)) - } - if qr.Options.DefaultMessageTimeToLive != nil { - d, err := time.ParseDuration(*qr.Options.DefaultMessageTimeToLive) - if err != nil { - errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Duration Parse Error" - errorResponse.Message = "There was an error processing the DefaultMessageTimeToLive from string" - return nil, &errorResponse - } - opts = append(opts, servicebus.QueueEntityWithMessageTimeToLive(&d)) - } - if qr.Options.RequireSession != nil && *qr.Options.RequireSession { - opts = append(opts, servicebus.QueueEntityWithRequiredSessions()) - } - if qr.Options.EnablePartitioning != nil && *qr.Options.EnablePartitioning { - opts = append(opts, servicebus.QueueEntityWithPartitioning()) - } - } - - return &opts, nil -} - -func (qr *QueueRequestEntity) IsValid() (bool, *ApiErrorResponse) { - var errorResponse ApiErrorResponse - - if qr.Name == "" { - errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Queue name is null" - errorResponse.Message = "Queue name cannot be null" - return false, &errorResponse - } - - _, errResp := qr.GetOptions() - - if errResp != nil { - return false, errResp - } - - return true, nil -} - -type QueueRequestOptions struct { - AutoDeleteOnIdle *string `json:"autoDeleteOnIdle,omitempty"` - EnableDuplicateDetection *string `json:"enableDuplicateDetection,omitempty"` - MaxSizeInMegabytes *int `json:"maxSizeInMegabytes,omitempty"` - DefaultMessageTimeToLive *string `json:"defaultMessageTimeToLive,omitempty"` - LockDuration *string `json:"lockDuration,omitempty"` - SupportOrdering *bool `json:"supportOrdering,omitempty"` - EnablePartitioning *bool `json:"enablePartitioning,omitempty"` - RequireSession *bool `json:"requireSession,omitempty"` - DeadLetteringOnMessageExpiration *bool `json:"deadLetteringOnMessageExpiration,omitempty"` -} diff --git a/entities/rule-request.go b/entities/rule-request.go new file mode 100644 index 0000000..b9a734e --- /dev/null +++ b/entities/rule-request.go @@ -0,0 +1,50 @@ +package entities + +import ( + "encoding/json" + "errors" + "io/ioutil" + "net/http" + + "github.com/cjlapao/common-go/helper" +) + +// RuleRequest struct +type RuleRequest struct { + Name string `json:"name"` + SQLFilter string `json:"sqlFilter"` + SQLAction string `json:"sqlAction"` +} + +func (r *RuleRequest) IsValid() (bool, *ApiErrorResponse) { + var errorResponse ApiErrorResponse + + if r.Name == "" { + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Queue name is null" + errorResponse.Message = "Queue name cannot be null" + return false, &errorResponse + } + + return true, nil +} + +func (r *RuleRequest) FromFile(filePath string) error { + fileExists := helper.FileExists(filePath) + + if !fileExists { + err := errors.New("file " + filePath + " was not found") + return err + } + + fileContent, err := ioutil.ReadFile(filePath) + if err != nil { + return err + } + err = json.Unmarshal(fileContent, r) + if err != nil { + return err + } + + return nil +} diff --git a/entities/rule-response-action.go b/entities/rule-response-action.go new file mode 100644 index 0000000..57a10bb --- /dev/null +++ b/entities/rule-response-action.go @@ -0,0 +1,27 @@ +package entities + +import ( + "errors" + + servicebus "github.com/Azure/azure-service-bus-go" +) + +type RuleResponseAction struct { + Type string `json:"type"` + RequiresPreprocessing bool `json:"requiresPreprocessing"` + SQLExpression string `json:"sqlExpression"` + CompatibilityLevel int `json:"compatibilityLevel"` +} + +func (e *RuleResponseAction) FromServiceBus(action *servicebus.ActionDescription) error { + if action == nil { + err := errors.New("entity cannot be null") + return err + } + + e.Type = action.Type + e.SQLExpression = action.SQLExpression + e.CompatibilityLevel = action.CompatibilityLevel + + return nil +} diff --git a/entities/rule-response-filter.go b/entities/rule-response-filter.go new file mode 100644 index 0000000..f784da3 --- /dev/null +++ b/entities/rule-response-filter.go @@ -0,0 +1,35 @@ +package entities + +import servicebus "github.com/Azure/azure-service-bus-go" + +type RuleResponseFilter struct { + CorrelationID *string `json:"correlationID"` + MessageID *string `json:"messageID"` + To *string `json:"to"` + ReplyTo *string `json:"replyTo"` + Label *string `json:"label"` + SessionID *string `json:"sessionID"` + ReplyToSessionID *string `json:"replyToSessionID"` + ContentType *string `json:"contentType"` + Properties map[string]interface{} `json:"properties"` + Type string `json:"type"` + SQLExpression *string `json:"sqlExpression"` + CompatibilityLevel int `json:"compatibilityLevel"` +} + +func (c *RuleResponseFilter) FromServiceBus(filter servicebus.FilterDescription) error { + c.CorrelationID = filter.CorrelationID + c.MessageID = filter.MessageID + c.To = filter.To + c.ReplyTo = filter.ReplyTo + c.Label = filter.Label + c.SessionID = filter.SessionID + c.ReplyToSessionID = filter.ReplyToSessionID + c.ContentType = filter.ContentType + c.Properties = filter.Properties + c.Type = filter.Type + c.SQLExpression = filter.SQLExpression + c.CompatibilityLevel = filter.CompatibilityLevel + + return nil +} diff --git a/entities/rule-response.go b/entities/rule-response.go new file mode 100644 index 0000000..2b9923d --- /dev/null +++ b/entities/rule-response.go @@ -0,0 +1,31 @@ +package entities + +import ( + "errors" + + servicebus "github.com/Azure/azure-service-bus-go" +) + +type RuleResponse struct { + Name string `json:"name"` + ID string `json:"id"` + Filter RuleResponseFilter `json:"filter"` + Action RuleResponseAction `json:"action"` +} + +func (r *RuleResponse) FromServiceBus(msg *servicebus.RuleEntity) error { + if msg == nil { + err := errors.New("entity cannot be null") + return err + } + + r.ID = msg.ID + r.Name = msg.Name + r.Filter = RuleResponseFilter{} + r.Action = RuleResponseAction{} + + r.Filter.FromServiceBus(msg.Filter) + r.Action.FromServiceBus(msg.Action) + + return nil +} diff --git a/entities/rule.go b/entities/rule.go deleted file mode 100644 index 4ebd21e..0000000 --- a/entities/rule.go +++ /dev/null @@ -1,142 +0,0 @@ -package entities - -import ( - "bytes" - "encoding/json" - "errors" - - servicebus "github.com/Azure/azure-service-bus-go" -) - -// RuleRequestEntity struct -type RuleRequestEntity struct { - Name string `json:"name"` - SQLFilter string `json:"sqlFilter"` - SQLAction string `json:"sqlAction"` -} - -// ForwardEntity struct -type ForwardEntity struct { - To string - In ForwardingDestinationEntity -} - -// ForwardingDestinationEntity Enum -type ForwardingDestinationEntity int - -// ForwardingDestination Enum definition -const ( - ForwardToTopic ForwardingDestinationEntity = iota - ForwardToQueue -) - -func (s ForwardingDestinationEntity) String() string { - return forwardingDestinationToString[s] -} - -var forwardingDestinationToString = map[ForwardingDestinationEntity]string{ - ForwardToTopic: "Topic", - ForwardToQueue: "Queue", -} - -var forwardingDestinationToID = map[string]ForwardingDestinationEntity{ - "Topic": ForwardToTopic, - "topic": ForwardToTopic, - "Queue": ForwardToQueue, - "queue": ForwardToQueue, -} - -func (s ForwardingDestinationEntity) MarshalJSON() ([]byte, error) { - buffer := bytes.NewBufferString(`"`) - buffer.WriteString(forwardingDestinationToString[s]) - buffer.WriteString(`"`) - return buffer.Bytes(), nil -} - -func (s *ForwardingDestinationEntity) UnmarshalJSON(b []byte) error { - var j string - err := json.Unmarshal(b, &j) - if err != nil { - return err - } - - *s = forwardingDestinationToID[j] - - return nil -} - -type RuleResponseEntity struct { - Name string `json:"name"` - ID string `json:"id"` - Filter RuleResponseFilterEntity `json:"filter"` - Action RuleResponseActionEntity `json:"action"` -} - -func (c *RuleResponseEntity) FromServiceBus(msg *servicebus.RuleEntity) error { - if msg == nil { - err := errors.New("entity cannot be null") - return err - } - - c.ID = msg.ID - c.Name = msg.Name - c.Filter = RuleResponseFilterEntity{} - c.Action = RuleResponseActionEntity{} - - c.Filter.FromServiceBus(msg.Filter) - c.Action.FromServiceBus(msg.Action) - - return nil -} - -type RuleResponseFilterEntity struct { - CorrelationID *string `json:"correlationID"` - MessageID *string `json:"messageID"` - To *string `json:"to"` - ReplyTo *string `json:"replyTo"` - Label *string `json:"label"` - SessionID *string `json:"sessionID"` - ReplyToSessionID *string `json:"replyToSessionID"` - ContentType *string `json:"contentType"` - Properties map[string]interface{} `json:"properties"` - Type string `json:"type"` - SQLExpression *string `json:"sqlExpression"` - CompatibilityLevel int `json:"compatibilityLevel"` -} - -func (c *RuleResponseFilterEntity) FromServiceBus(filter servicebus.FilterDescription) error { - c.CorrelationID = filter.CorrelationID - c.MessageID = filter.MessageID - c.To = filter.To - c.ReplyTo = filter.ReplyTo - c.Label = filter.Label - c.SessionID = filter.SessionID - c.ReplyToSessionID = filter.ReplyToSessionID - c.ContentType = filter.ContentType - c.Properties = filter.Properties - c.Type = filter.Type - c.SQLExpression = filter.SQLExpression - c.CompatibilityLevel = filter.CompatibilityLevel - - return nil -} - -type RuleResponseActionEntity struct { - Type string `json:"type"` - RequiresPreprocessing bool `json:"requiresPreprocessing"` - SQLExpression string `json:"sqlExpression"` - CompatibilityLevel int `json:"compatibilityLevel"` -} - -func (c *RuleResponseActionEntity) FromServiceBus(action *servicebus.ActionDescription) error { - if action == nil { - err := errors.New("entity cannot be null") - return err - } - - c.Type = action.Type - c.SQLExpression = action.SQLExpression - c.CompatibilityLevel = action.CompatibilityLevel - - return nil -} diff --git a/entities/subscription-request-options.go b/entities/subscription-request-options.go new file mode 100644 index 0000000..c63adbb --- /dev/null +++ b/entities/subscription-request-options.go @@ -0,0 +1,11 @@ +package entities + +// SubscriptionRequestOptions Entity +type SubscriptionRequestOptions struct { + AutoDeleteOnIdle *string `json:"autoDeleteOnIdle,omitempty"` + DefaultMessageTimeToLive *string `json:"defaultMessageTimeToLive,omitempty"` + LockDuration *string `json:"lockDuration,omitempty"` + EnableBatchedOperation *bool `json:"enableBatchedOperation,omitempty"` + DeadLetteringOnMessageExpiration *bool `json:"deadLetteringOnMessageExpiration,omitempty"` + RequireSession *bool `json:"requireSession,omitempty"` +} diff --git a/entities/subscription-request.go b/entities/subscription-request.go new file mode 100644 index 0000000..2eecf5b --- /dev/null +++ b/entities/subscription-request.go @@ -0,0 +1,235 @@ +package entities + +import ( + "encoding/json" + "errors" + "io/ioutil" + "net/http" + "strings" + "time" + + servicebus "github.com/Azure/azure-service-bus-go" + "github.com/cjlapao/common-go/helper" +) + +type SubscriptionRequest struct { + Name string `json:"name"` + TopicName string `json:"topicName"` + UserDescription string `json:"userDescription"` + MaxDeliveryCount int32 `json:"maxDeliveryCount,omitempty"` + Forward *Forward `json:"forward,omitempty"` + ForwardDeadLetter *Forward `json:"forwardDeadLetter,omitempty"` + Rules []*RuleRequest `json:"rules,omitempty"` + Options *SubscriptionRequestOptions `json:"options,omitempty"` +} + +// NewSubscriptionRequest Creates a new subscription entity +func NewSubscriptionRequest(topicName string, name string) *SubscriptionRequest { + result := SubscriptionRequest{ + Name: name, + TopicName: topicName, + MaxDeliveryCount: 10, + } + + result.Rules = make([]*RuleRequest, 0) + result.Forward = &Forward{} + result.Forward.In = ForwardToTopic + result.ForwardDeadLetter = &Forward{} + result.Options = &SubscriptionRequestOptions{} + + return &result +} + +// AddSQLFilter Adds a Sql filter to a specific Rule +func (s *SubscriptionRequest) AddSQLFilter(ruleName string, filter string) { + var rule RuleRequest + ruleFound := false + + for i := range s.Rules { + if s.Rules[i].Name == ruleName { + ruleFound = true + if len(s.Rules[i].SQLFilter) > 0 { + s.Rules[i].SQLFilter += " " + } + s.Rules[i].SQLFilter += filter + break + } + } + + if !ruleFound { + rule = RuleRequest{ + Name: ruleName, + SQLFilter: filter, + } + s.Rules = append(s.Rules, &rule) + } +} + +// AddSQLAction Adds a Sql Action to a specific rule +func (s *SubscriptionRequest) AddSQLAction(ruleName string, action string) { + var rule RuleRequest + ruleFound := false + + for i := range s.Rules { + if s.Rules[i].Name == ruleName { + ruleFound = true + if len(s.Rules[i].SQLAction) > 0 { + s.Rules[i].SQLAction += " " + } + s.Rules[i].SQLAction += action + break + } + } + + if !ruleFound { + rule = RuleRequest{ + Name: ruleName, + SQLAction: action, + } + s.Rules = append(s.Rules, &rule) + } +} + +// MapMessageForwardFlag Maps a forward flag string into it's sub components +func (s *SubscriptionRequest) MapMessageForwardFlag(value string) { + if value != "" { + forwardMapped := strings.Split(value, ":") + if len(forwardMapped) == 1 { + s.Forward.To = forwardMapped[0] + } else if len(forwardMapped) == 2 { + s.Forward.To = forwardMapped[1] + switch strings.ToLower(forwardMapped[0]) { + case "topic": + s.Forward.In = ForwardToTopic + case "queue": + s.Forward.In = ForwardToQueue + } + } + } +} + +// MapDeadLetterForwardFlag Maps a forward dead letter flag string into it's sub components +func (s *SubscriptionRequest) MapDeadLetterForwardFlag(value string) { + if value != "" { + forwardMapped := strings.Split(value, ":") + if len(forwardMapped) == 1 { + s.ForwardDeadLetter.To = forwardMapped[0] + } else if len(forwardMapped) == 2 { + s.ForwardDeadLetter.To = forwardMapped[1] + switch strings.ToLower(forwardMapped[0]) { + case "topic": + s.ForwardDeadLetter.In = ForwardToTopic + case "queue": + s.ForwardDeadLetter.In = ForwardToQueue + } + } + } +} + +// MapRuleFlag Maps a rule flag string into it's sub components +func (s *SubscriptionRequest) MapRuleFlag(value string) { + if value != "" { + ruleMapped := strings.Split(value, ":") + if len(ruleMapped) > 1 { + s.AddSQLFilter(ruleMapped[0], ruleMapped[1]) + if len(ruleMapped) == 3 { + s.AddSQLAction(ruleMapped[0], ruleMapped[2]) + } + } + } +} + +func (s *SubscriptionRequest) GetOptions() (*[]servicebus.SubscriptionManagementOption, *ApiErrorResponse) { + var opts []servicebus.SubscriptionManagementOption + opts = make([]servicebus.SubscriptionManagementOption, 0) + var errorResponse ApiErrorResponse + if s.Options != nil { + if s.Options.AutoDeleteOnIdle != nil { + d, err := time.ParseDuration(*s.Options.AutoDeleteOnIdle) + if err != nil { + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Duration Parse Error" + errorResponse.Message = "There was an error processing the AutoDeleteOnIdle from string" + return nil, &errorResponse + } + opts = append(opts, servicebus.SubscriptionWithAutoDeleteOnIdle(&d)) + } + if s.Options.EnableBatchedOperation != nil && *s.Options.EnableBatchedOperation { + opts = append(opts, servicebus.SubscriptionWithBatchedOperations()) + } + if s.Options.DeadLetteringOnMessageExpiration != nil && *s.Options.DeadLetteringOnMessageExpiration { + opts = append(opts, servicebus.SubscriptionWithDeadLetteringOnMessageExpiration()) + } + if s.Options.RequireSession != nil && *s.Options.RequireSession { + opts = append(opts, servicebus.SubscriptionWithRequiredSessions()) + } + if s.Options.DefaultMessageTimeToLive != nil { + d, err := time.ParseDuration(*s.Options.DefaultMessageTimeToLive) + if err != nil { + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Duration Parse Error" + errorResponse.Message = "There was an error processing the DefaultMessageTimeToLive from string" + return nil, &errorResponse + } + opts = append(opts, servicebus.SubscriptionWithMessageTimeToLive(&d)) + } + if s.Options.LockDuration != nil { + d, err := time.ParseDuration(*s.Options.LockDuration) + if err != nil { + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Duration Parse Error" + errorResponse.Message = "There was an error processing the LockDuration from string" + return nil, &errorResponse + } + opts = append(opts, servicebus.SubscriptionWithLockDuration(&d)) + } + } + + return &opts, nil +} + +func (s *SubscriptionRequest) IsValid() (bool, *ApiErrorResponse) { + var errorResponse ApiErrorResponse + + if s.Name == "" { + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Subscription name is null" + errorResponse.Message = "Subscription Name cannot be null" + return false, &errorResponse + } + + if s.TopicName == "" { + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Topic Name is null" + errorResponse.Message = "Topic Name cannot be null" + return false, &errorResponse + } + + _, errResp := s.GetOptions() + + if errResp != nil { + return false, errResp + } + + return true, nil +} + +func (s *SubscriptionRequest) FromFile(filePath string) error { + fileExists := helper.FileExists(filePath) + + if !fileExists { + err := errors.New("file " + filePath + " was not found") + return err + } + + fileContent, err := ioutil.ReadFile(filePath) + if err != nil { + return err + } + err = json.Unmarshal(fileContent, s) + if err != nil { + return err + } + + return nil +} diff --git a/entities/subscription-response.go b/entities/subscription-response.go new file mode 100644 index 0000000..fa86525 --- /dev/null +++ b/entities/subscription-response.go @@ -0,0 +1,61 @@ +package entities + +import ( + "time" + + azservicebus "github.com/Azure/azure-service-bus-go" + "github.com/cjlapao/common-go/duration" +) + +type SubscriptionResponse struct { + Name string `json:"name"` + ID string `json:"url"` + CountDetails CountDetails `json:"countDetails"` + LockDuration duration.Duration `json:"lockDuration"` + RequiresSession *bool `json:"requiresSession"` + DefaultMessageTimeToLive duration.Duration `json:"defaultMessageTimeToLive"` + AutoDeleteOnIdle duration.Duration `json:"autoDeleteOnIdle"` + DeadLetteringOnMessageExpiration *bool `json:"deadLetteringOnMessageExpiration"` + DeadLetteringOnFilterEvaluationExceptions *bool `json:"deadLetteringOnFilterEvaluationExceptions"` + MessageCount *int64 `json:"messageCount"` + MaxDeliveryCount int64 `json:"maxDeliveryCount"` + EnableBatchedOperations *bool `json:"enableBatchedOperations"` + Status string `json:"status"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + AccessedAt time.Time `json:"accessedAt"` + ForwardTo *string `json:"forwardTo"` + ForwardDeadLetteredMessagesTo *string `json:"forwardDeadLetteredMessagesTo"` +} + +func (e *SubscriptionResponse) FromServiceBus(subscription *azservicebus.SubscriptionEntity) { + lockDuration, _ := duration.FromString(*subscription.LockDuration) + defaultMessageTimeToLive, _ := duration.FromString(*subscription.DefaultMessageTimeToLive) + autoDeleteOnIdle, _ := duration.FromString(*subscription.AutoDeleteOnIdle) + + e.LockDuration = *lockDuration + e.RequiresSession = subscription.RequiresSession + e.AutoDeleteOnIdle = *autoDeleteOnIdle + e.DefaultMessageTimeToLive = *defaultMessageTimeToLive + e.DeadLetteringOnMessageExpiration = subscription.DeadLetteringOnMessageExpiration + e.DeadLetteringOnFilterEvaluationExceptions = subscription.DeadLetteringOnFilterEvaluationExceptions + e.MessageCount = subscription.MessageCount + e.MaxDeliveryCount = int64(*subscription.MaxDeliveryCount) + e.EnableBatchedOperations = subscription.EnableBatchedOperations + e.Status = string(*subscription.Status) + e.CreatedAt = subscription.CreatedAt.Time + e.UpdatedAt = subscription.UpdatedAt.Time + e.AccessedAt = subscription.AccessedAt.Time + e.ForwardTo = subscription.ForwardTo + e.ForwardDeadLetteredMessagesTo = subscription.ForwardDeadLetteredMessagesTo + e.Name = subscription.Name + e.ID = subscription.ID + + e.CountDetails = CountDetails{ + ActiveMessageCount: subscription.CountDetails.ActiveMessageCount, + DeadLetterMessageCount: subscription.CountDetails.DeadLetterMessageCount, + ScheduledMessageCount: subscription.CountDetails.ScheduledMessageCount, + TransferDeadLetterMessageCount: subscription.CountDetails.TransferDeadLetterMessageCount, + TransferMessageCount: subscription.CountDetails.TransferMessageCount, + } +} diff --git a/entities/subscription.go b/entities/subscription.go deleted file mode 100644 index 0cec3e4..0000000 --- a/entities/subscription.go +++ /dev/null @@ -1,262 +0,0 @@ -package entities - -import ( - "net/http" - "strings" - "time" - - azservicebus "github.com/Azure/azure-service-bus-go" - servicebus "github.com/Azure/azure-service-bus-go" -) - -type SubscriptionResponseEntity struct { - Name string `json:"name"` - ID string `json:"url"` - CountDetails CountDetailsEntity `json:"countDetails"` - LockDuration *string `json:"lockDuration"` - RequiresSession *bool `json:"requiresSession"` - DefaultMessageTimeToLive *string `json:"defaultMessageTimeToLive"` - DeadLetteringOnMessageExpiration *bool `json:"deadLetteringOnMessageExpiration"` - DeadLetteringOnFilterEvaluationExceptions *bool `json:"deadLetteringOnFilterEvaluationExceptions"` - MessageCount *int64 `json:"messageCount"` - MaxDeliveryCount *int32 `json:"maxDeliveryCount"` - EnableBatchedOperations *bool `json:"enableBatchedOperations"` - Status string `json:"status"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - AccessedAt time.Time `json:"accessedAt"` - ForwardTo *string `json:"forwardTo"` - ForwardDeadLetteredMessagesTo *string `json:"forwardDeadLetteredMessagesTo"` -} - -func (e *SubscriptionResponseEntity) FromServiceBus(subscription *azservicebus.SubscriptionEntity) { - e.LockDuration = subscription.LockDuration - e.RequiresSession = subscription.RequiresSession - e.DefaultMessageTimeToLive = subscription.DefaultMessageTimeToLive - e.DeadLetteringOnMessageExpiration = subscription.DeadLetteringOnMessageExpiration - e.DeadLetteringOnFilterEvaluationExceptions = subscription.DeadLetteringOnFilterEvaluationExceptions - e.MessageCount = subscription.MessageCount - e.MaxDeliveryCount = subscription.MaxDeliveryCount - e.EnableBatchedOperations = subscription.EnableBatchedOperations - e.Status = string(*subscription.Status) - e.CreatedAt = subscription.CreatedAt.Time - e.UpdatedAt = subscription.UpdatedAt.Time - e.AccessedAt = subscription.AccessedAt.Time - e.ForwardTo = subscription.ForwardTo - e.ForwardDeadLetteredMessagesTo = subscription.ForwardDeadLetteredMessagesTo - e.Name = subscription.Name - e.ID = subscription.ID - - e.CountDetails = CountDetailsEntity{ - ActiveMessageCount: subscription.CountDetails.ActiveMessageCount, - DeadLetterMessageCount: subscription.CountDetails.DeadLetterMessageCount, - ScheduledMessageCount: subscription.CountDetails.ScheduledMessageCount, - TransferDeadLetterMessageCount: subscription.CountDetails.TransferDeadLetterMessageCount, - TransferMessageCount: subscription.CountDetails.TransferMessageCount, - } -} - -type SubscriptionRequestEntity struct { - Name string `json:"name"` - TopicName string `json:"topicName"` - UserDescription string `json:"userDescription"` - MaxDeliveryCount int32 `json:"maxDeliveryCount,omitempty"` - Forward *ForwardEntity `json:"forward,omitempty"` - ForwardDeadLetter *ForwardEntity `json:"forwardDeadLetter,omitempty"` - Rules []*RuleRequestEntity `json:"rules,omitempty"` - Options *SubscriptionRequestOptions `json:"options,omitempty"` -} - -// NewSubscriptionRequest Creates a new subscription entity -func NewSubscriptionRequest(topicName string, name string) *SubscriptionRequestEntity { - result := SubscriptionRequestEntity{ - Name: name, - TopicName: topicName, - MaxDeliveryCount: 10, - } - - result.Rules = make([]*RuleRequestEntity, 0) - result.Forward = &ForwardEntity{} - result.Forward.In = ForwardToTopic - result.ForwardDeadLetter = &ForwardEntity{} - result.Options = &SubscriptionRequestOptions{} - - return &result -} - -// AddSQLFilter Adds a Sql filter to a specific Rule -func (s *SubscriptionRequestEntity) AddSQLFilter(ruleName string, filter string) { - var rule RuleRequestEntity - ruleFound := false - - for i := range s.Rules { - if s.Rules[i].Name == ruleName { - ruleFound = true - if len(s.Rules[i].SQLFilter) > 0 { - s.Rules[i].SQLFilter += " " - } - s.Rules[i].SQLFilter += filter - break - } - } - - if !ruleFound { - rule = RuleRequestEntity{ - Name: ruleName, - SQLFilter: filter, - } - s.Rules = append(s.Rules, &rule) - } -} - -// AddSQLAction Adds a Sql Action to a specific rule -func (s *SubscriptionRequestEntity) AddSQLAction(ruleName string, action string) { - var rule RuleRequestEntity - ruleFound := false - - for i := range s.Rules { - if s.Rules[i].Name == ruleName { - ruleFound = true - if len(s.Rules[i].SQLAction) > 0 { - s.Rules[i].SQLAction += " " - } - s.Rules[i].SQLAction += action - break - } - } - - if !ruleFound { - rule = RuleRequestEntity{ - Name: ruleName, - SQLAction: action, - } - s.Rules = append(s.Rules, &rule) - } -} - -// MapMessageForwardFlag Maps a forward flag string into it's sub components -func (s *SubscriptionRequestEntity) MapMessageForwardFlag(value string) { - if value != "" { - forwardMapped := strings.Split(value, ":") - if len(forwardMapped) == 1 { - s.Forward.To = forwardMapped[0] - } else if len(forwardMapped) == 2 { - s.Forward.To = forwardMapped[1] - switch strings.ToLower(forwardMapped[0]) { - case "topic": - s.Forward.In = ForwardToTopic - case "queue": - s.Forward.In = ForwardToQueue - } - } - } -} - -// MapDeadLetterForwardFlag Maps a forward dead letter flag string into it's sub components -func (s *SubscriptionRequestEntity) MapDeadLetterForwardFlag(value string) { - if value != "" { - forwardMapped := strings.Split(value, ":") - if len(forwardMapped) == 1 { - s.ForwardDeadLetter.To = forwardMapped[0] - } else if len(forwardMapped) == 2 { - s.ForwardDeadLetter.To = forwardMapped[1] - switch strings.ToLower(forwardMapped[0]) { - case "topic": - s.ForwardDeadLetter.In = ForwardToTopic - case "queue": - s.ForwardDeadLetter.In = ForwardToQueue - } - } - } -} - -// MapRuleFlag Maps a rule flag string into it's sub components -func (s *SubscriptionRequestEntity) MapRuleFlag(value string) { - if value != "" { - ruleMapped := strings.Split(value, ":") - if len(ruleMapped) > 1 { - s.AddSQLFilter(ruleMapped[0], ruleMapped[1]) - if len(ruleMapped) == 3 { - s.AddSQLAction(ruleMapped[0], ruleMapped[2]) - } - } - } -} - -func (tr *SubscriptionRequestEntity) GetOptions() (*[]servicebus.SubscriptionManagementOption, *ApiErrorResponse) { - var opts []servicebus.SubscriptionManagementOption - opts = make([]servicebus.SubscriptionManagementOption, 0) - var errorResponse ApiErrorResponse - if tr.Options != nil { - if tr.Options.AutoDeleteOnIdle != nil { - d, err := time.ParseDuration(*tr.Options.AutoDeleteOnIdle) - if err != nil { - errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Duration Parse Error" - errorResponse.Message = "There was an error processing the AutoDeleteOnIdle from string" - return nil, &errorResponse - } - opts = append(opts, servicebus.SubscriptionWithAutoDeleteOnIdle(&d)) - } - if tr.Options.EnableBatchedOperation != nil && *tr.Options.EnableBatchedOperation { - opts = append(opts, servicebus.SubscriptionWithBatchedOperations()) - } - if tr.Options.DeadLetteringOnMessageExpiration != nil && *tr.Options.DeadLetteringOnMessageExpiration { - opts = append(opts, servicebus.SubscriptionWithDeadLetteringOnMessageExpiration()) - } - if tr.Options.RequireSession != nil && *tr.Options.RequireSession { - opts = append(opts, servicebus.SubscriptionWithRequiredSessions()) - } - if tr.Options.DefaultMessageTimeToLive != nil { - d, err := time.ParseDuration(*tr.Options.DefaultMessageTimeToLive) - if err != nil { - errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Duration Parse Error" - errorResponse.Message = "There was an error processing the DefaultMessageTimeToLive from string" - return nil, &errorResponse - } - opts = append(opts, servicebus.SubscriptionWithMessageTimeToLive(&d)) - } - if tr.Options.LockDuration != nil { - d, err := time.ParseDuration(*tr.Options.LockDuration) - if err != nil { - errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Duration Parse Error" - errorResponse.Message = "There was an error processing the LockDuration from string" - return nil, &errorResponse - } - opts = append(opts, servicebus.SubscriptionWithLockDuration(&d)) - } - } - - return &opts, nil -} - -func (tr *SubscriptionRequestEntity) ValidateSubscriptionRequest() (bool, *ApiErrorResponse) { - var errorResponse ApiErrorResponse - - if tr.Name == "" { - errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Subscription name is null" - errorResponse.Message = "Subscription Name cannot be null" - return false, &errorResponse - } - - if tr.TopicName == "" { - errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Topic Name is null" - errorResponse.Message = "Topic Name cannot be null" - return false, &errorResponse - } - - return true, nil -} - -type SubscriptionRequestOptions struct { - AutoDeleteOnIdle *string `json:"autoDeleteOnIdle,omitempty"` - DefaultMessageTimeToLive *string `json:"defaultMessageTimeToLive,omitempty"` - LockDuration *string `json:"lockDuration,omitempty"` - EnableBatchedOperation *bool `json:"enableBatchedOperation,omitempty"` - DeadLetteringOnMessageExpiration *bool `json:"deadLetteringOnMessageExpiration,omitempty"` - RequireSession *bool `json:"requireSession,omitempty"` -} diff --git a/entities/topic-request-options.go b/entities/topic-request-options.go new file mode 100644 index 0000000..4c27ad2 --- /dev/null +++ b/entities/topic-request-options.go @@ -0,0 +1,12 @@ +package entities + +type TopicRequestOptions struct { + AutoDeleteOnIdle *string `json:"autoDeleteOnIdle,omitempty"` + EnableBatchedOperation *bool `json:"enableBatchedOperation,omitempty"` + EnableDuplicateDetection *string `json:"enableDuplicateDetection,omitempty"` + EnableExpress *bool `json:"enableExpress,omitempty"` + MaxSizeInMegabytes *int `json:"maxSizeInMegabytes,omitempty"` + DefaultMessageTimeToLive *string `json:"defaultMessageTimeToLive,omitempty"` + SupportOrdering *bool `json:"supportOrdering,omitempty"` + EnablePartitioning *bool `json:"enablePartitioning,omitempty"` +} diff --git a/entities/topic-request.go b/entities/topic-request.go new file mode 100644 index 0000000..51de9c6 --- /dev/null +++ b/entities/topic-request.go @@ -0,0 +1,81 @@ +package entities + +import ( + "net/http" + "time" + + servicebus "github.com/Azure/azure-service-bus-go" +) + +type TopicRequestEntity struct { + Name string `json:"name"` + Options *TopicRequestOptions `json:"options,omitempty"` +} + +func (tr *TopicRequestEntity) GetOptions() (*[]servicebus.TopicManagementOption, *ApiErrorResponse) { + var opts []servicebus.TopicManagementOption + opts = make([]servicebus.TopicManagementOption, 0) + var errorResponse ApiErrorResponse + if tr.Options != nil { + if tr.Options.AutoDeleteOnIdle != nil { + d, err := time.ParseDuration(*tr.Options.AutoDeleteOnIdle) + if err != nil { + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Duration Parse Error" + errorResponse.Message = "There was an error processing the AutoDeleteOnIdle from string" + return nil, &errorResponse + } + opts = append(opts, servicebus.TopicWithAutoDeleteOnIdle(&d)) + } + if tr.Options.EnableBatchedOperation != nil && *tr.Options.EnableBatchedOperation { + opts = append(opts, servicebus.TopicWithBatchedOperations()) + } + if tr.Options.EnableDuplicateDetection != nil { + d, err := time.ParseDuration(*tr.Options.EnableDuplicateDetection) + if err != nil { + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Duration Parse Error" + errorResponse.Message = "There was an error processing the EnableDuplicateDetection from string" + return nil, &errorResponse + } + opts = append(opts, servicebus.TopicWithDuplicateDetection(&d)) + } + if tr.Options.EnableExpress != nil && *tr.Options.EnableExpress { + opts = append(opts, servicebus.TopicWithExpress()) + } + if tr.Options.MaxSizeInMegabytes != nil { + opts = append(opts, servicebus.TopicWithMaxSizeInMegabytes(*tr.Options.MaxSizeInMegabytes)) + } + if tr.Options.DefaultMessageTimeToLive != nil { + d, err := time.ParseDuration(*tr.Options.DefaultMessageTimeToLive) + if err != nil { + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Duration Parse Error" + errorResponse.Message = "There was an error processing the DefaultMessageTimeToLive from string" + return nil, &errorResponse + } + opts = append(opts, servicebus.TopicWithMessageTimeToLive(&d)) + } + if tr.Options.SupportOrdering != nil && *tr.Options.SupportOrdering { + opts = append(opts, servicebus.TopicWithOrdering()) + } + if tr.Options.EnablePartitioning != nil && *tr.Options.EnablePartitioning { + opts = append(opts, servicebus.TopicWithPartitioning()) + } + } + + return &opts, nil +} + +func (tr *TopicRequestEntity) IsValid() (bool, *ApiErrorResponse) { + var errorResponse ApiErrorResponse + + if tr.Name == "" { + errorResponse.Code = http.StatusBadRequest + errorResponse.Error = "Topic name is null" + errorResponse.Message = "Topic name cannot be null" + return false, &errorResponse + } + + return true, nil +} diff --git a/entities/topic-response.go b/entities/topic-response.go new file mode 100644 index 0000000..077547c --- /dev/null +++ b/entities/topic-response.go @@ -0,0 +1,56 @@ +package entities + +import ( + "time" + + servicebus "github.com/Azure/azure-service-bus-go" +) + +type TopicResponseEntity struct { + Name string `json:"name"` + ID string `json:"id"` + CountDetails CountDetails `json:"countDetails,omitempty"` + DefaultMessageTimeToLive *string `json:"defaultMessageTimeToLive"` + MaxSizeInMegabytes *int32 `json:"maxSizeInMegabytes"` + RequiresDuplicateDetection *bool `json:"requiresDuplicateDetection"` + DuplicateDetectionHistoryTimeWindow *string `json:"duplicateDetectionHistoryTimeWindow"` + EnableBatchedOperations *bool `json:"enableBatchedOperations"` + SizeInBytes *int64 `json:"sizeInBytes"` + FilteringMessagesBeforePublishing *bool `json:"filteringMessagesBeforePublishing"` + IsAnonymousAccessible *bool `json:"isAnonymousAccessible"` + Status string `json:"status"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + SupportOrdering *bool `json:"supportOrdering"` + AutoDeleteOnIdle *string `json:"autoDeleteOnIdle"` + EnablePartitioning *bool `json:"enablePartitioning"` + EnableSubscriptionPartitioning *bool `json:"enableSubscriptionPartitioning"` + EnableExpress *bool `json:"enableExpress"` +} + +func (t *TopicResponseEntity) FromServiceBus(topic *servicebus.TopicEntity) { + if topic == nil { + return + } + + t.Name = topic.Name + t.ID = topic.ID + t.DefaultMessageTimeToLive = topic.DefaultMessageTimeToLive + t.MaxSizeInMegabytes = topic.MaxSizeInMegabytes + t.RequiresDuplicateDetection = topic.RequiresDuplicateDetection + t.DuplicateDetectionHistoryTimeWindow = topic.DuplicateDetectionHistoryTimeWindow + t.EnableBatchedOperations = topic.EnableBatchedOperations + t.SizeInBytes = topic.SizeInBytes + t.FilteringMessagesBeforePublishing = topic.FilteringMessagesBeforePublishing + t.IsAnonymousAccessible = topic.IsAnonymousAccessible + t.Status = string(*topic.Status) + t.CreatedAt = topic.CreatedAt.Time + t.UpdatedAt = topic.UpdatedAt.Time + t.SupportOrdering = topic.SupportOrdering + t.AutoDeleteOnIdle = topic.AutoDeleteOnIdle + t.EnablePartitioning = topic.EnablePartitioning + t.EnableSubscriptionPartitioning = topic.EnableSubscriptionPartitioning + t.EnableExpress = topic.EnableExpress + t.CountDetails = CountDetails{} + t.CountDetails.FromServiceBus(topic.CountDetails) +} diff --git a/entities/topic.go b/entities/topic.go deleted file mode 100644 index c9b170a..0000000 --- a/entities/topic.go +++ /dev/null @@ -1,141 +0,0 @@ -package entities - -import ( - "net/http" - "time" - - servicebus "github.com/Azure/azure-service-bus-go" -) - -type TopicResponseEntity struct { - Name string `json:"name"` - ID string `json:"id"` - CountDetails CountDetailsEntity `json:"countDetails,omitempty"` - DefaultMessageTimeToLive *string `json:"defaultMessageTimeToLive"` - MaxSizeInMegabytes *int32 `json:"maxSizeInMegabytes"` - RequiresDuplicateDetection *bool `json:"requiresDuplicateDetection"` - DuplicateDetectionHistoryTimeWindow *string `json:"duplicateDetectionHistoryTimeWindow"` - EnableBatchedOperations *bool `json:"enableBatchedOperations"` - SizeInBytes *int64 `json:"sizeInBytes"` - FilteringMessagesBeforePublishing *bool `json:"filteringMessagesBeforePublishing"` - IsAnonymousAccessible *bool `json:"isAnonymousAccessible"` - Status string `json:"status"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - SupportOrdering *bool `json:"supportOrdering"` - AutoDeleteOnIdle *string `json:"autoDeleteOnIdle"` - EnablePartitioning *bool `json:"enablePartitioning"` - EnableSubscriptionPartitioning *bool `json:"enableSubscriptionPartitioning"` - EnableExpress *bool `json:"enableExpress"` -} - -func (t *TopicResponseEntity) FromServiceBus(topic *servicebus.TopicEntity) { - if topic == nil { - return - } - - t.Name = topic.Name - t.ID = topic.ID - t.DefaultMessageTimeToLive = topic.DefaultMessageTimeToLive - t.MaxSizeInMegabytes = topic.MaxSizeInMegabytes - t.RequiresDuplicateDetection = topic.RequiresDuplicateDetection - t.DuplicateDetectionHistoryTimeWindow = topic.DuplicateDetectionHistoryTimeWindow - t.EnableBatchedOperations = topic.EnableBatchedOperations - t.SizeInBytes = topic.SizeInBytes - t.FilteringMessagesBeforePublishing = topic.FilteringMessagesBeforePublishing - t.IsAnonymousAccessible = topic.IsAnonymousAccessible - t.Status = string(*topic.Status) - t.CreatedAt = topic.CreatedAt.Time - t.UpdatedAt = topic.UpdatedAt.Time - t.SupportOrdering = topic.SupportOrdering - t.AutoDeleteOnIdle = topic.AutoDeleteOnIdle - t.EnablePartitioning = topic.EnablePartitioning - t.EnableSubscriptionPartitioning = topic.EnableSubscriptionPartitioning - t.EnableExpress = topic.EnableExpress - t.CountDetails = CountDetailsEntity{} - t.CountDetails.FromServiceBus(topic.CountDetails) -} - -type TopicRequestEntity struct { - Name string `json:"name"` - Options *TopicRequestOptions `json:"options,omitempty"` -} - -func (tr *TopicRequestEntity) GetOptions() (*[]servicebus.TopicManagementOption, *ApiErrorResponse) { - var opts []servicebus.TopicManagementOption - opts = make([]servicebus.TopicManagementOption, 0) - var errorResponse ApiErrorResponse - if tr.Options != nil { - if tr.Options.AutoDeleteOnIdle != nil { - d, err := time.ParseDuration(*tr.Options.AutoDeleteOnIdle) - if err != nil { - errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Duration Parse Error" - errorResponse.Message = "There was an error processing the AutoDeleteOnIdle from string" - return nil, &errorResponse - } - opts = append(opts, servicebus.TopicWithAutoDeleteOnIdle(&d)) - } - if tr.Options.EnableBatchedOperation != nil && *tr.Options.EnableBatchedOperation { - opts = append(opts, servicebus.TopicWithBatchedOperations()) - } - if tr.Options.EnableDuplicateDetection != nil { - d, err := time.ParseDuration(*tr.Options.EnableDuplicateDetection) - if err != nil { - errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Duration Parse Error" - errorResponse.Message = "There was an error processing the EnableDuplicateDetection from string" - return nil, &errorResponse - } - opts = append(opts, servicebus.TopicWithDuplicateDetection(&d)) - } - if tr.Options.EnableExpress != nil && *tr.Options.EnableExpress { - opts = append(opts, servicebus.TopicWithExpress()) - } - if tr.Options.MaxSizeInMegabytes != nil { - opts = append(opts, servicebus.TopicWithMaxSizeInMegabytes(*tr.Options.MaxSizeInMegabytes)) - } - if tr.Options.DefaultMessageTimeToLive != nil { - d, err := time.ParseDuration(*tr.Options.DefaultMessageTimeToLive) - if err != nil { - errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Duration Parse Error" - errorResponse.Message = "There was an error processing the DefaultMessageTimeToLive from string" - return nil, &errorResponse - } - opts = append(opts, servicebus.TopicWithMessageTimeToLive(&d)) - } - if tr.Options.SupportOrdering != nil && *tr.Options.SupportOrdering { - opts = append(opts, servicebus.TopicWithOrdering()) - } - if tr.Options.EnablePartitioning != nil && *tr.Options.EnablePartitioning { - opts = append(opts, servicebus.TopicWithPartitioning()) - } - } - - return &opts, nil -} - -func (tr *TopicRequestEntity) IsValidate() (bool, *ApiErrorResponse) { - var errorResponse ApiErrorResponse - - if tr.Name == "" { - errorResponse.Code = http.StatusBadRequest - errorResponse.Error = "Topic name is null" - errorResponse.Message = "Topic name cannot be null" - return false, &errorResponse - } - - return true, nil -} - -type TopicRequestOptions struct { - AutoDeleteOnIdle *string `json:"autoDeleteOnIdle,omitempty"` - EnableBatchedOperation *bool `json:"enableBatchedOperation,omitempty"` - EnableDuplicateDetection *string `json:"enableDuplicateDetection,omitempty"` - EnableExpress *bool `json:"enableExpress,omitempty"` - MaxSizeInMegabytes *int `json:"maxSizeInMegabytes,omitempty"` - DefaultMessageTimeToLive *string `json:"defaultMessageTimeToLive,omitempty"` - SupportOrdering *bool `json:"supportOrdering,omitempty"` - EnablePartitioning *bool `json:"enablePartitioning,omitempty"` -} diff --git a/entities/user.go b/entities/user.go deleted file mode 100644 index fc335ff..0000000 --- a/entities/user.go +++ /dev/null @@ -1,10 +0,0 @@ -package entities - -// User entity -type User struct { - ID string `json:"id" bson:"_id"` - Email string `json:"email" bson:"email"` - FirstName string `json:"firstName" bson:"firstName"` - LastName string `json:"lastName" bson:"lastName"` - Password string `json:"password" bson:"password"` -} diff --git a/go.mod b/go.mod index ec69d52..0d0b979 100644 --- a/go.mod +++ b/go.mod @@ -2,11 +2,9 @@ module github.com/cjlapao/servicebuscli-go go 1.16 -// replace github.com/cjlapao/common-go => D:\Code\Projects\Go\common-go - require ( github.com/Azure/azure-service-bus-go v0.10.7 - github.com/cjlapao/common-go v0.0.7 + github.com/cjlapao/common-go v0.0.9 github.com/fatih/color v1.10.0 github.com/golang/protobuf v1.4.2 // indirect github.com/gomarkdown/markdown v0.0.0-20210408062403-ad838ccf8cdd @@ -15,7 +13,6 @@ require ( github.com/kr/pretty v0.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect - github.com/rs/xid v1.2.1 github.com/stretchr/objx v0.1.1 // indirect golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect diff --git a/go.sum b/go.sum index 35f4b3e..d8633e6 100644 --- a/go.sum +++ b/go.sum @@ -31,8 +31,8 @@ github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUM github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cjlapao/common-go v0.0.7 h1:TrRMKtzSB0+I9q9KlZgnKbYSJ2ecOI0w9uzedavGHyw= -github.com/cjlapao/common-go v0.0.7/go.mod h1:WS8XKs+ihK2SX0PuYmngl26zXGYuW+0sv3W6qW+dwR8= +github.com/cjlapao/common-go v0.0.9 h1:v5z7T4mtaZPoOiVUgnBgs0G7n1pN7E+xes4xpwWdq/0= +github.com/cjlapao/common-go v0.0.9/go.mod h1:WS8XKs+ihK2SX0PuYmngl26zXGYuW+0sv3W6qW+dwR8= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -124,8 +124,6 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc= -github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/helm/values.yaml b/helm/values.yaml index 86c6bf3..39a282f 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -1,2 +1,2 @@ namespace: "default" -serviceBusConnectionString: \ No newline at end of file +serviceBusConnectionString: "" \ No newline at end of file diff --git a/help/main.go b/help/main.go index 474d485..7c9dd15 100644 --- a/help/main.go +++ b/help/main.go @@ -198,21 +198,13 @@ func PrintTopicSendCommandHelper() { logger.Info("") logger.Info("Available Options:") logger.Info(" --topic string Name of the topic where to send the message") - logger.Info(" --tenant guid Id of the tenant") + logger.Info(" --file string File path for the message to be sent, this will include all of the options") logger.Info(" --body json Message body in json (please escape the json correctly as this is validated)") - logger.Info(" --domain string Forwarding topology Message Domain") - logger.Info(" --name string Forwarding topology Message Name") - logger.Info(" --version string Forwarding topology Version") - logger.Info(" --sender string Forwarding topology Sender") logger.Info(" --label string Message Label") logger.Info(" --property key:value Add a User property to the message") logger.Info(" This option can be repeated to add more than one property") logger.Info(" the format will be [key]:[value]") logger.Info(" example: X-Sender:example") - logger.Info(" --default With this flag the tool will generate a default TimeService sample") - logger.Info(" using the forwarding topology format") - logger.Info(" --uno With this flag the tool will convert the default TimeService sample") - logger.Info(" message to Uno format") logger.Info("") logger.Info("example:") os := runtime.GOOS @@ -286,21 +278,13 @@ func PrintQueueSendCommandHelper() { logger.Info("") logger.Info("Available Options:") logger.Info(" --queue string Name of the queue where to send the message") - logger.Info(" --tenant guid Id of the tenant") + logger.Info(" --file string File path for the message to be sent, this will include all of the options") logger.Info(" --body json Message body in json (please escape the json correctly as this is validated)") - logger.Info(" --domain string Forwarding topology Message Domain") - logger.Info(" --name string Forwarding topology Message Name") - logger.Info(" --version string Forwarding topology Version") - logger.Info(" --sender string Forwarding topology Sender") logger.Info(" --label string Message Label") logger.Info(" --property key:value Add a User property to the message") logger.Info(" This option can be repeated to add more than one property") logger.Info(" the format will be [key]:[value]") logger.Info(" example: X-Sender:example") - logger.Info(" --default With this flag the tool will generate a default TimeService sample") - logger.Info(" using the forwarding topology format") - logger.Info(" --uno With this flag the tool will convert the default TimeService sample") - logger.Info(" message to Uno format") logger.Info("") logger.Info("example:") os := runtime.GOOS diff --git a/main.go b/main.go index d54aa3e..5635190 100644 --- a/main.go +++ b/main.go @@ -7,7 +7,7 @@ import ( "os/signal" "strings" "sync" - "time" + "syscall" "github.com/cjlapao/common-go/helper" "github.com/cjlapao/common-go/log" @@ -17,7 +17,6 @@ import ( "github.com/cjlapao/servicebuscli-go/help" "github.com/cjlapao/servicebuscli-go/servicebus" "github.com/cjlapao/servicebuscli-go/startup" - "github.com/rs/xid" ) var logger = log.Get() @@ -27,6 +26,7 @@ func main() { ver.Name = "Service Bus Tool" ver.Author = "Carlos Lapao" ver.License = "MIT" + ver.Minor = 2 ver.Rev = 1 ver.PrintHeader() @@ -76,7 +76,7 @@ func main() { } signalChan := make(chan os.Signal, 1) - signal.Notify(signalChan, os.Interrupt, os.Kill) + signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM) var wg sync.WaitGroup wg.Add(len(topics)) @@ -168,22 +168,6 @@ func main() { } else { logger.LogHighlight("No subscriptions found on topic %v in service bus %v", log.Info, topic, sbcli.Namespace.Name) } - case "delete": - if helpArg { - help.PrintTopicDeleteTopicCommandHelper() - os.Exit(0) - } - topic := helper.GetFlagValue("name", "") - if topic == "" { - logger.Error("Missing topic name mandatory argument --name") - help.PrintTopicDeleteTopicCommandHelper() - os.Exit(0) - } - sbcli := servicebus.NewCli(connStr) - err := sbcli.DeleteTopic(topic) - if err != nil { - os.Exit(1) - } case "create": if helpArg { help.PrintTopicCreateTopicCommandHelper() @@ -232,6 +216,22 @@ func main() { if err != nil { os.Exit(1) } + case "delete": + if helpArg { + help.PrintTopicDeleteTopicCommandHelper() + os.Exit(0) + } + topic := helper.GetFlagValue("name", "") + if topic == "" { + logger.Error("Missing topic name mandatory argument --name") + help.PrintTopicDeleteTopicCommandHelper() + os.Exit(0) + } + sbcli := servicebus.NewCli(connStr) + err := sbcli.DeleteTopic(topic) + if err != nil { + os.Exit(1) + } case "delete-subscription": if helpArg { help.PrintTopicDeleteSubscriptionCommandHelper() @@ -260,15 +260,11 @@ func main() { os.Exit(0) } topic := helper.GetFlagValue("topic", "") - tenantID := helper.GetFlagValue("tenant", "11111111-1111-1111-1111-555555550001") - useDefault := helper.GetFlagSwitch("default", false) - unoFormat := helper.GetFlagSwitch("uno", false) body := helper.GetFlagValue("body", "") label := helper.GetFlagValue("label", "ServiceBus.Tools") - name := helper.GetFlagValue("name", "") - domain := helper.GetFlagValue("domain", "") - sender := helper.GetFlagValue("sender", "ServiceBus.Tools") - version := helper.GetFlagValue("version", "1.0") + filePath := helper.GetFlagValue("file", "") + correlationID := helper.GetFlagValue("correlationID", "") + contentType := helper.GetFlagValue("contentType", "") propertiesFlags := helper.GetFlagArrayValue("property") if topic == "" { @@ -277,65 +273,52 @@ func main() { os.Exit(0) } - var message map[string]interface{} - if useDefault && body == "" { - if !unoFormat { - domain = "TimeService" - name = "TimePassed" - } else { - domain = "" - name = "" - } - message = map[string]interface{}{ - "Timestamp": time.Now().Format("2006-01-02T15:04:05.00000000-07:00"), - "TheTime": time.Now().Format("2006-01-02T15:04:05"), - } - } else if body != "" { - err := json.Unmarshal([]byte(body), &message) + sbMessage := entities.MessageRequest{} + if filePath != "" { + err := sbMessage.FromFile(filePath) if err != nil { logger.Error(err.Error()) os.Exit(1) } } else { - logger.LogHighlight("Missing message body, use %v='{\"example\": \"object\"}' or use the %v flag, this will generate a TimeService sample message", log.Info, "--body", "--default") - help.PrintTopicSendCommandHelper() - os.Exit(0) - } - var properties map[string]interface{} - if len(propertiesFlags) == 0 || useDefault { - if domain != "" && name != "" { - label = domain + "." + name - diagnosticID := xid.New().String() - properties = map[string]interface{}{ - "X-MsgTypeVersion": version, - "X-MsgDomain": domain, - "X-MsgName": name, - "X-Sender": sender, - "X-TenantId": tenantID, - "Diagnostic-Id": diagnosticID, + var message map[string]interface{} + if contentType != "" { + sbMessage.ContentType = contentType + } + if correlationID != "" { + sbMessage.CorrelationID = correlationID + } + sbMessage.Label = label + + if body != "" { + err := json.Unmarshal([]byte(body), &message) + if err != nil { + logger.Error(err.Error()) + os.Exit(1) } } else { - label = topic - properties = map[string]interface{}{ - "Serialization": "1", - "TenantId": tenantID, - } - } - } - if len(propertiesFlags) > 0 { - if properties == nil { - properties = make(map[string]interface{}) + logger.LogHighlight("Missing message body, use %v='{\"example\": \"object\"}' or any json body, you can also send a message object from a file using the --file option", log.Info, "--body", "--default") + help.PrintTopicSendCommandHelper() + os.Exit(0) } - for _, property := range propertiesFlags { - key, value := helper.MapFlagValue(property) - if key != "" && value != "" { - properties[key] = value + sbMessage.Data = message + var properties map[string]interface{} + if len(propertiesFlags) > 0 { + if properties == nil { + properties = make(map[string]interface{}) + } + for _, property := range propertiesFlags { + key, value := helper.MapFlagValue(property) + if key != "" && value != "" { + properties[key] = value + } } } + sbMessage.UserProperties = properties } sbcli := servicebus.NewCli(connStr) - sbcli.SendTopicMessage(topic, message, label, properties) + sbcli.SendTopicMessage(topic, sbMessage) default: logger.LogHighlight("Invalid command argument %v, please choose a valid argument", log.Info, command) help.PrintTopicMainCommandHelper() @@ -468,82 +451,65 @@ func main() { os.Exit(0) } queue := helper.GetFlagValue("queue", "") - tenantID := helper.GetFlagValue("tenant", "11111111-1111-1111-1111-555555550001") - useDefault := helper.GetFlagSwitch("default", false) - unoFormat := helper.GetFlagSwitch("uno", false) body := helper.GetFlagValue("body", "") label := helper.GetFlagValue("label", "ServiceBus.Tools") - name := helper.GetFlagValue("name", "") - domain := helper.GetFlagValue("domain", "") - sender := helper.GetFlagValue("sender", "ServiceBus.Tools") - version := helper.GetFlagValue("version", "1.0") + filePath := helper.GetFlagValue("file", "") + correlationID := helper.GetFlagValue("correlationID", "") + contentType := helper.GetFlagValue("contentType", "") propertiesFlags := helper.GetFlagArrayValue("property") if queue == "" { - logger.Error("Missing queue name mandatory argument --name") + logger.LogHighlight("Missing queue name mandatory argument %v", log.Error, "--name") help.PrintQueueSendCommandHelper() os.Exit(0) } - var message map[string]interface{} - if useDefault && body == "" { - if !unoFormat { - domain = "TimeService" - name = "TimePassed" - } else { - domain = "" - name = "" - } - message = map[string]interface{}{ - "Timestamp": time.Now().Format("2006-01-02T15:04:05.00000000-07:00"), - "TheTime": time.Now().Format("2006-01-02T15:04:05"), - } - } else if body != "" { - err := json.Unmarshal([]byte(body), &message) + sbMessage := entities.MessageRequest{} + if filePath != "" { + err := sbMessage.FromFile(filePath) if err != nil { logger.Error(err.Error()) os.Exit(1) } } else { - logger.LogHighlight("Missing message body, use %v='{\"example\": \"object\"}' or use the %v flag, this will generate a TimeService sample message", log.Error, "--body", "--default") - help.PrintTopicSendCommandHelper() - os.Exit(0) - } - var properties map[string]interface{} - if len(propertiesFlags) == 0 || useDefault { - if domain != "" && name != "" { - label = domain + "." + name - diagnosticID := xid.New().String() - properties = map[string]interface{}{ - "X-MsgTypeVersion": version, - "X-MsgDomain": domain, - "X-MsgName": name, - "X-Sender": sender, - "X-TenantId": tenantID, - "Diagnostic-Id": diagnosticID, + var message map[string]interface{} + if contentType != "" { + sbMessage.ContentType = contentType + } + if correlationID != "" { + sbMessage.CorrelationID = correlationID + } + sbMessage.Label = label + + if body != "" { + err := json.Unmarshal([]byte(body), &message) + if err != nil { + logger.Error(err.Error()) + os.Exit(1) } } else { - label = queue - properties = map[string]interface{}{ - "Serialization": "1", - "TenantId": tenantID, - } + logger.LogHighlight("Missing message body, use %v='{\"example\": \"object\"}' or any json body, you can also send a message object from a file using the --file option", log.Info, "--body", "--default") + help.PrintTopicSendCommandHelper() + os.Exit(0) } - } - if len(propertiesFlags) > 0 { - if properties == nil { - properties = make(map[string]interface{}) - } - for _, property := range propertiesFlags { - key, value := helper.MapFlagValue(property) - if key != "" && value != "" { - properties[key] = value + sbMessage.Data = message + var properties map[string]interface{} + if len(propertiesFlags) > 0 { + if properties == nil { + properties = make(map[string]interface{}) + } + for _, property := range propertiesFlags { + key, value := helper.MapFlagValue(property) + if key != "" && value != "" { + properties[key] = value + } } } + sbMessage.UserProperties = properties } sbcli := servicebus.NewCli(connStr) - sbcli.SendQueueMessage(queue, message, label, properties) + sbcli.SendQueueMessage(queue, sbMessage) default: logger.LogHighlight("Invalid command argument %v, please choose a valid argument", log.Error, command) diff --git a/servicebus/message.go b/servicebus/message.go deleted file mode 100644 index 121bd04..0000000 --- a/servicebus/message.go +++ /dev/null @@ -1,8 +0,0 @@ -package servicebus - -// MessageEntity Entity -type MessageEntity struct { - Label string `json:"label"` - Message map[string]interface{} `json:"message"` - Properties map[string]interface{} `json:"properties"` -} diff --git a/servicebus/queue.go b/servicebus/queue.go index b41ba79..10111fe 100644 --- a/servicebus/queue.go +++ b/servicebus/queue.go @@ -84,7 +84,7 @@ func (s *ServiceBusCli) ListQueues() ([]*servicebus.QueueEntity, error) { } // CreateQueue Creates a queue in the service bus namespace -func (s *ServiceBusCli) CreateQueue(queue entities.QueueRequestEntity) error { +func (s *ServiceBusCli) CreateQueue(queue entities.QueueRequest) error { var commonError error opts := make([]servicebus.QueueManagementOption, 0) @@ -121,7 +121,7 @@ func (s *ServiceBusCli) CreateQueue(queue entities.QueueRequestEntity) error { } // Generating the forward rule, checking if the target exists or not - if queue.Forward.To != "" { + if queue.Forward != nil && queue.Forward.To != "" { switch queue.Forward.In { case entities.ForwardToTopic: tm := s.GetTopicManager() @@ -143,7 +143,7 @@ func (s *ServiceBusCli) CreateQueue(queue entities.QueueRequestEntity) error { } // Generating the Dead Letter forwarding rule, checking if the target exist or not - if queue.ForwardDeadLetter.To != "" { + if queue.ForwardDeadLetter != nil && queue.ForwardDeadLetter.To != "" { switch queue.ForwardDeadLetter.In { case entities.ForwardToTopic: tm := s.GetTopicManager() @@ -198,7 +198,7 @@ func (s *ServiceBusCli) DeleteQueue(queueName string) error { } // SendQueueMessage Sends a Service Bus Message to a Queue -func (s *ServiceBusCli) SendQueueMessage(queueName string, message map[string]interface{}, label string, userParameters map[string]interface{}) error { +func (s *ServiceBusCli) SendQueueMessage(queueName string, message entities.MessageRequest) error { var commonError error logger.LogHighlight("Sending a service bus queue message to %v queue in service bus %v", log.Info, queueName, s.Namespace.Name) if queueName == "" { @@ -223,16 +223,14 @@ func (s *ServiceBusCli) SendQueueMessage(queueName string, message map[string]in return err } - sbMessage := servicebus.Message{ - Data: messageData, - UserProperties: userParameters, - } + sbMessage, err := message.ToServiceBus() - if label != "" { - sbMessage.Label = label + if err != nil { + logger.Error(err.Error()) + return err } - err = queue.Send(ctx, &sbMessage) + err = queue.Send(ctx, sbMessage) if err != nil { logger.Error(err.Error()) @@ -245,6 +243,57 @@ func (s *ServiceBusCli) SendQueueMessage(queueName string, message map[string]in return nil } +func (s *ServiceBusCli) SendParallelBulkQueueMessage(wg *sync.WaitGroup, queueName string, messages ...entities.MessageRequest) { + defer wg.Done() + _ = s.SendBulkQueueMessage(queueName, messages...) +} + +// SendQueueMessage Sends a Service Bus Message to a Queue +func (s *ServiceBusCli) SendBulkQueueMessage(queueName string, messages ...entities.MessageRequest) error { + var commonError error + logger.LogHighlight("Sending a service bus queue messages to %v queue in service bus %v", log.Info, queueName, s.Namespace.Name) + if queueName == "" { + commonError = errors.New("queue cannot be null") + logger.Error(commonError.Error()) + return commonError + } + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + queue, err := s.GetQueue(queueName) + if queue == nil || err != nil { + commonError = errors.New("Could not find queue " + queueName + " in service bus " + s.Namespace.Name) + logger.LogHighlight("Could not find queue %v in service bus %v", log.Error, queueName, s.Namespace.Name) + return commonError + } + sbMessages := make([]*servicebus.Message, 0) + for _, msg := range messages { + sbMessage, err := msg.ToServiceBus() + + if err != nil { + logger.Error(err.Error()) + return err + } + sbMessages = append(sbMessages, sbMessage) + } + + if err != nil { + logger.Error(err.Error()) + return err + } + + err = queue.SendBatch(ctx, servicebus.NewMessageBatchIterator(262144, sbMessages...)) + + if err != nil { + logger.Error(err.Error()) + os.Exit(1) + } + + logger.LogHighlight("Service bus bulk queue messages were sent successfully to %v queue in service bus %v", log.Info, queueName, s.Namespace.Name) + return nil +} + // SendQueueServiceBusMessage Sends a Service Bus Message to a Queue func (s *ServiceBusCli) SendQueueServiceBusMessage(queueName string, sbMessage *servicebus.Message) error { var commonError error @@ -419,15 +468,22 @@ func (s *ServiceBusCli) GetQueueActiveMessages(queueName string, qty int, peek b // Background task to receive all of the messages we need go func() { - for i := 0; i < qty; i++ { - if peek { - m, commonError := queue.PeekOne(ctx) - if commonError == nil { - messages = append(messages, *m) + if peek { + t, err := queue.Peek(ctx) + if err != nil { + fmt.Println(err.Error()) + } + for i := 0; i < qty; i++ { + m, err := t.Next(ctx) + if err != nil { + fmt.Println(err.Error()) } + messages = append(messages, *m) waitForMessages.Done() - } else { - if err := messageReceiver.ReceiveOne(ctx, messageHandler); err != nil { + } + } else { + for i := 0; i < qty; i++ { + if err := queue.ReceiveOne(ctx, messageHandler); err != nil { fmt.Println(err.Error()) } } diff --git a/servicebus/subscription.go b/servicebus/subscription.go index 132a7b5..a0d4bad 100644 --- a/servicebus/subscription.go +++ b/servicebus/subscription.go @@ -47,7 +47,7 @@ func (s *ServiceBusCli) ListSubscriptions(topicName string) ([]*servicebus.Subsc } // CreateSubscription Creates a subscription to a topic in the service bus -func (s *ServiceBusCli) CreateSubscription(subscription entities.SubscriptionRequestEntity, upsert bool) error { +func (s *ServiceBusCli) CreateSubscription(subscription entities.SubscriptionRequest, upsert bool) error { var commonError error opts := make([]servicebus.SubscriptionManagementOption, 0) ctx, cancel := context.WithTimeout(context.Background(), 40*time.Second) @@ -196,7 +196,7 @@ func (s *ServiceBusCli) DeleteSubscriptionRule(topicName string, subscriptionNam } // CreateSubscriptionRule Creates a rule to a specific subscription -func (s *ServiceBusCli) CreateSubscriptionRule(subscription entities.SubscriptionRequestEntity, rule entities.RuleRequestEntity) error { +func (s *ServiceBusCli) CreateSubscriptionRule(subscription entities.SubscriptionRequest, rule entities.RuleRequest) error { ctx, cancel := context.WithTimeout(context.Background(), 40*time.Second) defer cancel() logger.LogHighlight("Creating subscription rule %v in subscription %v on topic %v in service bus %v", log.Info, rule.Name, subscription.Name, subscription.TopicName, s.Namespace.Name) @@ -454,14 +454,21 @@ func (s *ServiceBusCli) GetSubscriptionActiveMessages(topicName string, subscrip // Background task to receive all of the messages we need go func() { - for i := 0; i < qty; i++ { - if peek { - m, commonError := messageReceiver.PeekOne(ctx) - if commonError == nil { - messages = append(messages, *m) + if peek { + t, err := messageReceiver.Peek(ctx) + if err != nil { + fmt.Println(err.Error()) + } + for i := 0; i < qty; i++ { + m, err := t.Next(ctx) + if err != nil { + fmt.Println(err.Error()) } + messages = append(messages, *m) waitForMessages.Done() - } else { + } + } else { + for i := 0; i < qty; i++ { if err := messageReceiver.ReceiveOne(ctx, messageHandler); err != nil { fmt.Println(err.Error()) } diff --git a/servicebus/topic.go b/servicebus/topic.go index 2e2e439..67edb74 100644 --- a/servicebus/topic.go +++ b/servicebus/topic.go @@ -2,13 +2,14 @@ package servicebus import ( "context" - "encoding/json" "errors" "os" + "sync" "time" servicebus "github.com/Azure/azure-service-bus-go" "github.com/cjlapao/common-go/log" + "github.com/cjlapao/servicebuscli-go/entities" ) // GetTopicManager creates a servicebus topic manager @@ -88,7 +89,7 @@ func (s *ServiceBusCli) ListTopics() ([]*servicebus.TopicEntity, error) { } // SendTopicMessage sends a message to a specific topic -func (s *ServiceBusCli) SendTopicMessage(topicName string, message map[string]interface{}, label string, userParameters map[string]interface{}) error { +func (s *ServiceBusCli) SendTopicMessage(topicName string, message entities.MessageRequest) error { var commonError error logger.LogHighlight("Sending a service bus topic message to %v topic in service bus %v", log.Info, topicName, s.Namespace.Name) if topicName == "" { @@ -107,31 +108,69 @@ func (s *ServiceBusCli) SendTopicMessage(topicName string, message map[string]in return commonError } - messageData, err := json.MarshalIndent(message, "", " ") + sbMessage, err := message.ToServiceBus() + if err != nil { logger.Error(err.Error()) return err } - sbMessage := servicebus.Message{ - Data: messageData, - UserProperties: userParameters, + err = topic.Send(ctx, sbMessage) + + if err != nil { + logger.Error(err.Error()) + return err + } + + logger.LogHighlight("Service bus topic message was sent successfully to %v topic in service bus %v", log.Info, topicName, s.Namespace.Name) + logger.Info("Message Body:") + logger.Info(string(sbMessage.Data)) + return nil +} + +func (s *ServiceBusCli) SendParallelBulkTopicMessage(wg *sync.WaitGroup, topicName string, messages ...entities.MessageRequest) { + defer wg.Done() + _ = s.SendBulkTopicMessage(topicName, messages...) +} + +func (s *ServiceBusCli) SendBulkTopicMessage(topicName string, messages ...entities.MessageRequest) error { + var commonError error + logger.LogHighlight("Sending a service bus topic messages to %v topic in service bus %v", log.Info, topicName, s.Namespace.Name) + if topicName == "" { + commonError = errors.New("Topic cannot be null") + logger.Error(commonError.Error()) + return commonError + } + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + topic := s.GetTopic(topicName) + if topic == nil { + commonError = errors.New("Could not find topic " + topicName + " in service bus " + s.Namespace.Name) + logger.LogHighlight("Could not find topic %v in service bus %v", log.Error, topicName, s.Namespace.Name) + return commonError } - if label != "" { - sbMessage.Label = label + sbMessages := make([]*servicebus.Message, 0) + for _, msg := range messages { + sbMessage, err := msg.ToServiceBus() + + if err != nil { + logger.Error(err.Error()) + return err + } + sbMessages = append(sbMessages, sbMessage) } - err = topic.Send(ctx, &sbMessage) + err := topic.SendBatch(ctx, servicebus.NewMessageBatchIterator(262144, sbMessages...)) if err != nil { logger.Error(err.Error()) - os.Exit(1) + return err } - logger.LogHighlight("Service bus topic message was sent successfully to %v topic in service bus %v", log.Info, topicName, s.Namespace.Name) - logger.Info("Message:") - logger.Info(string(messageData)) + logger.LogHighlight("Service bus bulk topic messages were sent successfully to %v topic in service bus %v", log.Info, topicName, s.Namespace.Name) return nil } diff --git a/servicebus/uno.go b/servicebus/uno.go deleted file mode 100644 index aeb21bd..0000000 --- a/servicebus/uno.go +++ /dev/null @@ -1,44 +0,0 @@ -package servicebus - -import "github.com/rs/xid" - -// SetMessageForwardingTopologyProperties sets the custom message properties for the forwarding topology -func SetMessageForwardingTopologyProperties(sender string, name string, domain string, tenantID string, version string) map[string]interface{} { - if sender == "" { - sender = "GlobalOutboxSender" - } - if tenantID == "" { - tenantID = "11111111-1111-1111-1111-555555550001" - } - if version == "" { - version = "1.0" - } - - diagnosticID := xid.New().String() - - properties := map[string]interface{}{ - "X-MsgTypeVersion": version, - "X-MsgDomain": domain, - "X-MsgName": name, - "X-Sender": sender, - "X-TenantId": tenantID, - "Diagnostic-Id": diagnosticID, - } - return properties -} - -// SetMessageUnoProperties sets the custom message properties for the uno topology -func SetMessageUnoProperties(serialization string, tenantID string) map[string]interface{} { - if serialization == "" { - serialization = "1" - } - if tenantID == "" { - tenantID = "11111111-1111-1111-1111-555555550001" - } - - properties := map[string]interface{}{ - "Serialization": "1", - "TenantId": tenantID, - } - return properties -}