messagemedia_webhooks_sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +28 -0
  3. data/README.md +132 -0
  4. data/lib/message_media_webhooks.rb +39 -0
  5. data/lib/message_media_webhooks/api_helper.rb +272 -0
  6. data/lib/message_media_webhooks/configuration.rb +28 -0
  7. data/lib/message_media_webhooks/controllers/base_controller.rb +55 -0
  8. data/lib/message_media_webhooks/controllers/webhooks_controller.rb +369 -0
  9. data/lib/message_media_webhooks/exceptions/api_exception.rb +16 -0
  10. data/lib/message_media_webhooks/exceptions/create_webhook_400_response_exception.rb +25 -0
  11. data/lib/message_media_webhooks/exceptions/retrieve_webhook_400_response_exception.rb +26 -0
  12. data/lib/message_media_webhooks/exceptions/update_webhook_400_response_exception.rb +25 -0
  13. data/lib/message_media_webhooks/http/auth/basic_auth.rb +20 -0
  14. data/lib/message_media_webhooks/http/faraday_client.rb +54 -0
  15. data/lib/message_media_webhooks/http/http_call_back.rb +20 -0
  16. data/lib/message_media_webhooks/http/http_client.rb +90 -0
  17. data/lib/message_media_webhooks/http/http_context.rb +16 -0
  18. data/lib/message_media_webhooks/http/http_method_enum.rb +9 -0
  19. data/lib/message_media_webhooks/http/http_request.rb +46 -0
  20. data/lib/message_media_webhooks/http/http_response.rb +19 -0
  21. data/lib/message_media_webhooks/message_media_webhooks_client.rb +26 -0
  22. data/lib/message_media_webhooks/models/base_model.rb +32 -0
  23. data/lib/message_media_webhooks/models/create_webhook_request.rb +76 -0
  24. data/lib/message_media_webhooks/models/update_webhook_request.rb +67 -0
  25. data/test/controllers/controller_test_base.rb +30 -0
  26. data/test/controllers/test_webhooks_controller.rb +56 -0
  27. data/test/http_response_catcher.rb +16 -0
  28. data/test/test_helper.rb +91 -0
  29. metadata +155 -0
