force 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (151) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +96 -0
  3. data/Gemfile +11 -0
  4. data/Gemfile.lock +107 -0
  5. data/Guardfile +8 -0
  6. data/LICENSE +22 -0
  7. data/README.md +421 -0
  8. data/Rakefile +10 -0
  9. data/coverage/assets/0.7.1/application.css +1110 -0
  10. data/coverage/assets/0.7.1/application.js +626 -0
  11. data/coverage/assets/0.7.1/fancybox/blank.gif +0 -0
  12. data/coverage/assets/0.7.1/fancybox/fancy_close.png +0 -0
  13. data/coverage/assets/0.7.1/fancybox/fancy_loading.png +0 -0
  14. data/coverage/assets/0.7.1/fancybox/fancy_nav_left.png +0 -0
  15. data/coverage/assets/0.7.1/fancybox/fancy_nav_right.png +0 -0
  16. data/coverage/assets/0.7.1/fancybox/fancy_shadow_e.png +0 -0
  17. data/coverage/assets/0.7.1/fancybox/fancy_shadow_n.png +0 -0
  18. data/coverage/assets/0.7.1/fancybox/fancy_shadow_ne.png +0 -0
  19. data/coverage/assets/0.7.1/fancybox/fancy_shadow_nw.png +0 -0
  20. data/coverage/assets/0.7.1/fancybox/fancy_shadow_s.png +0 -0
  21. data/coverage/assets/0.7.1/fancybox/fancy_shadow_se.png +0 -0
  22. data/coverage/assets/0.7.1/fancybox/fancy_shadow_sw.png +0 -0
  23. data/coverage/assets/0.7.1/fancybox/fancy_shadow_w.png +0 -0
  24. data/coverage/assets/0.7.1/fancybox/fancy_title_left.png +0 -0
  25. data/coverage/assets/0.7.1/fancybox/fancy_title_main.png +0 -0
  26. data/coverage/assets/0.7.1/fancybox/fancy_title_over.png +0 -0
  27. data/coverage/assets/0.7.1/fancybox/fancy_title_right.png +0 -0
  28. data/coverage/assets/0.7.1/fancybox/fancybox-x.png +0 -0
  29. data/coverage/assets/0.7.1/fancybox/fancybox-y.png +0 -0
  30. data/coverage/assets/0.7.1/fancybox/fancybox.png +0 -0
  31. data/coverage/assets/0.7.1/favicon_green.png +0 -0
  32. data/coverage/assets/0.7.1/favicon_red.png +0 -0
  33. data/coverage/assets/0.7.1/favicon_yellow.png +0 -0
  34. data/coverage/assets/0.7.1/loading.gif +0 -0
  35. data/coverage/assets/0.7.1/magnify.png +0 -0
  36. data/coverage/assets/0.7.1/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  37. data/coverage/assets/0.7.1/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  38. data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  39. data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  40. data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  41. data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  42. data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  43. data/coverage/assets/0.7.1/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  44. data/coverage/assets/0.7.1/smoothness/images/ui-icons_222222_256x240.png +0 -0
  45. data/coverage/assets/0.7.1/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  46. data/coverage/assets/0.7.1/smoothness/images/ui-icons_454545_256x240.png +0 -0
  47. data/coverage/assets/0.7.1/smoothness/images/ui-icons_888888_256x240.png +0 -0
  48. data/coverage/assets/0.7.1/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  49. data/coverage/index.html +19808 -0
  50. data/force.gemspec +27 -0
  51. data/lib/force.rb +74 -0
  52. data/lib/force/abstract_client.rb +9 -0
  53. data/lib/force/attachment.rb +21 -0
  54. data/lib/force/client.rb +3 -0
  55. data/lib/force/collection.rb +45 -0
  56. data/lib/force/concerns/api.rb +321 -0
  57. data/lib/force/concerns/authentication.rb +39 -0
  58. data/lib/force/concerns/base.rb +59 -0
  59. data/lib/force/concerns/caching.rb +24 -0
  60. data/lib/force/concerns/canvas.rb +10 -0
  61. data/lib/force/concerns/connection.rb +74 -0
  62. data/lib/force/concerns/picklists.rb +87 -0
  63. data/lib/force/concerns/streaming.rb +31 -0
  64. data/lib/force/concerns/verbs.rb +67 -0
  65. data/lib/force/config.rb +140 -0
  66. data/lib/force/data/client.rb +18 -0
  67. data/lib/force/mash.rb +66 -0
  68. data/lib/force/middleware.rb +27 -0
  69. data/lib/force/middleware/authentication.rb +73 -0
  70. data/lib/force/middleware/authentication/password.rb +17 -0
  71. data/lib/force/middleware/authentication/token.rb +15 -0
  72. data/lib/force/middleware/authorization.rb +15 -0
  73. data/lib/force/middleware/caching.rb +22 -0
  74. data/lib/force/middleware/gzip.rb +31 -0
  75. data/lib/force/middleware/instance_url.rb +14 -0
  76. data/lib/force/middleware/logger.rb +40 -0
  77. data/lib/force/middleware/mashify.rb +16 -0
  78. data/lib/force/middleware/multipart.rb +55 -0
  79. data/lib/force/middleware/raise_error.rb +25 -0
  80. data/lib/force/signed_request.rb +48 -0
  81. data/lib/force/sobject.rb +68 -0
  82. data/lib/force/tooling/client.rb +11 -0
  83. data/lib/force/upload_io.rb +20 -0
  84. data/lib/force/version.rb +3 -0
  85. data/spec/fixtures/auth_error_response.json +4 -0
  86. data/spec/fixtures/auth_success_response.json +7 -0
  87. data/spec/fixtures/blob.jpg +0 -0
  88. data/spec/fixtures/expired_session_response.json +6 -0
  89. data/spec/fixtures/reauth_success_response.json +7 -0
  90. data/spec/fixtures/refresh_error_response.json +4 -0
  91. data/spec/fixtures/refresh_success_response.json +7 -0
  92. data/spec/fixtures/services_data_success_response.json +12 -0
  93. data/spec/fixtures/sobject/create_success_response.json +5 -0
  94. data/spec/fixtures/sobject/delete_error_response.json +1 -0
  95. data/spec/fixtures/sobject/describe_sobjects_success_response.json +31 -0
  96. data/spec/fixtures/sobject/list_sobjects_success_response.json +31 -0
  97. data/spec/fixtures/sobject/org_query_response.json +11 -0
  98. data/spec/fixtures/sobject/query_aggregate_success_response.json +23 -0
  99. data/spec/fixtures/sobject/query_empty_response.json +5 -0
  100. data/spec/fixtures/sobject/query_error_response.json +6 -0
  101. data/spec/fixtures/sobject/query_paginated_first_page_response.json +14 -0
  102. data/spec/fixtures/sobject/query_paginated_last_page_response.json +13 -0
  103. data/spec/fixtures/sobject/query_success_response.json +38 -0
  104. data/spec/fixtures/sobject/recent_success_response.json +18 -0
  105. data/spec/fixtures/sobject/search_error_response.json +6 -0
  106. data/spec/fixtures/sobject/search_success_response.json +16 -0
  107. data/spec/fixtures/sobject/sobject_describe_error_response.json +6 -0
  108. data/spec/fixtures/sobject/sobject_describe_success_response.json +1429 -0
  109. data/spec/fixtures/sobject/sobject_find_error_response.json +6 -0
  110. data/spec/fixtures/sobject/sobject_find_success_response.json +29 -0
  111. data/spec/fixtures/sobject/upsert_created_success_response.json +5 -0
  112. data/spec/fixtures/sobject/upsert_error_response.json +6 -0
  113. data/spec/fixtures/sobject/upsert_multiple_error_response.json +4 -0
  114. data/spec/fixtures/sobject/upsert_updated_success_response.json +0 -0
  115. data/spec/fixtures/sobject/write_error_response.json +6 -0
  116. data/spec/integration/abstract_client_spec.rb +306 -0
  117. data/spec/integration/data/client_spec.rb +90 -0
  118. data/spec/spec_helper.rb +20 -0
  119. data/spec/support/client_integration.rb +45 -0
  120. data/spec/support/concerns.rb +18 -0
  121. data/spec/support/event_machine.rb +14 -0
  122. data/spec/support/fixture_helpers.rb +45 -0
  123. data/spec/support/matchers.rb +11 -0
  124. data/spec/support/middleware.rb +76 -0
  125. data/spec/support/mock_cache.rb +13 -0
  126. data/spec/unit/abstract_client_spec.rb +11 -0
  127. data/spec/unit/attachment_spec.rb +15 -0
  128. data/spec/unit/collection_spec.rb +52 -0
  129. data/spec/unit/concerns/api_spec.rb +244 -0
  130. data/spec/unit/concerns/authentication_spec.rb +98 -0
  131. data/spec/unit/concerns/base_spec.rb +42 -0
  132. data/spec/unit/concerns/caching_spec.rb +29 -0
  133. data/spec/unit/concerns/canvas_spec.rb +30 -0
  134. data/spec/unit/concerns/connection_spec.rb +22 -0
  135. data/spec/unit/config_spec.rb +99 -0
  136. data/spec/unit/data/client_spec.rb +10 -0
  137. data/spec/unit/mash_spec.rb +36 -0
  138. data/spec/unit/middleware/authentication/password_spec.rb +31 -0
  139. data/spec/unit/middleware/authentication/token_spec.rb +24 -0
  140. data/spec/unit/middleware/authentication_spec.rb +67 -0
  141. data/spec/unit/middleware/authorization_spec.rb +11 -0
  142. data/spec/unit/middleware/gzip_spec.rb +66 -0
  143. data/spec/unit/middleware/instance_url_spec.rb +24 -0
  144. data/spec/unit/middleware/logger_spec.rb +19 -0
  145. data/spec/unit/middleware/mashify_spec.rb +11 -0
  146. data/spec/unit/middleware/raise_error_spec.rb +32 -0
  147. data/spec/unit/signed_request_spec.rb +24 -0
  148. data/spec/unit/sobject_spec.rb +86 -0
  149. data/spec/unit/tooling/client_spec.rb +7 -0
  150. data/tmp/rspec_guard_result +1 -0
  151. metadata +383 -0
