kafka_rest_client 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.rubocop.yml +4 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/Guardfile +45 -0
- data/README.md +68 -0
- data/Rakefile +8 -0
- data/bin/console +11 -0
- data/bin/setup +7 -0
- data/kafka_rest_client.gemspec +30 -0
- data/lib/kafka_rest_client.rb +8 -0
- data/lib/kafka_rest_client/avro_producer.rb +89 -0
- data/lib/kafka_rest_client/configuration.rb +28 -0
- data/lib/kafka_rest_client/errors.rb +16 -0
- metadata +184 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 55eaec42836887d93b9460701cdca823c0f63f77
|
4
|
+
data.tar.gz: b6eeb11b3fa7c973c2b3d51fe00631f5b92b63d6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d9af06c6d72c0284905b76883f4dfc338eae7c6d39bfdb54ffefede69cd8b6462b1ac761085fced8340d9a274b7f76a46ae0ded6d59c5979fe13b9a1f49fa456
|
7
|
+
data.tar.gz: 3ac7cd879e202aea4ef4010099f3816455cd796d9545b316768a54098905a57e8b30f915fdb50acaae0b1f02f9b264d9f48b7e3e49261e4c2c0b977927366c3c
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.0.0-p645
|
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
## Uncomment and set this to only include directories you want to watch
|
5
|
+
# directories %w(app lib config test spec features) \
|
6
|
+
# .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
|
7
|
+
|
8
|
+
## Note: if you are using the `directories` clause above and you are not
|
9
|
+
## watching the project directory ('.'), then you will want to move
|
10
|
+
## the Guardfile to a watched dir and symlink it back, e.g.
|
11
|
+
#
|
12
|
+
# $ mkdir config
|
13
|
+
# $ mv Guardfile config/
|
14
|
+
# $ ln -s config/Guardfile .
|
15
|
+
#
|
16
|
+
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
|
17
|
+
|
18
|
+
# Note: The cmd option is now required due to the increasing number of ways
|
19
|
+
# rspec may be run, below are examples of the most common uses.
|
20
|
+
# * bundler: 'bundle exec rspec'
|
21
|
+
# * bundler binstubs: 'bin/rspec'
|
22
|
+
# * spring: 'bin/rspec' (This will use spring if running and you have
|
23
|
+
# installed the spring binstubs per the docs)
|
24
|
+
# * zeus: 'zeus rspec' (requires the server to be started separately)
|
25
|
+
# * 'just' rspec: 'rspec'
|
26
|
+
|
27
|
+
guard :rspec, cmd: 'bundle exec rspec' do
|
28
|
+
require 'guard/rspec/dsl'
|
29
|
+
dsl = Guard::RSpec::Dsl.new(self)
|
30
|
+
|
31
|
+
# RSpec files
|
32
|
+
rspec = dsl.rspec
|
33
|
+
watch(rspec.spec_helper) { rspec.spec_dir }
|
34
|
+
watch(rspec.spec_support) { rspec.spec_dir }
|
35
|
+
watch(rspec.spec_files)
|
36
|
+
|
37
|
+
# Ruby files
|
38
|
+
ruby = dsl.ruby
|
39
|
+
dsl.watch_spec_files_for(ruby.lib_files)
|
40
|
+
end
|
41
|
+
|
42
|
+
guard :rubocop do
|
43
|
+
watch(/.+\.rb$/)
|
44
|
+
watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
|
45
|
+
end
|
data/README.md
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# KafkaRestClient
|
2
|
+
|
3
|
+
A Ruby client to interact with [Kafka REST Proxy](http://docs.confluent.io/1.0.1/kafka-rest/docs/index.html)
|
4
|
+
|
5
|
+
**Current Version:** 0.1.0
|
6
|
+
|
7
|
+
**Supported Ruby versions:** 2.0, 2.1, 2.2
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'kafka_rest_client', git: 'git@github.com:FundingCircle/kafka_rest_client.git', tag: 'v0.1.0'
|
15
|
+
```
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
### Producing events
|
20
|
+
```ruby
|
21
|
+
require 'kafka_rest_client'
|
22
|
+
|
23
|
+
# Configure global settings
|
24
|
+
KafkaRestClient.configure do |config|
|
25
|
+
config.kafka_proxy_url = ENV['KAFKA_PROXY_URL']
|
26
|
+
config.schema_registry_url = ENV['SCHEMA_REGISTRY_URL']
|
27
|
+
config.timeout = 10
|
28
|
+
config.logger = Rails.logger
|
29
|
+
end
|
30
|
+
|
31
|
+
producer = KafkaRestClient::AvroProducer.new
|
32
|
+
|
33
|
+
# Produce a single event using the topic name and payload
|
34
|
+
producer.produce('ice-cream-melted', { temperature: 35, unit: 'celsius' })
|
35
|
+
|
36
|
+
# Produce multiple events
|
37
|
+
producer.produce('ice-cream-melted', [{ temperature: 35, unit: 'celsius' }])
|
38
|
+
|
39
|
+
# Produce event objects by relying on #to_json and #as_json when using Rails ActiveSupport
|
40
|
+
class IceCreamMeltedEvent
|
41
|
+
attr_reader :temperature, :unit
|
42
|
+
def initialize(temperature, unit)
|
43
|
+
@temperature = temperature
|
44
|
+
@unit = unit
|
45
|
+
end
|
46
|
+
|
47
|
+
def as_json(_options = nil)
|
48
|
+
{ temperature: temperature, unit: unit }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
producer.produce('ice-cream-melted', [IceCreamMeltedEvent.new(35, 'celsius')])
|
53
|
+
|
54
|
+
# Exception handling
|
55
|
+
begin
|
56
|
+
producer.produce('ice-cream-melted', { temperature: 35, unit: 'celsius' })
|
57
|
+
rescue KafkaRestClient::SchemaNotFoundError => e
|
58
|
+
# Schema has not been registered in the schema registry
|
59
|
+
rescue KafkaRestClient::TopicNotFoundError => e
|
60
|
+
# Topic does not exist in Kafka, create it with confluent tools
|
61
|
+
rescue KafkaRestClient::Error => e
|
62
|
+
# Rescue any error raised by the library
|
63
|
+
end
|
64
|
+
```
|
65
|
+
|
66
|
+
## Contributing
|
67
|
+
|
68
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/fundingcircle/kafka_rest_client.
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'kafka_rest_client'
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
require 'pry'
|
11
|
+
Pry.start
|
data/bin/setup
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'kafka_rest_client'
|
7
|
+
spec.version = '0.1.0'
|
8
|
+
spec.authors = ['Funding Circle Engineering']
|
9
|
+
spec.email = ['engineering+kafka_rest_client@fundingcircle.com']
|
10
|
+
|
11
|
+
spec.summary = 'Ruby client for interacting with Kafka REST Proxy'
|
12
|
+
spec.description = 'Ruby client for interacting with Kafka REST Proxy'
|
13
|
+
spec.homepage = 'http://github.com/FundingCircle/kakfa_rest_client'
|
14
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f|
|
15
|
+
f.match(%r{^(test|spec|features)/})
|
16
|
+
}
|
17
|
+
spec.bindir = 'exe'
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_development_dependency 'bundler', '~> 1.10'
|
22
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
23
|
+
spec.add_development_dependency 'rspec', '~> 3.4'
|
24
|
+
spec.add_development_dependency 'pry', '~> 0.10'
|
25
|
+
spec.add_development_dependency 'guard-rspec', '~> 4.6'
|
26
|
+
spec.add_development_dependency 'rubocop', '~> 0.36'
|
27
|
+
spec.add_development_dependency 'guard-rubocop', '~> 1.2'
|
28
|
+
spec.add_development_dependency 'webmock', '~> 1.22'
|
29
|
+
spec.add_dependency 'httparty', '~> 0.13'
|
30
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'kafka_rest_client/errors'
|
2
|
+
require 'kafka_rest_client/configuration'
|
3
|
+
require 'httparty'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module KafkaRestClient
|
7
|
+
class AvroProducer
|
8
|
+
AVRO_AS_JSON = 'application/vnd.kafka.avro.v1+json'.freeze
|
9
|
+
|
10
|
+
attr_reader :config
|
11
|
+
private :config
|
12
|
+
|
13
|
+
def initialize(config = Configuration.current)
|
14
|
+
@config = config
|
15
|
+
end
|
16
|
+
|
17
|
+
def enabled?
|
18
|
+
if config.kafka_proxy_url && config.schema_registry_url
|
19
|
+
true
|
20
|
+
else
|
21
|
+
false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def produce(topic, events)
|
26
|
+
if enabled?
|
27
|
+
payload = build_event_payload(topic, Array(events))
|
28
|
+
response = post_event_to_kafka(topic, payload)
|
29
|
+
config.logger.debug("Produced to Kafka topic #{topic}: #{payload.inspect}")
|
30
|
+
response
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def build_event_payload(topic, events)
|
37
|
+
{
|
38
|
+
value_schema_id: get_latest_schema(topic).fetch('id'),
|
39
|
+
records: events.map { |event| { value: event } }
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_latest_schema(topic)
|
44
|
+
response = HTTParty.get(
|
45
|
+
"#{config.schema_registry_url}/subjects/#{topic}-value/versions/latest",
|
46
|
+
timeout: config.timeout
|
47
|
+
)
|
48
|
+
|
49
|
+
if response.code == 200
|
50
|
+
JSON.parse(response.body)
|
51
|
+
elsif response.code == 404
|
52
|
+
fail SchemaNotFoundError, "Schema for #{topic} not found: #{response.body}"
|
53
|
+
elsif response.code == 500
|
54
|
+
fail InternalServerError, "Schema registry internal error: #{response.body}"
|
55
|
+
elsif response.code == 503
|
56
|
+
fail BadGateway, "Bad gateway: #{response.body}"
|
57
|
+
else
|
58
|
+
fail "Unexpected error: #{response.body}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def post_event_to_kafka(topic, message)
|
63
|
+
response = HTTParty.post(
|
64
|
+
"#{config.kafka_proxy_url}/topics/#{topic}",
|
65
|
+
headers: { 'Content-Type' => AVRO_AS_JSON },
|
66
|
+
body: message.to_json,
|
67
|
+
timeout: config.timeout
|
68
|
+
)
|
69
|
+
|
70
|
+
if response.code == 200
|
71
|
+
config.logger.debug("#{message[:records].count} event(s) published on #{topic}")
|
72
|
+
JSON.parse(response.body)
|
73
|
+
elsif response.code == 404
|
74
|
+
fail SchemaNotFoundError,
|
75
|
+
"Topic #{topic} not found in schema registry"
|
76
|
+
elsif response.code == 422
|
77
|
+
fail SchemaValidationError,
|
78
|
+
"Message #{message} does not match schema for #{topic} or is otherwise invalid"
|
79
|
+
elsif response.code == 500
|
80
|
+
fail InternalServerError,
|
81
|
+
'Kafka Rest Proxy internal error (check zookeeper, kafka services)'
|
82
|
+
elsif response.code == 503
|
83
|
+
fail BadGateway, "Bad gateway: #{response.body}"
|
84
|
+
else
|
85
|
+
fail "Unexpected error: #{response.body}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module KafkaRestClient
|
4
|
+
class Configuration
|
5
|
+
attr_accessor :kafka_proxy_url, :schema_registry_url, :timeout, :logger
|
6
|
+
class << self
|
7
|
+
attr_accessor :current
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
@kafka_proxy_url = options[:kafka_proxy_url]
|
12
|
+
@schema_registry_url = options[:schema_registry_url]
|
13
|
+
@timeout = options[:timeout]
|
14
|
+
@logger = options[:loggger]
|
15
|
+
end
|
16
|
+
|
17
|
+
def timeout
|
18
|
+
@timeout ||= 30
|
19
|
+
end
|
20
|
+
|
21
|
+
def logger
|
22
|
+
@logger ||= Logger.new(STDOUT).tap do |logger|
|
23
|
+
# Set level too high so we don't log anything
|
24
|
+
logger.level = Logger::FATAL
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module KafkaRestClient
|
2
|
+
# Base Error for all error classes of the library
|
3
|
+
class Error < StandardError; end
|
4
|
+
|
5
|
+
# Exception raised when the desired schema is not found (404 response code)
|
6
|
+
class SchemaNotFoundError < Error; end
|
7
|
+
|
8
|
+
# Exception raised on an internal server error (500 response code)
|
9
|
+
class InternalServerError < Error; end
|
10
|
+
|
11
|
+
# Exception raised on a message not matching the requested schema (422)
|
12
|
+
class SchemaValidationError < Error; end
|
13
|
+
|
14
|
+
# Exception raised on a bad gateway proxy resolution failure (503)
|
15
|
+
class BadGateway < Error; end
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kafka_rest_client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Funding Circle Engineering
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-06-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.10'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.10'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.4'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.4'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.10'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.10'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: guard-rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '4.6'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '4.6'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.36'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.36'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: guard-rubocop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.2'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1.2'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: webmock
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '1.22'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '1.22'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: httparty
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0.13'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0.13'
|
139
|
+
description: Ruby client for interacting with Kafka REST Proxy
|
140
|
+
email:
|
141
|
+
- engineering+kafka_rest_client@fundingcircle.com
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- ".gitignore"
|
147
|
+
- ".rspec"
|
148
|
+
- ".rubocop.yml"
|
149
|
+
- ".ruby-version"
|
150
|
+
- Gemfile
|
151
|
+
- Guardfile
|
152
|
+
- README.md
|
153
|
+
- Rakefile
|
154
|
+
- bin/console
|
155
|
+
- bin/setup
|
156
|
+
- kafka_rest_client.gemspec
|
157
|
+
- lib/kafka_rest_client.rb
|
158
|
+
- lib/kafka_rest_client/avro_producer.rb
|
159
|
+
- lib/kafka_rest_client/configuration.rb
|
160
|
+
- lib/kafka_rest_client/errors.rb
|
161
|
+
homepage: http://github.com/FundingCircle/kakfa_rest_client
|
162
|
+
licenses: []
|
163
|
+
metadata: {}
|
164
|
+
post_install_message:
|
165
|
+
rdoc_options: []
|
166
|
+
require_paths:
|
167
|
+
- lib
|
168
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - ">="
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: '0'
|
173
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
174
|
+
requirements:
|
175
|
+
- - ">="
|
176
|
+
- !ruby/object:Gem::Version
|
177
|
+
version: '0'
|
178
|
+
requirements: []
|
179
|
+
rubyforge_project:
|
180
|
+
rubygems_version: 2.0.14
|
181
|
+
signing_key:
|
182
|
+
specification_version: 4
|
183
|
+
summary: Ruby client for interacting with Kafka REST Proxy
|
184
|
+
test_files: []
|