@@ -0,0 +1,28 @@
1
+
2
+
3
+ module MessageMediaWebhooks
4
+
5
+ Logging.logger.root.appenders = Logging.appenders.stdout
6
+ Logging.logger.root.level = :info
7
+
8
+ # All configuration including auth info and base URI for the API access
9
+ # are configured in this class.
10
+ class Configuration
11
+ # The base Uri for API calls
12
+ @base_uri = 'https://api.messagemedia.com'
13
+
14
+ # The username to use with basic authentication
15
+ @basic_auth_user_name = 'TODO: Replace'
16
+
17
+ # The password to use with basic authentication
18
+ @basic_auth_password = 'TODO: Replace'
19
+
20
+ # The attribute accessors for public properties.
21
+ class << self
22
+ attr_accessor :array_serialization
23
+ attr_accessor :base_uri
24
+ attr_accessor :basic_auth_user_name
25
+ attr_accessor :basic_auth_password
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,55 @@
1
+
2
+ module MessageMediaWebhooks
3
+ # Base controller.
4
+ class BaseController
5
+ attr_accessor :http_client, :http_call_back
6
+
7
+ def initialize(http_client: nil, http_call_back: nil)
8
+ @http_client = http_client || FaradayClient.new
9
+ @http_call_back = http_call_back
10
+
11
+ @global_headers = {
12
+ 'user-agent' => 'messagemedia-webhooks-ruby-sdk-1.0.0'
13
+ }
14
+ @logger = Logging.logger[self]
15
+ @logger.info("Instantiated controller class.")
16
+ end
17
+
18
+ def validate_parameters(args)
19
+ args.each do |_name, value|
20
+ if value.nil?
21
+ raise ArgumentError, "Required parameter #{_name} cannot be nil."
22
+ end
23
+ end
24
+ end
25
+
26
+ def execute_request(request, binary: false, name: nil)
27
+ @logger.info("Calling the on_before_request method of http_call_back for #{name}.") if @http_call_back
28
+ @http_call_back.on_before_request(request) if @http_call_back
29
+
30
+ @logger.info("Merging global headers with endpoint headers for #{name}.")
31
+ APIHelper.clean_hash(request.headers)
32
+ request.headers = @global_headers.clone.merge(request.headers)
33
+
34
+ @logger.debug("Raw request for #{name} is: #{request.inspect}")
35
+ response = if binary
36
+ @http_client.execute_as_binary(request)
37
+ else
38
+ @http_client.execute_as_string(request)
39
+ end
40
+ @logger.debug("Raw response for #{name} is: #{response.inspect}")
41
+ @logger.info("Wrapping request and response in a context object for #{name}.")
42
+ context = HttpContext.new(request, response)
43
+
44
+ @logger.info("Calling on_after_response method of http_call_back for #{name}.") if @http_call_back
45
+ @http_call_back.on_after_response(context) if @http_call_back
46
+
47
+ context
48
+ end
49
+
50
+ def validate_response(context)
51
+ raise APIException.new 'HTTP Response Not OK', context unless
52
+ context.response.status_code.between?(200, 208) # [200,208] = HTTP OK
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,369 @@
1
+
2
+ module MessageMediaWebhooks
3
+ # WebhooksController
4
+ class WebhooksController < BaseController
5
+ @instance = WebhooksController.new
6
+
7
+ class << self
8
+ attr_accessor :instance
9
+ end
10
+
11
+ def instance
12
+ self.class.instance
13
+ end
14
+
15
+ # Create a webhook for one or more of the specified events.
16
+ # A webhook would typically have the following structure:
17
+ # ```
18
+ # {
19
+ # "url": "http://webhook.com",
20
+ # "method": "POST",
21
+ # "encoding": "JSON",
22
+ # "headers": {
23
+ # "Account": "DeveloperPortal7000"
24
+ # },
25
+ # "events": [
26
+ # "RECEIVED_SMS"
27
+ # ],
28
+ # "template": "{\"id\":\"$mtId\",\"status\":\"$statusCode\"}"
29
+ # }
30
+ # ```
31
+ # A valid webhook must consist of the following properties:
32
+ # - ```url``` The configured URL which will trigger the webhook when a
33
+ # selected event occurs.
34
+ # - ```method``` The methods to map CRUD (create, retrieve, update, delete)
35
+ # operations to HTTP requests.
36
+ # - ```encoding``` The format in which the payload will be returned. You can
37
+ # choose from ```JSON```, ```FORM_ENCODED``` or ```XML```. This will
38
+ # automatically add the Content-Type header for you so you don't have to add
39
+ # it again in the `headers` property.
40
+ # - ```headers``` HTTP header fields which provide required information
41
+ # about the request or response, or about the object sent in the message
42
+ # body. This should not include the `Content-Type` header.
43
+ # - ```events``` Event or events that will trigger the webhook. Atleast one
44
+ # event should be present.
45
+ # - ```template``` The structure of the payload that will be returned.
46
+ # #### Types of Events
47
+ # You can select all of the events (listed below) or combine them in
48
+ # whatever way you like but atleast one event must be used. Otherwise, the
49
+ # webhook won't be created.
50
+ # A webhook will be triggered when any one or more of the events occur:
51
+ # + **SMS**
52
+ # + `RECEIVED_SMS` Receive an SMS
53
+ # + `OPT_OUT_SMS` Opt-out occured
54
+ # + **MMS**
55
+ # + `RECEIVED_MMS` Receive an MMS
56
+ # + **DR (Delivery Reports)**
57
+ # + `ENROUTE_DR` Message is enroute
58
+ # + `EXPIRED_DR` Message has expired
59
+ # + `REJECTED_DR` Message is rejected
60
+ # + `FAILED_DR` Message has failed
61
+ # + `DELIVERED_DR` Message is delivered
62
+ # + `SUBMITTED_DR` Message is submitted
63
+ # #### Template Parameters
64
+ # You can choose what to include in the data that will be sent as the
65
+ # payload via the Webhook.
66
+ # Keep in my mind, you must escape the JSON in the template value (see
67
+ # example above).
68
+ # The table illustrates a list of all the parameters that can be included in
69
+ # the template and which event types it can be applied to.
70
+ # | Data | Parameter Name | Example | Event Type |
71
+ # |:--|--|--|--|--|
72
+ # | **Service Type** | $type| `SMS` | `DR` `MO` `MO MMS` |
73
+ # | **Message ID** | $mtId, $messageId|
74
+ # `877c19ef-fa2e-4cec-827a-e1df9b5509f7` | `DR` `MO` `MO MMS`|
75
+ # | **Delivery Report ID** |$drId, $reportId|
76
+ # `01e1fa0a-6e27-4945-9cdb-18644b4de043` | `DR` |
77
+ # | **Reply ID**| $moId, $replyId| `a175e797-2b54-468b-9850-41a3eab32f74` |
78
+ # `MO` `MO MMS` |
79
+ # | **Account ID** | $accountId| `DeveloperPortal7000` | `DR` `MO` `MO MMS`
80
+ # |
81
+ # | **Message Timestamp** | $submittedTimestamp| `2016-12-07T08:43:00.850Z`
82
+ # | `DR` `MO` `MO MMS` |
83
+ # | **Provider Timestamp** | $receivedTimestamp| `2016-12-07T08:44:00.850Z`
84
+ # | `DR` `MO` `MO MMS` |
85
+ # | **Message Status** | $status| `enroute` | `DR` |
86
+ # | **Status Code** | $statusCode| `200` | `DR` |
87
+ # | **External Metadata** | $metadata.get('key')| `name` | `DR` `MO` `MO
88
+ # MMS` |
89
+ # | **Source Address**| $sourceAddress| `+61491570156` | `DR` `MO` `MO MMS`
90
+ # |
91
+ # | **Destination Address**| $destinationAddress| `+61491593156` | `MO` `MO
92
+ # MMS` |
93
+ # | **Message Content**| $mtContent, $messageContent| `Hi Derp` | `DR` `MO`
94
+ # `MO MMS` |
95
+ # | **Reply Content**| $moContent, $replyContent| `Hello Derpina` | `MO` `MO
96
+ # MMS` |
97
+ # | **Retry Count**| $retryCount| `1` | `DR` `MO` `MO MMS` |
98
+ # *Note: A 400 response will be returned if the `url` is invalid, the
99
+ # `events`, `encoding` or `method` is null or the `headers` has a
100
+ # Content-Type attribute.*
101
+ # @param [CreateWebhookRequest] body Required parameter: Example:
102
+ # @return Mixed response from the API call
103
+ def create_webhook(body)
104
+ begin
105
+ @logger.info("create_webhook called.")
106
+ # Prepare query url.
107
+ @logger.info("Preparing query URL for create_webhook.")
108
+ _query_builder = Configuration.base_uri.dup
109
+ _query_builder << '/v1/webhooks/messages'
110
+ _query_url = APIHelper.clean_url _query_builder
111
+
112
+ # Prepare headers.
113
+ @logger.info("Preparing headers for create_webhook.")
114
+ _headers = {
115
+ 'accept' => 'application/json',
116
+ 'content-type' => 'application/json; charset=utf-8'
117
+ }
118
+
119
+ # Prepare and execute HttpRequest.
120
+ @logger.info('Preparing and executing HttpRequest for create_webhook.')
121
+ _request = @http_client.post(
122
+ _query_url,
123
+ headers: _headers,
124
+ parameters: body.to_json
125
+ )
126
+ BasicAuth.apply(_request)
127
+ _context = execute_request(_request, name: 'create_webhook')
128
+
129
+ # Validate response against endpoint and global error codes.
130
+ @logger.info("Validating response for create_webhook.")
131
+ if _context.response.status_code == 400
132
+ raise CreateWebhook400ResponseException.new(
133
+ 'Unexpected error in API call. See HTTP response body for details.',
134
+ _context
135
+ )
136
+ elsif _context.response.status_code == 409
137
+ raise CreateWebhook400ResponseException.new(
138
+ 'Unexpected error in API call. See HTTP response body for details.',
139
+ _context
140
+ )
141
+ end
142
+ validate_response(_context)
143
+
144
+ # Return appropriate response type.
145
+ @logger.info("Returning response for create_webhook.")
146
+ decoded = APIHelper.json_deserialize(_context.response.raw_body) unless
147
+ _context.response.raw_body.nil? ||
148
+ _context.response.raw_body.to_s.strip.empty?
149
+ decoded
150
+
151
+ rescue Exception => e
152
+ @logger.error(e)
153
+ raise e
154
+ end
155
+ end
156
+
157
+ # Retrieve all the webhooks created for the connected account.
158
+ # A successful request to the retrieve webhook endpoint will return a
159
+ # response body as follows:
160
+ # ```
161
+ # {
162
+ # "page": 0,
163
+ # "pageSize": 100,
164
+ # "pageData": [
165
+ # {
166
+ # "url": "https://webhook.com",
167
+ # "method": "POST",
168
+ # "id": "8805c9d8-bef7-41c7-906a-69ede93aa024",
169
+ # "encoding": "JSON",
170
+ # "events": [
171
+ # "RECEIVED_SMS"
172
+ # ],
173
+ # "headers": {},
174
+ # "template": "{\"id\":\"$mtId\", \"status\":\"$statusCode\"}"
175
+ # }
176
+ # ]
177
+ # }
178
+ # ```
179
+ # *Note: Response 400 is returned when the `page` query parameter is not
180
+ # valid or the `pageSize` query parameter is not valid.*
181
+ # @param [Integer] page Optional parameter: Example:
182
+ # @param [Integer] page_size Optional parameter: Example:
183
+ # @return Mixed response from the API call
184
+ def retrieve_webhook(page = nil,
185
+ page_size = nil)
186
+ begin
187
+ @logger.info("retrieve_webhook called.")
188
+ # Prepare query url.
189
+ @logger.info("Preparing query URL for retrieve_webhook.")
190
+ _query_builder = Configuration.base_uri.dup
191
+ _query_builder << '/v1/webhooks/messages/'
192
+ _query_builder = APIHelper.append_url_with_query_parameters(
193
+ _query_builder,
194
+ {
195
+ 'page' => page,
196
+ 'pageSize' => page_size
197
+ },
198
+ array_serialization: Configuration.array_serialization
199
+ )
200
+ _query_url = APIHelper.clean_url _query_builder
201
+
202
+ # Prepare headers.
203
+ @logger.info("Preparing headers for retrieve_webhook.")
204
+ _headers = {
205
+ 'accept' => 'application/json'
206
+ }
207
+
208
+ # Prepare and execute HttpRequest.
209
+ @logger.info('Preparing and executing HttpRequest for retrieve_webhook.')
210
+ _request = @http_client.get(
211
+ _query_url,
212
+ headers: _headers
213
+ )
214
+ BasicAuth.apply(_request)
215
+ _context = execute_request(_request, name: 'retrieve_webhook')
216
+
217
+ # Validate response against endpoint and global error codes.
218
+ @logger.info("Validating response for retrieve_webhook.")
219
+ if _context.response.status_code == 400
220
+ raise RetrieveWebhook400ResponseException.new(
221
+ 'Unexpected error in API call. See HTTP response body for details.',
222
+ _context
223
+ )
224
+ end
225
+ validate_response(_context)
226
+
227
+ # Return appropriate response type.
228
+ @logger.info("Returning response for retrieve_webhook.")
229
+ decoded = APIHelper.json_deserialize(_context.response.raw_body) unless
230
+ _context.response.raw_body.nil? ||
231
+ _context.response.raw_body.to_s.strip.empty?
232
+ decoded
233
+
234
+ rescue Exception => e
235
+ @logger.error(e)
236
+ raise e
237
+ end
238
+ end
239
+
240
+ # Delete a webhook that was previously created for the connected account.
241
+ # A webhook can be cancelled by appending the UUID of the webhook to the
242
+ # endpoint and submitting a DELETE request to the /webhooks/messages
243
+ # endpoint.
244
+ # *Note: Only pre-created webhooks can be deleted. If an invalid or non
245
+ # existent webhook ID parameter is specified in the request, then a HTTP 404
246
+ # Not Found response will be returned.*
247
+ # @param [UUID | String] webhook_id Required parameter: Example:
248
+ # @return void response from the API call
249
+ def delete_webhook(webhook_id)
250
+ begin
251
+ @logger.info("delete_webhook called.")
252
+ # Prepare query url.
253
+ @logger.info("Preparing query URL for delete_webhook.")
254
+ _query_builder = Configuration.base_uri.dup
255
+ _query_builder << '/v1/webhooks/messages/{webhookId}'
256
+ _query_builder = APIHelper.append_url_with_template_parameters(
257
+ _query_builder,
258
+ 'webhookId' => webhook_id
259
+ )
260
+ _query_url = APIHelper.clean_url _query_builder
261
+
262
+ # Prepare and execute HttpRequest.
263
+ @logger.info('Preparing and executing HttpRequest for delete_webhook.')
264
+ _request = @http_client.delete(
265
+ _query_url
266
+ )
267
+ BasicAuth.apply(_request)
268
+ _context = execute_request(_request, name: 'delete_webhook')
269
+
270
+ # Validate response against endpoint and global error codes.
271
+ @logger.info("Validating response for delete_webhook.")
272
+ if _context.response.status_code == 404
273
+ raise APIException.new(
274
+ '',
275
+ _context
276
+ )
277
+ end
278
+ validate_response(_context)
279
+
280
+ rescue Exception => e
281
+ @logger.error(e)
282
+ raise e
283
+ end
284
+ end
285
+
286
+ # Update a webhook. You can update individual attributes or all of them by
287
+ # submitting a PATCH request to the /webhooks/messages endpoint (the same
288
+ # endpoint used above to delete a webhook)
289
+ # A successful request to the retrieve webhook endpoint will return a
290
+ # response body as follows:
291
+ # ```
292
+ # {
293
+ # "url": "https://webhook.com",
294
+ # "method": "POST",
295
+ # "id": "04442623-0961-464e-9cbc-ec50804e0413",
296
+ # "encoding": "JSON",
297
+ # "events": [
298
+ # "RECEIVED_SMS"
299
+ # ],
300
+ # "headers": {},
301
+ # "template": "{\"id\":\"$mtId\", \"status\":\"$statusCode\"}"
302
+ # }
303
+ # ```
304
+ # *Note: Only pre-created webhooks can be deleted. If an invalid or non
305
+ # existent webhook ID parameter is specified in the request, then a HTTP 404
306
+ # Not Found response will be returned.*
307
+ # @param [UUID | String] webhook_id Required parameter: Example:
308
+ # @param [UpdateWebhookRequest] body Required parameter: Example:
309
+ # @return Mixed response from the API call
310
+ def update_webhook(webhook_id,
311
+ body)
312
+ begin
313
+ @logger.info("update_webhook called.")
314
+ # Prepare query url.
315
+ @logger.info("Preparing query URL for update_webhook.")
316
+ _query_builder = Configuration.base_uri.dup
317
+ _query_builder << '/v1/webhooks/messages/{webhookId}'
318
+ _query_builder = APIHelper.append_url_with_template_parameters(
319
+ _query_builder,
320
+ 'webhookId' => webhook_id
321
+ )
322
+ _query_url = APIHelper.clean_url _query_builder
323
+
324
+ # Prepare headers.
325
+ @logger.info("Preparing headers for update_webhook.")
326
+ _headers = {
327
+ 'accept' => 'application/json',
328
+ 'content-type' => 'application/json; charset=utf-8'
329
+ }
330
+
331
+ # Prepare and execute HttpRequest.
332
+ @logger.info('Preparing and executing HttpRequest for update_webhook.')
333
+ _request = @http_client.patch(
334
+ _query_url,
335
+ headers: _headers,
336
+ parameters: body.to_json
337
+ )
338
+ BasicAuth.apply(_request)
339
+ _context = execute_request(_request, name: 'update_webhook')
340
+
341
+ # Validate response against endpoint and global error codes.
342
+ @logger.info("Validating response for update_webhook.")
343
+ if _context.response.status_code == 400
344
+ raise UpdateWebhook400ResponseException.new(
345
+ 'Unexpected error in API call. See HTTP response body for details.',
346
+ _context
347
+ )
348
+ elsif _context.response.status_code == 404
349
+ raise APIException.new(
350
+ '',
351
+ _context
352
+ )
353
+ end
354
+ validate_response(_context)
355
+
356
+ # Return appropriate response type.
357
+ @logger.info("Returning response for update_webhook.")
358
+ decoded = APIHelper.json_deserialize(_context.response.raw_body) unless
359
+ _context.response.raw_body.nil? ||
360
+ _context.response.raw_body.to_s.strip.empty?
361
+ decoded
362
+
363
+ rescue Exception => e
364
+ @logger.error(e)
365
+ raise e
366
+ end
367
+ end
368
+ end
369
+ end