lhc 0.2.1

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 (107) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +36 -0
  3. data/Gemfile +11 -0
  4. data/README.md +116 -0
  5. data/Rakefile +25 -0
  6. data/docs/configuration.md +57 -0
  7. data/docs/exceptions.md +68 -0
  8. data/docs/interceptors.md +90 -0
  9. data/docs/request.md +24 -0
  10. data/docs/response.md +19 -0
  11. data/lhc.gemspec +30 -0
  12. data/lib/lhc.rb +16 -0
  13. data/lib/lhc/concerns/lhc/basic_methods.rb +42 -0
  14. data/lib/lhc/config.rb +45 -0
  15. data/lib/lhc/endpoint.rb +53 -0
  16. data/lib/lhc/error.rb +63 -0
  17. data/lib/lhc/errors/client_error.rb +73 -0
  18. data/lib/lhc/errors/server_error.rb +28 -0
  19. data/lib/lhc/errors/timeout.rb +4 -0
  20. data/lib/lhc/errors/unknown_error.rb +4 -0
  21. data/lib/lhc/interceptor.rb +9 -0
  22. data/lib/lhc/interceptor_processor.rb +24 -0
  23. data/lib/lhc/request.rb +91 -0
  24. data/lib/lhc/response.rb +52 -0
  25. data/lib/lhc/version.rb +3 -0
  26. data/script/ci/build.sh +19 -0
  27. data/spec/basic_methods/delete_spec.rb +34 -0
  28. data/spec/basic_methods/get_spec.rb +37 -0
  29. data/spec/basic_methods/post_spec.rb +42 -0
  30. data/spec/basic_methods/put_spec.rb +48 -0
  31. data/spec/basic_methods/request_spec.rb +19 -0
  32. data/spec/config/endpoints_spec.rb +49 -0
  33. data/spec/config/placeholders_spec.rb +32 -0
  34. data/spec/dummy/README.rdoc +28 -0
  35. data/spec/dummy/Rakefile +6 -0
  36. data/spec/dummy/app/assets/images/.keep +0 -0
  37. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  38. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  39. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  40. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  41. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  42. data/spec/dummy/app/mailers/.keep +0 -0
  43. data/spec/dummy/app/models/.keep +0 -0
  44. data/spec/dummy/app/models/concerns/.keep +0 -0
  45. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  46. data/spec/dummy/bin/bundle +3 -0
  47. data/spec/dummy/bin/rails +4 -0
  48. data/spec/dummy/bin/rake +4 -0
  49. data/spec/dummy/config.ru +4 -0
  50. data/spec/dummy/config/application.rb +14 -0
  51. data/spec/dummy/config/boot.rb +5 -0
  52. data/spec/dummy/config/environment.rb +5 -0
  53. data/spec/dummy/config/environments/development.rb +34 -0
  54. data/spec/dummy/config/environments/production.rb +75 -0
  55. data/spec/dummy/config/environments/test.rb +39 -0
  56. data/spec/dummy/config/initializers/assets.rb +8 -0
  57. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  58. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  59. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  60. data/spec/dummy/config/initializers/inflections.rb +16 -0
  61. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  62. data/spec/dummy/config/initializers/session_store.rb +3 -0
  63. data/spec/dummy/config/initializers/wrap_parameters.rb +9 -0
  64. data/spec/dummy/config/locales/en.yml +23 -0
  65. data/spec/dummy/config/routes.rb +56 -0
  66. data/spec/dummy/config/secrets.yml +22 -0
  67. data/spec/dummy/lib/assets/.keep +0 -0
  68. data/spec/dummy/log/.keep +0 -0
  69. data/spec/dummy/public/404.html +67 -0
  70. data/spec/dummy/public/422.html +67 -0
  71. data/spec/dummy/public/500.html +66 -0
  72. data/spec/dummy/public/favicon.ico +0 -0
  73. data/spec/endpoint/compile_spec.rb +25 -0
  74. data/spec/endpoint/placeholders_spec.rb +14 -0
  75. data/spec/endpoint/remove_interpolated_params_spec.rb +16 -0
  76. data/spec/error/find_spec.rb +56 -0
  77. data/spec/error/response_spec.rb +17 -0
  78. data/spec/error/timeout_spec.rb +14 -0
  79. data/spec/interceptors/after_request_spec.rb +21 -0
  80. data/spec/interceptors/after_response_spec.rb +42 -0
  81. data/spec/interceptors/before_request_spec.rb +21 -0
  82. data/spec/interceptors/before_response_spec.rb +21 -0
  83. data/spec/interceptors/default_interceptors_spec.rb +15 -0
  84. data/spec/interceptors/define_spec.rb +29 -0
  85. data/spec/interceptors/response_competition_spec.rb +40 -0
  86. data/spec/interceptors/return_response_spec.rb +39 -0
  87. data/spec/rails_helper.rb +4 -0
  88. data/spec/request/error_handling_spec.rb +52 -0
  89. data/spec/request/headers_spec.rb +11 -0
  90. data/spec/request/option_dup_spec.rb +12 -0
  91. data/spec/request/parallel_requests_spec.rb +15 -0
  92. data/spec/request/url_patterns_spec.rb +19 -0
  93. data/spec/response/body_spec.rb +16 -0
  94. data/spec/response/code_spec.rb +16 -0
  95. data/spec/response/data_spec.rb +18 -0
  96. data/spec/response/headers_spec.rb +18 -0
  97. data/spec/response/success_spec.rb +12 -0
  98. data/spec/response/time_spec.rb +16 -0
  99. data/spec/spec_helper.rb +4 -0
  100. data/spec/support/fixtures/json/feedback.json +11 -0
  101. data/spec/support/fixtures/json/feedbacks.json +164 -0
  102. data/spec/support/fixtures/json/localina_content_ad.json +23 -0
  103. data/spec/support/load_json.rb +3 -0
  104. data/spec/support/reset_config.rb +7 -0
  105. data/spec/timeouts/no_signal_spec.rb +13 -0
  106. data/spec/timeouts/timings_spec.rb +59 -0
  107. metadata +313 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bac9f0ada28e8054aa6f8e01de35451970dd478b