@@ -0,0 +1,48 @@
1
+ require 'openssl'
2
+ require 'base64'
3
+ require 'json'
4
+
5
+ module Force
6
+ class SignedRequest
7
+ # Public: Initializes and decodes the signed request
8
+ #
9
+ # signed_request - The POST message containing the signed request from Salesforce.
10
+ # client_secret - The oauth client secret used to encrypt the signed request.
11
+ #
12
+ # Returns the parsed JSON context.
13
+ def self.decode(signed_request, client_secret)
14
+ new(signed_request, client_secret).decode
15
+ end
16
+
17
+ def initialize(signed_request, client_secret)
18
+ @client_secret = client_secret
19
+ split_components(signed_request)
20
+ end
21
+
22
+ # Public: Decode the signed request.
23
+ #
24
+ # Returns the parsed JSON context.
25
+ # Returns nil if the signed request is invalid.
26
+ def decode
27
+ return nil if signature != hmac
28
+ JSON.parse(Base64.decode64(payload))
29
+ end
30
+
31
+ private
32
+
33
+ attr_reader :client_secret, :signature, :payload
34
+
35
+ def split_components(signed_request)
36
+ @signature, @payload = signed_request.split('.')
37
+ @signature = Base64.decode64(@signature)
38
+ end
39
+
40
+ def hmac
41
+ OpenSSL::HMAC.digest(digest, client_secret, payload)
42
+ end
43
+
44
+ def digest
45
+ OpenSSL::Digest::Digest.new('sha256')
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,68 @@
1
+ module Force
2
+ class SObject < Force::Mash
3
+
4
+ def sobject_type
5
+ self.attributes['type']
6
+ end
7
+
8
+ # Public: Get the describe for this sobject type
9
+ def describe
10
+ @client.describe(sobject_type)
11
+ end
12
+
13
+ # Public: Describe layouts for this sobject type
14
+ def describe_layouts(layout_id = nil)
15
+ @client.describe_layouts(sobject_type, layout_id)
16
+ end
17
+
18
+ # Public: Persist the attributes to Salesforce.
19
+ #
20
+ # Examples
21
+ #
22
+ # account = client.query('select Id, Name from Account').first
23
+ # account.Name = 'Foobar'
24
+ # account.save
25
+ def save
26
+ ensure_id
27
+ @client.update(sobject_type, attrs)
28
+ end
29
+
30
+ def save!
31
+ ensure_id
32
+ @client.update!(sobject_type, attrs)
33
+ end
34
+
35
+ # Public: Destroy this record.
36
+ #
37
+ # Examples
38
+ #
39
+ # account = client.query('select Id, Name from Account').first
40
+ # account.destroy
41
+ def destroy
42
+ ensure_id
43
+ @client.destroy(sobject_type, self.Id)
44
+ end
45
+
46
+ def destroy!
47
+ ensure_id
48
+ @client.destroy!(sobject_type, self.Id)
49
+ end
50
+
51
+ # Public: Returns a hash representation of this object with the attributes
52
+ # key and parent/child relationships removed.
53
+ def attrs
54
+ self.to_hash.reject { |key, _| key =~ /.*__r/ || key =~ /^attributes$/ }
55
+ end
56
+
57
+ def to_sparam
58
+ self.Id
59
+ end
60
+
61
+ private
62
+
63
+ def ensure_id
64
+ return true if self.Id?
65
+ raise ArgumentError, 'You need to query the Id for the record first.'
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,11 @@
1
+ module Force
2
+ module Tooling
3
+ class Client < AbstractClient
4
+ private
5
+
6
+ def api_path(path)
7
+ super("tooling/#{path}")
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,20 @@
1
+ require 'faraday/upload_io'
2
+
3
+ module Force
4
+ UploadIO = Faraday::UploadIO
5
+ end
6
+
7
+ module Faraday
8
+ module Parts
9
+ class ParamPart
10
+ def build_part(boundary, name, value)
11
+ part = ''
12
+ part << "--#{boundary}\r\n"
13
+ part << "Content-Disposition: form-data; name=\"#{name.to_s}\";\r\n"
14
+ part << "Content-Type: application/json\r\n"
15
+ part << "\r\n"
16
+ part << "#{value}\r\n"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ module Force
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,4 @@
1
+ {
2
+ "error": "invalid_grant",
3
+ "error_description": "authentication failure - Invalid Password"
4
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "id": "https://login.salesforce.com/id/00Dx0000000BV7z/005x00000012Q9P",
3
+ "issued_at": "1278448832702",
4
+ "instance_url": "https://na1.salesforce.com",
5
+ "signature": "0CmxinZir53Yex7nE0TD+zMpvIWYGb/bdJh6XfOH6EQ=",
6
+ "access_token": "00Dx0000000BV7z!AR8AQAxo9UfVkh8AlV0Gomt9Czx9LjHnSSpwBMmbRcgKFmxOtvxjTrKW19ye6PE3Ds1eQz3z8jr3W7_VbWmEu4Q8TVGSTHxs"
7
+ }
Binary file
@@ -0,0 +1,6 @@
1
+ [
2
+ {
3
+ "message": "Session expired or invalid",
4
+ "errorCode": "INVALID_SESSION_ID"
5
+ }
6
+ ]
@@ -0,0 +1,7 @@
1
+ {
2
+ "id": "https://login.salesforce.com/id/foo/bar",
3
+ "issued_at": "1309974610026",
4
+ "instance_url": "https://na1.salesforce.com",
5
+ "signature": "sig=",
6
+ "access_token": "new_access_token"
7
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "error": "invalid_grant",
3
+ "error_description": "expired access/refresh token"
4
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "id": "https://login.salesforce.com/id/foo/bar",
3
+ "issued_at": "1309974610026",
4
+ "instance_url": "https://na1.salesforce.com",
5
+ "signature": "sig=",
6
+ "access_token": "refreshed_access_token"
7
+ }
@@ -0,0 +1,12 @@
1
+ [
2
+ {
3
+ "version": "20.0",
4
+ "url": "/services/data/v20.0",
5
+ "label": "Winter '11"
6
+ },
7
+ {
8
+ "version": "100",
9
+ "url": "/services/data/v100",
10
+ "label": "Spring '86"
11
+ }
12
+ ]
@@ -0,0 +1,5 @@
1
+ {
2
+ "id" : "some_id",
3
+ "errors" : [ ],
4
+ "success" : true
5
+ }
@@ -0,0 +1 @@
1
+ [{"message":"Provided external ID field does not exist or is not accessible: rid","errorCode":"NOT_FOUND"}]
@@ -0,0 +1,31 @@
1
+ {
2
+ "encoding" : "UTF-8",
3
+ "maxBatchSize" : 200,
4
+ "sobjects" : [ {
5
+ "name" : "Account",
6
+ "label" : "Account",
7
+ "custom" : false,
8
+ "keyPrefix" : "001",
9
+ "labelPlural" : "Accounts",
10
+ "layoutable" : true,
11
+ "activateable" : false,
12
+ "updateable" : true,
13
+ "urls" : {
14
+ "sobject" : "/services/data/v23.0/sobjects/Account",
15
+ "describe" : "/services/data/v23.0/sobjects/Account/describe",
16
+ "rowTemplate" : "/services/data/v23.0/sobjects/Account/{ID}"
17
+ },
18
+ "searchable" : true,
19
+ "createable" : true,
20
+ "customSetting" : false,
21
+ "deletable" : true,
22
+ "deprecatedAndHidden" : false,
23
+ "feedEnabled" : true,
24
+ "mergeable" : true,
25
+ "queryable" : true,
26
+ "replicateable" : true,
27
+ "retrieveable" : true,
28
+ "undeletable" : true,
29
+ "triggerable" : true
30
+ }]
31
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "encoding" : "UTF-8",
3
+ "maxBatchSize" : 200,
4
+ "sobjects" : [ {
5
+ "name" : "Account",
6
+ "label" : "Account",
7
+ "custom" : false,
8
+ "keyPrefix" : "001",
9
+ "labelPlural" : "Accounts",
10
+ "layoutable" : true,
11
+ "activateable" : false,
12
+ "updateable" : true,
13
+ "urls" : {
14
+ "sobject" : "/services/data/v23.0/sobjects/Account",
15
+ "describe" : "/services/data/v23.0/sobjects/Account/describe",
16
+ "rowTemplate" : "/services/data/v23.0/sobjects/Account/{ID}"
17
+ },
18
+ "searchable" : true,
19
+ "createable" : true,
20
+ "customSetting" : false,
21
+ "deletable" : true,
22
+ "deprecatedAndHidden" : false,
23
+ "feedEnabled" : true,
24
+ "mergeable" : true,
25
+ "queryable" : true,
26
+ "replicateable" : true,
27
+ "retrieveable" : true,
28
+ "undeletable" : true,
29
+ "triggerable" : true
30
+ }]
31
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "totalSize" : 1,
3
+ "done" : true,
4
+ "records" : [ {
5
+ "attributes" : {
6
+ "type" : "Organization",
7
+ "url" : "/services/data/v20.0/sobjects/Organization/00Dx0000000BV7z"
8
+ },
9
+ "Id" : "00Dx0000000BV7z"
10
+ } ]
11
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "totalSize" : 3,
3
+ "done" : true,
4
+ "records" : [ {
5
+ "attributes" : {
6
+ "type" : "AggregateResult"
7
+ },
8
+ "CampaignId" : "701E0000000JuFHIA0",
9
+ "expr0" : 300.0
10
+ }, {
11
+ "attributes" : {
12
+ "type" : "AggregateResult"
13
+ },
14
+ "CampaignId" : "701E00000005ZqAIAU",
15
+ "expr0" : 100.0
16
+ }, {
17
+ "attributes" : {
18
+ "type" : "AggregateResult"
19
+ },
20
+ "CampaignId" : null,
21
+ "expr0" : 400
22
+ } ]
23
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "totalSize" : 0,
3
+ "done" : true,
4
+ "records" : [ ]
5
+ }
@@ -0,0 +1,6 @@
1
+ [
2
+ {
3
+ "message": "error_message",
4
+ "errorCode": "INVALID_FIELD"
5
+ }
6
+ ]
@@ -0,0 +1,14 @@
1
+ {
2
+ "totalSize" : 2,
3
+ "done" : false,
4
+ "nextRecordsUrl" : "/services/data/v26.0/query/01gD",
5
+ "records" : [
6
+ {
7
+ "attributes" : {
8
+ "type" : "Whizbang",
9
+ "url" : "/services/data/v20.0/sobjects/Whizbang/foo"
10
+ },
11
+ "Text_Label" : "First Page"
12
+ }
13
+ ]
14
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "totalSize" : 2,
3
+ "done" : true,
4
+ "records" : [
5
+ {
6
+ "attributes" : {
7
+ "type" : "Whizbang",
8
+ "url" : "/services/data/v20.0/sobjects/Whizbang/foo"
9
+ },
10
+ "Text_Label" : "Last Page"
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "totalSize": 1,
3
+ "done": true,
4
+ "records": [
5
+ {
6
+ "attributes": {
7
+ "type": "Whizbang",
8
+ "url": "/services/data/v20.0/sobjects/Whizbang/foo"
9
+ },
10
+ "Checkbox_Label": false,
11
+ "Text_Label": "Hi there!",
12
+ "Date_Label": "2010-01-01",
13
+ "DateTime_Label": "2011-07-07T00:37:00.000+0000",
14
+ "Picklist_Multiselect_Label": "four;six",
15
+ "ParentWhizbang__r": {
16
+ "Name": "Parent Whizbang",
17
+ "Text_Label": "Hello",
18
+ "attributes": {
19
+ "type": "Whizbang",
20
+ "url": "/services/data/v20.0/sobjects/Whizbang/bar"
21
+ }
22
+ },
23
+ "Whizbangs__r": {
24
+ "totalSize": 1,
25
+ "done": true,
26
+ "records": [
27
+ {
28
+ "attributes": {
29
+ "type": "Whizbang__c",
30
+ "url": "/services/data/v24.0/sobjects/Whizbang__c/a00E0000004D5lsIAC"
31
+ },
32
+ "Name": "Child Whizbang"
33
+ }
34
+ ]
35
+ }
36
+ }
37
+ ]
38
+ }
@@ -0,0 +1,18 @@
1
+ [
2
+ {
3
+ "attributes": {
4
+ "type": "Whizbang",
5
+ "url": "/services/data/v23.0/sobjects/Whizbang/foo"
6
+ },
7
+ "Id": "foo",
8
+ "Name": "whatever"
9
+ },
10
+ {
11
+ "attributes": {
12
+ "type": "Whizbang",
13
+ "url": "/services/data/v23.0/sobjects/Whizbang/bar"
14
+ },
15
+ "Id": "bar",
16
+ "Name": "whatever"
17
+ }
18
+ ]
@@ -0,0 +1,6 @@
1
+ [
2
+ {
3
+ "message": "No search term found. The search term must be enclosed in braces.",
4
+ "errorCode": "MALFORMED_SEARCH"
5
+ }
6
+ ]