4
+ data.tar.gz: b457597aba0d084e762f599b8a42680c2126cc47
5
+ SHA512:
6
+ metadata.gz: 076b39d8fc0003520cd64ae221bc7f7efaf2b671a684699b3092566065f3490a85d54464447576179460715934b6350cc8cc0c8a57bf43cc2a7876ab745594fc
7
+ data.tar.gz: 6cb6e105b87af256708c9552a13aa1b935e59e500535bbb77197ba7e3a402ffd2f45fc1fdd84f3dc4c0b8ce67f3c9c6ead3dc09195f3ca7b99223a42e52b63c4
data/.gitignore ADDED
@@ -0,0 +1,36 @@
1
+ *.rbc
2
+ capybara-*.html
3
+ .rspec
4
+ .DS_Store
5
+ /log
6
+ /tmp
7
+ /db/*.sqlite3
8
+ /public/system
9
+ /coverage/
10
+ /spec/tmp
11
+ **.orig
12
+ rerun.txt
13
+ pickle-email-*.html
14
+ *.log
15
+ pkg/
16
+
17
+ # TODO Comment out these rules if you are OK with secrets being uploaded to the repo
18
+ config/initializers/secret_token.rb
19
+ config/secrets.yml
20
+
21
+ ## Environment normalisation:
22
+ /.bundle
23
+ /vendor/bundle
24
+
25
+ # these should all be checked in to normalise the environment:
26
+ Gemfile.lock
27
+ .ruby-version
28
+ .ruby-gemset
29
+
30
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
31
+ .rvmrc
32
+
33
+ # if using bower-rails ignore default bower_components path bower.json files
34
+ /vendor/assets/bower_components
35
+ *.bowerrc
36
+ bower.json
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'https://GemInAbox:e3XRBgVJRNUmwJ5y@gembox-vm-inx01.intra.local.ch/'
2
+
3
+ # Declare your gem's dependencies in lhc.gemspec.
4
+ # Bundler will treat runtime dependencies like base dependencies, and
5
+ # development dependencies will be added by default to the :development group.
6
+ gemspec
7
+
8
+ # Declare any dependencies that are still in development here instead of in
9
+ # your gemspec. These might include edge Rails or gems from your path or
10
+ # Git. Remember to move these dependencies to your gemspec before releasing
11
+ # your gem to rubygems.org.
data/README.md ADDED
@@ -0,0 +1,116 @@
1
+ LHC
2
+ ===
3
+
4
+ LHC uses [typhoeus](https://github.com/typhoeus/typhoeus) for http communication.
5
+
6
+ See [LHS](https://github.com/local-ch/LHS), if you are searching for something more **high level** that can query webservices easily and provides easy data access.
7
+
8
+ ## Quick Start Guide
9
+
10
+ ```ruby
11
+ response = LHC.get('http://datastore.lb-service/v2/feedbacks')
12
+ response.data.items[0]
13
+ response.data.items[0].recommended
14
+ response.body # String
15
+ response.headers # Hash
16
+ ```
17
+
18
+ ## Basic methods
19
+
20
+ Available are `get`, `post`, `put` & `delete`.
21
+
22
+ Other methods are available using `LHC.request(options)`.
23
+
24
+ ## A request from scratch
25
+
26
+ ```ruby
27
+ response = LHC.request(url: 'http://local.ch', method: :options)
28
+ response.headers
29
+
30
+ response = LHC.request(url: 'http://datastore.lb-service/v2/feedbacks', method: :get)
31
+ response.data
32
+ ```
33
+
34
+ → [Read more about the request object](docs/request.md)
35
+
36
+ → [Read more about the response object](docs/response.md)
37
+
38
+ ## Parallel requests
39
+
40
+ If you pass an array of requests to `LHC.request`, it will perform those requests in parallel.
41
+ You will get back an array of LHC::Response objects.
42
+
43
+ ```ruby
44
+ options = []
45
+ options << { url: 'http://datastore.lb-service/v2/feedbacks' }
46
+ options << { url: 'http://datastore.lb-service/v2/content-ads/123/feedbacks' }
47
+ responses = LHC.request(options)
48
+ ```
49
+
50
+ ## Transfer data through the body
51
+
52
+ Data that is transfered using the HTTP request body is transfered as you provide it.
53
+ Also consider setting the http header for content-type.
54
+
55
+ ```ruby
56
+ LHC.post('http://datastore.lb-service/v2/feedbacks',
57
+ body: feedback.to_json,
58
+ headers: { 'Content-Type' => 'application/json' }
59
+ )
60
+ ```
61
+
62
+ ## Configuration
63
+
64
+ You can configure global endpoints, placeholders and interceptors.
65
+
66
+ ```ruby
67
+ LHC.configure do |c|
68
+ c.placeholder :datastore, 'http://datastore.lb-service/v2'
69
+ c.endpoint :feedbacks, ':datastore/feedbacks', params: { has_reviews: true }
70
+ c.interceptors = [CacheInterceptor]
71
+ end
72
+ ```
73
+
74
+ → [Read more about configuration](docs/configuration.md)
75
+
76
+ ## URL-Templates
77
+
78
+ Instead of using concrete urls you can also use url-templates that contain placeholders.
79
+ This is especially handy for configuring an endpoint once and generate the url from the params when doing the request.
80
+
81
+ ```ruby
82
+ url = 'http://datastore.lb-service/v2/feedbacks/:id'
83
+ LHC.config.endpoint(:find_feedback, url, options)
84
+ LHC.get(:find_feedback, params:{ id: 123 })
85
+ # GET http://datastore.lb-service/v2/feedbacks/123
86
+ ```
87
+
88
+ This also works in place without configuring an endpoint.
89
+
90
+ ```ruby
91
+ LHC.get('http://datastore-stg.lb-service/v2/feedbacks/:id', params:{ id: 123 })
92
+ # GET http://datastore-stg.lb-service/v2/feedbacks/123
93
+ ```
94
+
95
+ If you miss to provide a parameter that is part of the url-template, it will raise an exception.
96
+
97
+ ## Exception handling
98
+
99
+ Anything but a response code indicating success (2**) throws an exception.
100
+
101
+ → [Read more about exceptions](docs/exceptions.md)
102
+
103
+ ## Interceptors
104
+
105
+ To monitor and manipulate the http communication done with LHC, you can define interceptors.
106
+
107
+ ```ruby
108
+ class TrackingIdInterceptor < LHC::Interceptor
109
+
110
+ def before_request(request)
111
+ request.params[:tid] = 123
112
+ end
113
+ end
114
+ ```
115
+
116
+ → [Read more about interceptors](docs/interceptors.md)
data/Rakefile ADDED
@@ -0,0 +1,25 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'LHC'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ begin
18
+ require 'rspec/core/rake_task'
19
+ RSpec::Core::RakeTask.new(:spec)
20
+ task :default => :spec
21
+ rescue LoadError
22
+ # no rspec available
23
+ end
24
+
25
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,57 @@
1
+ Configuration
2
+ ===
3
+
4
+ ## Configure LHC on initialisation
5
+
6
+ If you want to configure LHC on initialisation (like in a Rails initializer, environment.rb or application.rb), you could run into the problem that certain configurations can only be set once.
7
+ You can use `LHC.configure` to prevent the initialisation problem.
8
+ Take care that you only use `LHC.configure` once, because it is actually reseting previously made configurations and applies the new once.
9
+
10
+ ```ruby
11
+
12
+ LHC.configure do |c|
13
+ c.placeholder :datastore, 'http://datastore.lb-service/v2'
14
+ c.endpoint :feedbacks, ':datastore/feedbacks'
15
+ c.interceptors = [CachingInterceptor, MonitorInterceptor, TrackingIdInterceptor]
16
+ end
17
+
18
+ ```
19
+
20
+ ## Endpoints
21
+
22
+ You can configure endpoints, for later use, by giving them a name, an url and some parameters (optional).
23
+
24
+ ```ruby
25
+ url = 'http://datastore.lb-service/v2/feedbacks'
26
+ options = { params: { has_reviews: true } }
27
+ LHC.config.endpoint(:feedbacks, url, options)
28
+ LHC.get(:feedbacks)
29
+ ```
30
+
31
+ Explicit request options override configured options.
32
+
33
+ ```ruby
34
+ LHC.get(:feedbacks, params: { has_reviews: false }) # Overrides configured params
35
+ ```
36
+
37
+ ## Placeholders
38
+
39
+ You can configure global placeholders, that are used when generating urls from url-templates.
40
+
41
+ ```ruby
42
+ LHC.config.placeholder(:datastore, 'http://datastore.lb-service/v2')
43
+ options = { params: { has_reviews: true } }
44
+ LHC.config.endpoint(:feedbacks, url, options)
45
+ LHC.get(:feedbacks)
46
+ ```
47
+
48
+ ## Interceptors
49
+
50
+ To enable interceptors you have to configure LHC's interceptors for http communication.
51
+ The global default interceptors are processed in the order you provide them.
52
+
53
+ ```ruby
54
+ LHC.config.interceptors = [CachingInterceptor, MonitorInterceptor, TrackingIdInterceptor]
55
+ ```
56
+
57
+ You can only set the list of global interceptors once and you can not alter it after you set it.
@@ -0,0 +1,68 @@
1
+ Exceptions
2
+ ===
3
+
4
+ Anything but a response code indicating success (2**) raises an exception.
5
+
6
+ ```ruby
7
+
8
+ LHC.get('localhost') # UnknownError: 0
9
+ LHC.get('http://localhost:3000') # LHC::Timeout: 0
10
+
11
+ ```
12
+
13
+ You can access the response object that was causing the error.
14
+
15
+ ```ruby
16
+ LHC.get('local.ch')
17
+ rescue => e
18
+ e.response #<LHC:Response>
19
+ e.response.code # 403
20
+ e.response.timeout? # false
21
+ Rails.logger.error e
22
+ # LHC::UnknownError: get http://local.cac
23
+ # Params: {:url=>"http://local.cac", :method=>:get}
24
+ # Response Code: 0
25
+ # <Response Body>
26
+ ```
27
+
28
+ All errors that are raise by LHC inherit from `LHC::Error`.
29
+ They are divided into `LHC::ClientError`, `LHC::ServerError`, `LHC::Timeout` and `LHC::UnkownError` and mapped arcording to the following status code.
30
+
31
+ ```ruby
32
+ 400 => LHC::BadRequest
33
+ 401 => LHC::Unauthorized
34
+ 402 => LHC::PaymentRequired
35
+ 403 => LHC::Forbidden
36
+ 403 => LHC::Forbidden
37
+ 404 => LHC::NotFound
38
+ 405 => LHC::MethodNotAllowed
39
+ 406 => LHC::NotAcceptable
40
+ 407 => LHC::ProxyAuthenticationRequired
41
+ 408 => LHC::RequestTimeout
42
+ 409 => LHC::Conflict
43
+ 410 => LHC::Gone
44
+ 411 => LHC::LengthRequired
45
+ 412 => LHC::PreconditionFailed
46
+ 413 => LHC::RequestEntityTooLarge
47
+ 414 => LHC::RequestUriToLong
48
+ 415 => LHC::UnsupportedMediaType
49
+ 416 => LHC::RequestedRangeNotSatisfiable
50
+ 417 => LHC::ExpectationFailed
51
+ 422 => LHC::UnprocessableEntity
52
+ 423 => LHC::Locked
53
+ 424 => LHC::FailedDependency
54
+ 426 => LHC::UpgradeRequired
55
+
56
+ 500 => LHC::InternalServerError
57
+ 501 => LHC::NotImplemented
58
+ 502 => LHC::BadGateway
59
+ 503 => LHC::ServiceUnavailable
60
+ 504 => LHC::GatewayTimeout
61
+ 505 => LHC::HttpVersionNotSupported
62
+ 507 => LHC::InsufficientStorage
63
+ 510 => LHC::NotExtended
64
+
65
+ timeout? => LHC::Timeout
66
+
67
+ anything_else => LHC::UnknownError
68
+ ```
@@ -0,0 +1,90 @@
1
+ Interceptors
2
+ ===
3
+
4
+ ## Quick Start Guide
5
+
6
+ ```ruby
7
+ class TrackingIdInterceptor < LHC::Interceptor
8
+
9
+ def before_request(request)
10
+ request.params[:tid] = 123
11
+ end
12
+ end
13
+ ```
14
+
15
+ ```ruby
16
+ LHC.config.interceptors = [TrackingIdInterceptor] # global list of default interceptors
17
+ ```
18
+
19
+ ```ruby
20
+ LHC.request({url: 'http://local.ch', interceptors: []}) # no interceptor for this request
21
+ ```
22
+
23
+ ## Basic Interceptors
24
+
25
+ There are some interceptors available, that cover some basic usecases:
26
+ [lhc-core-interceptors](https://github.com/local-ch/lhc-core-interceptors)
27
+
28
+ ## Callbacks
29
+
30
+ `before_request(request)` is called when the request is prepared and about to be executed.
31
+
32
+ `after_request(request)` is called after request was started.
33
+
34
+ `before_response(request)` is called when response started to arrive.
35
+
36
+ `after_response(response)` is called after the response arrived completely.
37
+
38
+ → [Read more about the request object](request.md)
39
+
40
+ → [Read more about the response object](response.md)
41
+
42
+ ## Global default interceptors
43
+
44
+ Set the list of global default interceptors.
45
+ The global default interceptors are processed in the order you provide them.
46
+
47
+ ```ruby
48
+ LHC.config.interceptors = [CachingInterceptor, MonitorInterceptor, TrackingIdInterceptor]
49
+ ```
50
+
51
+ You can only set the list of global interceptors once and you cannot alter them later.
52
+
53
+ ## Interceptors on request level
54
+
55
+ You can override the global default interceptors on request level:
56
+
57
+ ```ruby
58
+ interceptors = LHC.config.interceptors
59
+ interceptors -= [CachingInterceptor] # remove caching
60
+ interceptors += [RetryInterceptor] # add retry
61
+ LHC.request({url: 'http://local.ch', retry: 2, interceptors: interceptors})
62
+ ```
63
+
64
+ ## Provide Response
65
+
66
+ Inside an interceptor, you are able to provide a response, rather then doing a real request.
67
+ This is usefull for implementing an interceptor for caching.
68
+
69
+ ```ruby
70
+ class CacheInterceptor < LHC::Interceptor
71
+
72
+ def before_request(request)
73
+ cached_response = Rails.cache.fetch(request.url)
74
+ return LHC::Response.new(cached_response) if cached_response
75
+ end
76
+ end
77
+ ```
78
+
79
+ Take care that having more than one interceptor trying to return a response will cause an exception.
80
+ You can access the request.response to identify if a response was already provided by another interceptor.
81
+
82
+ ```ruby
83
+ class RemoteCacheInterceptor < LHC::Interceptor
84
+
85
+ def before_request(request)
86
+ return unless request.response.nil?
87
+ return LHC::Response.new(remote_cache)
88
+ end
89
+ end
90
+ ```
data/docs/request.md ADDED
@@ -0,0 +1,24 @@
1
+ Request
2
+ ===
3
+
4
+ The request class handles the http request,
5
+ implements the interceptor pattern,
6
+ loads configured endpoints,
7
+ generates urls from url-templates
8
+ and raises exceptions for any response code that is not indicating success (2**).
9
+
10
+ → [Read more about exceptions](exceptions.md)
11
+
12
+ ```ruby
13
+ request.response #<LHC::Response> the associated response.
14
+
15
+ request.options #<Hash> the options used for creating the request.
16
+
17
+ request.params # access request params
18
+
19
+ request.headers # access request headers
20
+
21
+ request.url #<String> URL that is used for doing the request
22
+
23
+ request.method #<Symbol> provides the used http-method
24
+ ```