schema_registry_client 0.0.6 → 0.0.8
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 +4 -4
- data/CHANGELOG.md +10 -0
- data/Gemfile.lock +2 -30
- data/LICENSE +2 -0
- data/README.md +51 -6
- data/lib/schema_registry_client/avro_schema_store.rb +2 -2
- data/lib/schema_registry_client/cached_confluent_schema_registry.rb +1 -1
- data/lib/schema_registry_client/confluent_schema_registry.rb +1 -1
- data/lib/schema_registry_client/output/json_schema.rb +2 -2
- data/lib/schema_registry_client/output/proto_text.rb +1 -1
- data/lib/schema_registry_client/schema/avro.rb +42 -38
- data/lib/schema_registry_client/schema/base.rb +28 -30
- data/lib/schema_registry_client/schema/proto_json_schema.rb +14 -16
- data/lib/schema_registry_client/schema/protobuf.rb +97 -97
- data/lib/schema_registry_client/version.rb +2 -2
- data/lib/schema_registry_client/wire.rb +1 -1
- data/lib/schema_registry_client.rb +129 -127
- data/spec/decoding_spec.rb +5 -5
- data/spec/encoding_spec.rb +5 -5
- data/spec/gen/everything/everything_pb.rb +10 -10
- data/spec/gen/referenced/referer_pb.rb +8 -8
- data/spec/gen/simple/simple_pb.rb +3 -3
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8c4fb0ad39418dd0eb14e803f4c0652e47e64950b8684f564221a95b024177c1
|
|
4
|
+
data.tar.gz: c04a0a44298ff123a0a63cf530fe2c2ae56b7230cc740e2d02577f712d045e41
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c68cf8a284acdaad830acbbc76ea49b2cb1431b69e3c2961218f5c8af399b89d64f8b5eb1e25536e415f5720080152853f885d9984b47790ffd02d01cad73709
|
|
7
|
+
data.tar.gz: 7fb3f61b7159bf9f461f3fc9b6f8d0f145592f18a35b1e02d284a6f2ed62c95d30a6d8ff1082b2607976f134e6a74e1416e00483e61f8db2ecf27f601112bd84
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## UNRELEASED
|
|
9
9
|
|
|
10
|
+
# 0.0.8 - 2026-02-04
|
|
11
|
+
|
|
12
|
+
* Support passing a `schema_store` into the `Avro` schema backend.
|
|
13
|
+
* Move schema backend methods from class-level to instance-level and require instantiation.
|
|
14
|
+
|
|
15
|
+
# 0.0.7 - 2026-01-05
|
|
16
|
+
|
|
17
|
+
* Switch to using `SchemaRegistry::Client` instead of bare `SchemaRegistry`.
|
|
18
|
+
* Throw correct error when Avro schema is not found.
|
|
19
|
+
|
|
10
20
|
# 0.0.6 - 2026-01-02
|
|
11
21
|
|
|
12
22
|
* Initial release.
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
schema_registry_client (0.0.
|
|
4
|
+
schema_registry_client (0.0.8)
|
|
5
5
|
avro
|
|
6
6
|
excon
|
|
7
7
|
google-protobuf
|
|
@@ -22,33 +22,12 @@ GEM
|
|
|
22
22
|
docile (1.4.1)
|
|
23
23
|
excon (1.3.2)
|
|
24
24
|
logger
|
|
25
|
-
google-protobuf (4.33.2)
|
|
26
|
-
bigdecimal
|
|
27
|
-
rake (>= 13)
|
|
28
|
-
google-protobuf (4.33.2-aarch64-linux-gnu)
|
|
29
|
-
bigdecimal
|
|
30
|
-
rake (>= 13)
|
|
31
|
-
google-protobuf (4.33.2-aarch64-linux-musl)
|
|
32
|
-
bigdecimal
|
|
33
|
-
rake (>= 13)
|
|
34
25
|
google-protobuf (4.33.2-arm64-darwin)
|
|
35
26
|
bigdecimal
|
|
36
27
|
rake (>= 13)
|
|
37
|
-
google-protobuf (4.33.2-x86-linux-gnu)
|
|
38
|
-
bigdecimal
|
|
39
|
-
rake (>= 13)
|
|
40
|
-
google-protobuf (4.33.2-x86-linux-musl)
|
|
41
|
-
bigdecimal
|
|
42
|
-
rake (>= 13)
|
|
43
|
-
google-protobuf (4.33.2-x86_64-darwin)
|
|
44
|
-
bigdecimal
|
|
45
|
-
rake (>= 13)
|
|
46
28
|
google-protobuf (4.33.2-x86_64-linux-gnu)
|
|
47
29
|
bigdecimal
|
|
48
30
|
rake (>= 13)
|
|
49
|
-
google-protobuf (4.33.2-x86_64-linux-musl)
|
|
50
|
-
bigdecimal
|
|
51
|
-
rake (>= 13)
|
|
52
31
|
hashdiff (1.2.1)
|
|
53
32
|
json (2.18.0)
|
|
54
33
|
language_server-protocol (3.17.0.5)
|
|
@@ -127,15 +106,8 @@ GEM
|
|
|
127
106
|
hashdiff (>= 0.4.0, < 2.0.0)
|
|
128
107
|
|
|
129
108
|
PLATFORMS
|
|
130
|
-
aarch64-linux-gnu
|
|
131
|
-
aarch64-linux-musl
|
|
132
109
|
arm64-darwin
|
|
133
|
-
|
|
134
|
-
x86-linux-gnu
|
|
135
|
-
x86-linux-musl
|
|
136
|
-
x86_64-darwin
|
|
137
|
-
x86_64-linux-gnu
|
|
138
|
-
x86_64-linux-musl
|
|
110
|
+
x86_64-linux
|
|
139
111
|
|
|
140
112
|
DEPENDENCIES
|
|
141
113
|
bundler (~> 2.0)
|
data/LICENSE
CHANGED
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# schema_registry_client
|
|
2
2
|
|
|
3
|
-
`schema_registry_client` is a library to interact with the Confluent Schema Registry
|
|
3
|
+
`schema_registry_client` is a library to interact with the Confluent Schema Registry. It is inspired by and based off of [avro_turf](https://github.com/dasch/avro_turf).
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -24,21 +24,66 @@ SchemaRegistry interacts with the Confluent Schema Registry, and caches all resu
|
|
|
24
24
|
|
|
25
25
|
Example usage:
|
|
26
26
|
|
|
27
|
+
### Avro
|
|
28
|
+
|
|
29
|
+
Note that unlike AvroTurf, you must concatenate the namespace and schema name together when encoding.
|
|
30
|
+
|
|
27
31
|
```ruby
|
|
28
32
|
require 'schema_registry_client'
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
client = SchemaRegistry::Client.new(registry_url: 'http://localhost:8081', schema_type: SchemaRegistry::Schema::Avro.new)
|
|
35
|
+
SchemaRegistry.avro_schema_path = 'path/to/schemas'
|
|
36
|
+
message = {field1: 'value1', field2: 42 }
|
|
37
|
+
encoded = client.encode(message, schema_name: 'com.my-namespace.MySchema', subject: 'my-subject')
|
|
38
|
+
|
|
39
|
+
# Decoding
|
|
40
|
+
|
|
41
|
+
decoded_avro_message = client.decode(encoded_string)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Protobuf
|
|
45
|
+
|
|
46
|
+
```ruby
|
|
47
|
+
client = SchemaRegistry::Client.new(registry_url: 'http://localhost:8081', schema_type: SchemaRegistry::Schema::Protobuf.new)
|
|
48
|
+
message = MyProtoMessage.new(field1: 'value1', field2: 42)
|
|
49
|
+
encoded = client.encode(message, subject: 'my-proto-subject')
|
|
33
50
|
|
|
34
51
|
# Decoding
|
|
52
|
+
decoded_proto_message = client.decode(encoded_string)
|
|
53
|
+
```
|
|
35
54
|
|
|
36
|
-
|
|
55
|
+
### Protobuf JSON Schema
|
|
56
|
+
|
|
57
|
+
Since Protobuf is [not recommended to use for Kafka keys](https://protobuf.dev/programming-guides/encoding/#implications), it's instead recommended that you use the `ProtoJsonSchema` format. This will transform the Protobuf message into a JSON schema and register that with the registry instead. The encoded message will be the JSON representation of the Protobuf message, with keys sorted alphabetically to ensure consistent encoding.
|
|
58
|
+
|
|
59
|
+
Note that the algorithm to translate into JSON Schema is currently very naive (e.g. it does not handle nested messages) since keys should usually be very simple. If more complex logic is needed, pull requests are welcome.
|
|
60
|
+
|
|
61
|
+
```ruby
|
|
62
|
+
client = SchemaRegistry::Client.new(registry_url: 'http://localhost:8081', schema_type: SchemaRegistry::Schema::ProtoJsonSchema)
|
|
63
|
+
message = MyProtoMessage.new(field1: 'value1', field2: 42)
|
|
64
|
+
encoded = client.encode(message, subject: 'my-proto-subject') # will register a JSON Schema subject and encode into JSON
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
You can use JSON Schema with regular Ruby hashes as well by passing `schema_text` into the encode method:
|
|
69
|
+
|
|
70
|
+
```ruby
|
|
71
|
+
client = SchemaRegistry::Client.new(registry_url: 'http://localhost:8081', schema_type: SchemaRegistry::Schema::ProtoJsonSchema)
|
|
72
|
+
message = { field1: 'value1', field2: 42 }
|
|
73
|
+
schema_text = {
|
|
74
|
+
"type" => "object",
|
|
75
|
+
"properties" => {
|
|
76
|
+
"field1" => { "type" => "string" },
|
|
77
|
+
"field2" => { "type" => "integer" }
|
|
78
|
+
},
|
|
79
|
+
"required" => ["field1", "field2"]
|
|
80
|
+
}.to_json
|
|
81
|
+
encoded = client.encode(message, subject: 'my-proto-subject', schema_text: schema_text)
|
|
37
82
|
```
|
|
38
83
|
|
|
39
84
|
## Notes about usage
|
|
40
85
|
|
|
41
|
-
* When decoding, this library does *not* attempt to fully parse the
|
|
86
|
+
* When decoding, this library does *not* attempt to fully parse the Protobuf definition stored on the schema registry and generate dynamic classes. Instead, it simply parses out the package and message and assumes that the reader has the message available in the descriptor pool. Any compatibility issues should be detected through normal means, i.e. just by instantiating the message and seeing if any errors are raised.
|
|
42
87
|
|
|
43
88
|
### Regenerating test protos
|
|
44
89
|
Run the following to regenerate:
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'avro'
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
module SchemaRegistry
|
|
6
6
|
class AvroSchemaStore
|
|
7
7
|
def initialize(path: nil)
|
|
8
8
|
@path = path or raise 'Please specify a schema path'
|
|
@@ -116,7 +116,7 @@ class SchemaRegistry
|
|
|
116
116
|
end
|
|
117
117
|
load_schema!(fullname, @schemas.dup)
|
|
118
118
|
rescue Errno::ENOENT, Errno::ENAMETOOLONG
|
|
119
|
-
raise "could not find Avro schema at `#{schema_path}'"
|
|
119
|
+
raise SchemaRegistry::SchemaNotFoundError, "could not find Avro schema at `#{schema_path}'"
|
|
120
120
|
end
|
|
121
121
|
|
|
122
122
|
def build_schema_path(fullname)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
module SchemaRegistry
|
|
4
4
|
module Output
|
|
5
5
|
module JsonSchema
|
|
6
6
|
class << self
|
|
@@ -12,7 +12,7 @@ class SchemaRegistry
|
|
|
12
12
|
def output(descriptor, path: nil)
|
|
13
13
|
properties = {}
|
|
14
14
|
result = {
|
|
15
|
-
|
|
15
|
+
"$schema": 'https://json-schema.org/draft/2020-12/schema',
|
|
16
16
|
type: 'object',
|
|
17
17
|
properties: properties
|
|
18
18
|
}
|
|
@@ -3,58 +3,62 @@
|
|
|
3
3
|
require 'schema_registry_client/schema/base'
|
|
4
4
|
require 'schema_registry_client/avro_schema_store'
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
module SchemaRegistry
|
|
7
7
|
module Schema
|
|
8
8
|
class Avro < Base
|
|
9
9
|
DEFAULT_SCHEMAS_PATH = './schemas'
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
end
|
|
11
|
+
def self.schema_type
|
|
12
|
+
'AVRO'
|
|
13
|
+
end
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
@schema_store.load_schemas!
|
|
21
|
-
@schema_store
|
|
22
|
-
end
|
|
15
|
+
# @param schema_store [SchemaRegistry::AvroSchemaStore, nil]
|
|
16
|
+
def initialize(schema_store: nil)
|
|
17
|
+
@schema_store = schema_store
|
|
18
|
+
end
|
|
23
19
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
# @return [SchemaRegistry::AvroSchemaStore]
|
|
21
|
+
def schema_store
|
|
22
|
+
@schema_store ||= SchemaRegistry::AvroSchemaStore.new(
|
|
23
|
+
path: SchemaRegistry.avro_schema_path || DEFAULT_SCHEMAS_PATH
|
|
24
|
+
)
|
|
25
|
+
@schema_store.load_schemas!
|
|
26
|
+
@schema_store
|
|
27
|
+
end
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
fail_on_extra_fields: true }
|
|
32
|
-
schema = schema_store.find(schema_name)
|
|
29
|
+
def schema_text(_message, schema_name: nil)
|
|
30
|
+
schema_store.find_text(schema_name)
|
|
31
|
+
end
|
|
33
32
|
|
|
34
|
-
|
|
33
|
+
def encode(message, stream, schema_name: nil)
|
|
34
|
+
validate_options = { recursive: true,
|
|
35
|
+
encoded: false,
|
|
36
|
+
fail_on_extra_fields: true }
|
|
37
|
+
schema = schema_store.find(schema_name)
|
|
35
38
|
|
|
36
|
-
|
|
37
|
-
encoder = ::Avro::IO::BinaryEncoder.new(stream)
|
|
38
|
-
writer.write(message, encoder)
|
|
39
|
-
end
|
|
39
|
+
::Avro::SchemaValidator.validate!(schema, message, **validate_options)
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
writer = ::Avro::IO::DatumWriter.new(schema)
|
|
42
|
+
encoder = ::Avro::IO::BinaryEncoder.new(stream)
|
|
43
|
+
writer.write(message, encoder)
|
|
44
|
+
end
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
def decode(stream, schema_text)
|
|
47
|
+
# Parse the schema text from the registry into an Avro schema object
|
|
48
|
+
JSON.parse(schema_text)
|
|
49
|
+
writers_schema = ::Avro::Schema.parse(schema_text)
|
|
47
50
|
|
|
48
|
-
|
|
49
|
-
readers_schema = begin
|
|
50
|
-
schema_store.find(writers_schema.fullname)
|
|
51
|
-
rescue StandardError
|
|
52
|
-
writers_schema
|
|
53
|
-
end
|
|
51
|
+
decoder = ::Avro::IO::BinaryDecoder.new(stream)
|
|
54
52
|
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
# Try to find the reader schema locally, fall back to writer schema
|
|
54
|
+
readers_schema = begin
|
|
55
|
+
schema_store.find(writers_schema.fullname)
|
|
56
|
+
rescue StandardError
|
|
57
|
+
writers_schema
|
|
57
58
|
end
|
|
59
|
+
|
|
60
|
+
reader = ::Avro::IO::DatumReader.new(writers_schema, readers_schema)
|
|
61
|
+
reader.read(decoder)
|
|
58
62
|
end
|
|
59
63
|
end
|
|
60
64
|
end
|
|
@@ -1,43 +1,41 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
module SchemaRegistry
|
|
4
4
|
module Schema
|
|
5
5
|
class MissingImplementationError < StandardError; end
|
|
6
6
|
|
|
7
7
|
class Base
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
end
|
|
8
|
+
# @param message [Object]
|
|
9
|
+
# @param schema_name [String]
|
|
10
|
+
# @return [String]
|
|
11
|
+
def schema_text(_message, schema_name: nil)
|
|
12
|
+
raise MissingImplementationError, 'Subclasses must implement schema_text'
|
|
13
|
+
end
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
# @return [String]
|
|
16
|
+
def self.schema_type
|
|
17
|
+
raise MissingImplementationError, 'Subclasses must implement schema_type'
|
|
18
|
+
end
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
# @param message [Object]
|
|
21
|
+
# @param stream [StringIO]
|
|
22
|
+
# @param schema_name [String]
|
|
23
|
+
def encode(_message, _stream, schema_name: nil)
|
|
24
|
+
raise MissingImplementationError, 'Subclasses must implement encode'
|
|
25
|
+
end
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
# @param stream [StringIO]
|
|
28
|
+
# @param schema_text [String]
|
|
29
|
+
# @param registry [Object]
|
|
30
|
+
# @return [Object]
|
|
31
|
+
def decode(_stream, _schema_text)
|
|
32
|
+
raise MissingImplementationError, 'Subclasses must implement decode'
|
|
33
|
+
end
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
end
|
|
35
|
+
# @param message [Object]
|
|
36
|
+
# @return [Hash<String, String>]
|
|
37
|
+
def dependencies(_message)
|
|
38
|
+
{}
|
|
41
39
|
end
|
|
42
40
|
end
|
|
43
41
|
end
|
|
@@ -3,27 +3,25 @@
|
|
|
3
3
|
require 'schema_registry_client/schema/base'
|
|
4
4
|
require 'schema_registry_client/output/json_schema'
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
module SchemaRegistry
|
|
7
7
|
module Schema
|
|
8
8
|
class ProtoJsonSchema < Base
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
end
|
|
9
|
+
def self.schema_type
|
|
10
|
+
'JSON'
|
|
11
|
+
end
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
def schema_text(message, schema_name: nil)
|
|
14
|
+
SchemaRegistry::Output::JsonSchema.output(message.class.descriptor.to_proto)
|
|
15
|
+
end
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
def encode(message, stream, schema_name: nil)
|
|
18
|
+
json = message.to_h.sort.to_h.to_json
|
|
19
|
+
stream.write(json)
|
|
20
|
+
end
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
end
|
|
22
|
+
def decode(stream, _schema_text)
|
|
23
|
+
json = stream.read
|
|
24
|
+
JSON.parse(json)
|
|
27
25
|
end
|
|
28
26
|
end
|
|
29
27
|
end
|
|
@@ -7,124 +7,124 @@ require 'schema_registry_client/output/proto_text'
|
|
|
7
7
|
require 'schema_registry_client/schema/base'
|
|
8
8
|
require 'schema_registry_client/wire'
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
module SchemaRegistry
|
|
11
11
|
module Schema
|
|
12
12
|
class Protobuf < Base
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def schema_text(message, schema_name: nil)
|
|
19
|
-
file_descriptor = if message.is_a?(Google::Protobuf::FileDescriptor)
|
|
20
|
-
message
|
|
21
|
-
else
|
|
22
|
-
message.class.descriptor.file_descriptor
|
|
23
|
-
end
|
|
24
|
-
SchemaRegistry::Output::ProtoText.output(file_descriptor.to_proto)
|
|
25
|
-
end
|
|
13
|
+
def self.schema_type
|
|
14
|
+
'PROTOBUF'
|
|
15
|
+
end
|
|
26
16
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
17
|
+
def schema_text(message, schema_name: nil)
|
|
18
|
+
file_descriptor = if message.is_a?(Google::Protobuf::FileDescriptor)
|
|
19
|
+
message
|
|
20
|
+
else
|
|
21
|
+
message.class.descriptor.file_descriptor
|
|
22
|
+
end
|
|
23
|
+
SchemaRegistry::Output::ProtoText.output(file_descriptor.to_proto)
|
|
24
|
+
end
|
|
30
25
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
SchemaRegistry::Wire.write_int(stream, indexes.length)
|
|
35
|
-
indexes.each { |i| SchemaRegistry::Wire.write_int(stream, i) }
|
|
36
|
-
end
|
|
26
|
+
def encode(message, stream, schema_name: nil)
|
|
27
|
+
_, indexes = find_index(message.class.descriptor.to_proto,
|
|
28
|
+
message.class.descriptor.file_descriptor.to_proto.message_type)
|
|
37
29
|
|
|
38
|
-
|
|
39
|
-
|
|
30
|
+
if indexes == [0]
|
|
31
|
+
SchemaRegistry::Wire.write_int(stream, 0)
|
|
32
|
+
else
|
|
33
|
+
SchemaRegistry::Wire.write_int(stream, indexes.length)
|
|
34
|
+
indexes.each { |i| SchemaRegistry::Wire.write_int(stream, i) }
|
|
40
35
|
end
|
|
41
36
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
indexes = []
|
|
46
|
-
if index_length.zero?
|
|
47
|
-
indexes.push(0)
|
|
48
|
-
else
|
|
49
|
-
index_length.times do
|
|
50
|
-
indexes.push(SchemaRegistry::Wire.read_int(stream))
|
|
51
|
-
end
|
|
52
|
-
end
|
|
37
|
+
# Now we write the actual message.
|
|
38
|
+
stream.write(message.to_proto)
|
|
39
|
+
end
|
|
53
40
|
|
|
54
|
-
|
|
55
|
-
|
|
41
|
+
def decode(stream, schema_text)
|
|
42
|
+
# See https://docs.confluent.io/platform/current/schema-registry/fundamentals/serdes-develop/index.html#wire-format
|
|
43
|
+
index_length = SchemaRegistry::Wire.read_int(stream)
|
|
44
|
+
indexes = []
|
|
45
|
+
if index_length.zero?
|
|
46
|
+
indexes.push(0)
|
|
47
|
+
else
|
|
48
|
+
index_length.times do
|
|
49
|
+
indexes.push(SchemaRegistry::Wire.read_int(stream))
|
|
50
|
+
end
|
|
56
51
|
end
|
|
57
52
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
53
|
+
encoded = stream.read
|
|
54
|
+
decode_protobuf(schema_text, encoded, indexes)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def load_schemas!
|
|
58
|
+
@all_schemas = {}
|
|
59
|
+
all_files = ObjectSpace.each_object(Google::Protobuf::FileDescriptor).to_a
|
|
60
|
+
all_files.each do |file_desc|
|
|
61
|
+
file_path = file_desc.name
|
|
62
|
+
next if file_path.start_with?('google/protobuf/') # skip built-in protos
|
|
64
63
|
|
|
65
|
-
|
|
66
|
-
end
|
|
64
|
+
@all_schemas[file_path] = file_desc
|
|
67
65
|
end
|
|
66
|
+
end
|
|
68
67
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
68
|
+
def dependencies(message)
|
|
69
|
+
return [] if message.nil?
|
|
70
|
+
|
|
71
|
+
load_schemas! unless @all_schemas&.any?
|
|
72
|
+
file_descriptor = if message.is_a?(Google::Protobuf::FileDescriptor)
|
|
73
|
+
message
|
|
74
|
+
else
|
|
75
|
+
message.class.descriptor.file_descriptor
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
deps = file_descriptor.to_proto.dependency.to_a
|
|
79
|
+
.reject { |d| d.start_with?('google/protobuf/') }
|
|
80
|
+
deps.to_h do |dep|
|
|
81
|
+
dependency_schema = @all_schemas[dep]
|
|
82
|
+
[dependency_schema.name, dependency_schema]
|
|
83
83
|
end
|
|
84
|
+
end
|
|
84
85
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
end
|
|
86
|
+
def find_index(descriptor, messages, indexes = [])
|
|
87
|
+
messages.each_with_index do |sub_descriptor, i|
|
|
88
|
+
if sub_descriptor == descriptor
|
|
89
|
+
indexes.push(i)
|
|
90
|
+
return [true, indexes]
|
|
91
|
+
else
|
|
92
|
+
found, found_indexes = find_index(descriptor, sub_descriptor.nested_type, indexes + [i])
|
|
93
|
+
return [true, found_indexes] if found
|
|
94
94
|
end
|
|
95
|
-
[]
|
|
96
95
|
end
|
|
96
|
+
[]
|
|
97
|
+
end
|
|
97
98
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
end
|
|
106
|
-
path
|
|
99
|
+
def find_descriptor(indexes, messages)
|
|
100
|
+
first_index = indexes.shift
|
|
101
|
+
message = messages[first_index]
|
|
102
|
+
path = [message.name]
|
|
103
|
+
while indexes.length.positive?
|
|
104
|
+
message = message.nested_type[indexes.shift]
|
|
105
|
+
path.push(message.name)
|
|
107
106
|
end
|
|
107
|
+
path
|
|
108
|
+
end
|
|
108
109
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
path = find_descriptor(indexes, descriptor.file_descriptor.to_proto.message_type)
|
|
125
|
-
correct_message = Google::Protobuf::DescriptorPool.generated_pool.lookup("#{package}.#{path.join('.')}")
|
|
126
|
-
correct_message.msgclass.decode(encoded)
|
|
110
|
+
def decode_protobuf(schema, encoded, indexes)
|
|
111
|
+
# get the package
|
|
112
|
+
package = schema.match(/package (\S+);/)[1]
|
|
113
|
+
# get the first message in the protobuf text
|
|
114
|
+
# TODO - get the correct message based on schema index
|
|
115
|
+
message_name = schema.match(/message (\w+) {/)[1]
|
|
116
|
+
# look up the descriptor
|
|
117
|
+
full_name = "#{package}.#{message_name}"
|
|
118
|
+
descriptor = Google::Protobuf::DescriptorPool.generated_pool.lookup(full_name)
|
|
119
|
+
unless descriptor
|
|
120
|
+
msg = "Could not find schema for #{full_name}. " \
|
|
121
|
+
'Make sure the corresponding .proto file has been compiled and loaded.'
|
|
122
|
+
raise msg
|
|
127
123
|
end
|
|
124
|
+
|
|
125
|
+
path = find_descriptor(indexes, descriptor.file_descriptor.to_proto.message_type)
|
|
126
|
+
correct_message = Google::Protobuf::DescriptorPool.generated_pool.lookup("#{package}.#{path.join('.')}")
|
|
127
|
+
correct_message.msgclass.decode(encoded)
|
|
128
128
|
end
|
|
129
129
|
end
|
|
130
130
|
end
|
|
@@ -8,149 +8,151 @@ require 'schema_registry_client/schema/protobuf'
|
|
|
8
8
|
require 'schema_registry_client/schema/proto_json_schema'
|
|
9
9
|
require 'schema_registry_client/schema/avro'
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
module SchemaRegistry
|
|
12
12
|
class SchemaNotFoundError < StandardError; end
|
|
13
13
|
class SchemaError < StandardError; end
|
|
14
14
|
|
|
15
|
-
# Provides a way to encode and decode messages without having to embed schemas
|
|
16
|
-
# in the encoded data. Confluent's Schema Registry[1] is used to register
|
|
17
|
-
# a schema when encoding a message -- the registry will issue a schema id that
|
|
18
|
-
# will be included in the encoded data alongside the actual message. When
|
|
19
|
-
# decoding the data, the schema id will be used to look up the writer's schema
|
|
20
|
-
# from the registry.
|
|
21
|
-
#
|
|
22
|
-
# 1: https://github.com/confluentinc/schema-registry
|
|
23
|
-
# https://docs.confluent.io/platform/current/schema-registry/fundamentals/serdes-develop/serdes-protobuf.html
|
|
24
|
-
# https://docs.confluent.io/platform/current/schema-registry/fundamentals/serdes-develop/index.html#wire-format
|
|
25
|
-
MAGIC_BYTE = [0].pack('C').freeze
|
|
26
|
-
|
|
27
|
-
# Instantiate a new SchemaRegistry instance with the given configuration.
|
|
28
|
-
#
|
|
29
|
-
# registry - A schema registry object that responds to all methods in the
|
|
30
|
-
# SchemaRegistry::ConfluentSchemaRegistry interface.
|
|
31
|
-
# registry_url - The String URL of the schema registry that should be used.
|
|
32
|
-
# schema_context - Schema registry context name (optional)
|
|
33
|
-
# registry_path_prefix - The String URL path prefix used to namespace schema registry requests (optional).
|
|
34
|
-
# logger - The Logger that should be used to log information (optional).
|
|
35
|
-
# proxy - Forward the request via proxy (optional).
|
|
36
|
-
# user - User for basic auth (optional).
|
|
37
|
-
# password - Password for basic auth (optional).
|
|
38
|
-
# ssl_ca_file - Name of file containing CA certificate (optional).
|
|
39
|
-
# client_cert - Name of file containing client certificate (optional).
|
|
40
|
-
# client_key - Name of file containing client private key to go with client_cert (optional).
|
|
41
|
-
# client_key_pass - Password to go with client_key (optional).
|
|
42
|
-
# client_cert_data - In-memory client certificate (optional).
|
|
43
|
-
# client_key_data - In-memory client private key to go with client_cert_data (optional).
|
|
44
|
-
# connect_timeout - Timeout to use in the connection with the schema registry (optional).
|
|
45
|
-
# resolv_resolver - Custom domain name resolver (optional).
|
|
46
|
-
# schema_type - A SchemaRegistry::Schema::Base subclass.
|
|
47
|
-
def initialize( # rubocop:disable Metrics/ParameterLists
|
|
48
|
-
registry: nil,
|
|
49
|
-
registry_url: nil,
|
|
50
|
-
schema_context: nil,
|
|
51
|
-
registry_path_prefix: nil,
|
|
52
|
-
logger: nil,
|
|
53
|
-
proxy: nil,
|
|
54
|
-
user: nil,
|
|
55
|
-
password: nil,
|
|
56
|
-
ssl_ca_file: nil,
|
|
57
|
-
client_cert: nil,
|
|
58
|
-
client_key: nil,
|
|
59
|
-
client_key_pass: nil,
|
|
60
|
-
client_cert_data: nil,
|
|
61
|
-
client_key_data: nil,
|
|
62
|
-
connect_timeout: nil,
|
|
63
|
-
resolv_resolver: nil,
|
|
64
|
-
schema_type: SchemaRegistry::Schema::Protobuf
|
|
65
|
-
)
|
|
66
|
-
@logger = logger || Logger.new($stderr)
|
|
67
|
-
@registry = registry || SchemaRegistry::CachedConfluentSchemaRegistry.new(
|
|
68
|
-
SchemaRegistry::ConfluentSchemaRegistry.new(
|
|
69
|
-
registry_url,
|
|
70
|
-
schema_context: schema_context,
|
|
71
|
-
logger: @logger,
|
|
72
|
-
proxy: proxy,
|
|
73
|
-
user: user,
|
|
74
|
-
password: password,
|
|
75
|
-
ssl_ca_file: ssl_ca_file,
|
|
76
|
-
client_cert: client_cert,
|
|
77
|
-
client_key: client_key,
|
|
78
|
-
client_key_pass: client_key_pass,
|
|
79
|
-
client_cert_data: client_cert_data,
|
|
80
|
-
client_key_data: client_key_data,
|
|
81
|
-
path_prefix: registry_path_prefix,
|
|
82
|
-
connect_timeout: connect_timeout,
|
|
83
|
-
resolv_resolver: resolv_resolver
|
|
84
|
-
)
|
|
85
|
-
)
|
|
86
|
-
@schema = schema_type
|
|
87
|
-
end
|
|
88
|
-
|
|
89
15
|
class << self
|
|
90
16
|
attr_accessor :avro_schema_path
|
|
91
17
|
end
|
|
92
18
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
#
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
19
|
+
class Client
|
|
20
|
+
# Provides a way to encode and decode messages without having to embed schemas
|
|
21
|
+
# in the encoded data. Confluent's Schema Registry[1] is used to register
|
|
22
|
+
# a schema when encoding a message -- the registry will issue a schema id that
|
|
23
|
+
# will be included in the encoded data alongside the actual message. When
|
|
24
|
+
# decoding the data, the schema id will be used to look up the writer's schema
|
|
25
|
+
# from the registry.
|
|
26
|
+
#
|
|
27
|
+
# 1: https://github.com/confluentinc/schema-registry
|
|
28
|
+
# https://docs.confluent.io/platform/current/schema-registry/fundamentals/serdes-develop/serdes-protobuf.html
|
|
29
|
+
# https://docs.confluent.io/platform/current/schema-registry/fundamentals/serdes-develop/index.html#wire-format
|
|
30
|
+
MAGIC_BYTE = [0].pack('C').freeze
|
|
31
|
+
|
|
32
|
+
# Instantiate a new SchemaRegistry instance with the given configuration.
|
|
33
|
+
#
|
|
34
|
+
# registry - A schema registry object that responds to all methods in the
|
|
35
|
+
# SchemaRegistry::ConfluentSchemaRegistry interface.
|
|
36
|
+
# registry_url - The String URL of the schema registry that should be used.
|
|
37
|
+
# schema_context - Schema registry context name (optional)
|
|
38
|
+
# registry_path_prefix - The String URL path prefix used to namespace schema registry requests (optional).
|
|
39
|
+
# logger - The Logger that should be used to log information (optional).
|
|
40
|
+
# proxy - Forward the request via proxy (optional).
|
|
41
|
+
# user - User for basic auth (optional).
|
|
42
|
+
# password - Password for basic auth (optional).
|
|
43
|
+
# ssl_ca_file - Name of file containing CA certificate (optional).
|
|
44
|
+
# client_cert - Name of file containing client certificate (optional).
|
|
45
|
+
# client_key - Name of file containing client private key to go with client_cert (optional).
|
|
46
|
+
# client_key_pass - Password to go with client_key (optional).
|
|
47
|
+
# client_cert_data - In-memory client certificate (optional).
|
|
48
|
+
# client_key_data - In-memory client private key to go with client_cert_data (optional).
|
|
49
|
+
# connect_timeout - Timeout to use in the connection with the schema registry (optional).
|
|
50
|
+
# resolv_resolver - Custom domain name resolver (optional).
|
|
51
|
+
# schema_type - A SchemaRegistry::Schema::Base subclass.
|
|
52
|
+
def initialize( # rubocop:disable Metrics/ParameterLists
|
|
53
|
+
registry: nil,
|
|
54
|
+
registry_url: nil,
|
|
55
|
+
schema_context: nil,
|
|
56
|
+
registry_path_prefix: nil,
|
|
57
|
+
logger: nil,
|
|
58
|
+
proxy: nil,
|
|
59
|
+
user: nil,
|
|
60
|
+
password: nil,
|
|
61
|
+
ssl_ca_file: nil,
|
|
62
|
+
client_cert: nil,
|
|
63
|
+
client_key: nil,
|
|
64
|
+
client_key_pass: nil,
|
|
65
|
+
client_cert_data: nil,
|
|
66
|
+
client_key_data: nil,
|
|
67
|
+
connect_timeout: nil,
|
|
68
|
+
resolv_resolver: nil,
|
|
69
|
+
schema_type: SchemaRegistry::Schema::Protobuf.new
|
|
70
|
+
)
|
|
71
|
+
@logger = logger || Logger.new($stderr)
|
|
72
|
+
@registry = registry || SchemaRegistry::CachedConfluentSchemaRegistry.new(
|
|
73
|
+
SchemaRegistry::ConfluentSchemaRegistry.new(
|
|
74
|
+
registry_url,
|
|
75
|
+
schema_context: schema_context,
|
|
76
|
+
logger: @logger,
|
|
77
|
+
proxy: proxy,
|
|
78
|
+
user: user,
|
|
79
|
+
password: password,
|
|
80
|
+
ssl_ca_file: ssl_ca_file,
|
|
81
|
+
client_cert: client_cert,
|
|
82
|
+
client_key: client_key,
|
|
83
|
+
client_key_pass: client_key_pass,
|
|
84
|
+
client_cert_data: client_cert_data,
|
|
85
|
+
client_key_data: client_key_data,
|
|
86
|
+
path_prefix: registry_path_prefix,
|
|
87
|
+
connect_timeout: connect_timeout,
|
|
88
|
+
resolv_resolver: resolv_resolver
|
|
89
|
+
)
|
|
90
|
+
)
|
|
91
|
+
@schema = schema_type
|
|
92
|
+
end
|
|
107
93
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
94
|
+
# Encodes a message using the specified schema.
|
|
95
|
+
# @param message [Object] The message that should be encoded. Must be compatible with the schema.
|
|
96
|
+
# @param subject [String] The subject name the schema should be registered under in the schema registry (optional).
|
|
97
|
+
# @param schema_name [String] the name of the schema to use for encoding (optional).
|
|
98
|
+
# @return [String] the encoded data.
|
|
99
|
+
def encode(message, subject: nil, schema_text: nil, schema_name: nil)
|
|
100
|
+
id = register_schema(message, subject, schema_text: schema_text, schema_name: schema_name)
|
|
111
101
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
# @return [Object] the decoded data.
|
|
116
|
-
def decode(data)
|
|
117
|
-
stream = StringIO.new(data)
|
|
102
|
+
stream = StringIO.new
|
|
103
|
+
# Always start with the magic byte.
|
|
104
|
+
stream.write(MAGIC_BYTE)
|
|
118
105
|
|
|
119
|
-
|
|
120
|
-
|
|
106
|
+
# The schema id is encoded as a 4-byte big-endian integer.
|
|
107
|
+
stream.write([id].pack('N'))
|
|
121
108
|
|
|
122
|
-
|
|
109
|
+
@schema.encode(message, stream, schema_name: schema_name)
|
|
110
|
+
stream.string
|
|
111
|
+
end
|
|
123
112
|
|
|
124
|
-
#
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
@
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
end
|
|
113
|
+
# Decodes data into the original message.
|
|
114
|
+
#
|
|
115
|
+
# @param data [String] a string containing encoded data.
|
|
116
|
+
# @return [Object] the decoded data.
|
|
117
|
+
def decode(data)
|
|
118
|
+
stream = StringIO.new(data)
|
|
131
119
|
|
|
132
|
-
|
|
120
|
+
# The first byte is MAGIC!!!
|
|
121
|
+
magic_byte = stream.read(1)
|
|
133
122
|
|
|
134
|
-
|
|
135
|
-
schema_text ||= @schema.schema_text(message, schema_name: schema_name)
|
|
136
|
-
return if @registry.registered?(schema_text, subject)
|
|
123
|
+
raise "Expected data to begin with a magic byte, got `#{magic_byte.inspect}`" if magic_byte != MAGIC_BYTE
|
|
137
124
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
125
|
+
# The schema id is a 4-byte big-endian integer.
|
|
126
|
+
schema_id = stream.read(4).unpack1('N')
|
|
127
|
+
schema = @registry.fetch(schema_id)
|
|
128
|
+
@schema.decode(stream, schema)
|
|
129
|
+
rescue Excon::Error::NotFound
|
|
130
|
+
raise SchemaNotFoundError, "Schema with id: #{schema_id} is not found on registry"
|
|
143
131
|
end
|
|
144
132
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
133
|
+
private
|
|
134
|
+
|
|
135
|
+
def register_schema(message, subject, schema_text: nil, schema_name: nil)
|
|
136
|
+
schema_text ||= @schema.schema_text(message, schema_name: schema_name)
|
|
137
|
+
return if @registry.registered?(schema_text, subject)
|
|
138
|
+
|
|
139
|
+
# register dependencies first
|
|
140
|
+
dependencies = @schema.dependencies(message)
|
|
141
|
+
versions = dependencies.map do |name, dependency|
|
|
142
|
+
result = register_schema(dependency, name)
|
|
143
|
+
@registry.fetch_version(result, name)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
@registry.register(subject,
|
|
147
|
+
schema_text,
|
|
148
|
+
references: dependencies.keys.map.with_index do |dependency, i|
|
|
149
|
+
{
|
|
150
|
+
name: dependency,
|
|
151
|
+
subject: dependency,
|
|
152
|
+
version: versions[i]
|
|
153
|
+
}
|
|
154
|
+
end,
|
|
155
|
+
schema_type: @schema.class.schema_type)
|
|
156
|
+
end
|
|
155
157
|
end
|
|
156
158
|
end
|
data/spec/decoding_spec.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
RSpec.describe 'decoding' do
|
|
4
4
|
let(:schema_registry_client) do
|
|
5
|
-
SchemaRegistry.new(
|
|
5
|
+
SchemaRegistry::Client.new(
|
|
6
6
|
registry_url: 'http://localhost:8081'
|
|
7
7
|
)
|
|
8
8
|
end
|
|
@@ -38,9 +38,9 @@ RSpec.describe 'decoding' do
|
|
|
38
38
|
|
|
39
39
|
describe 'with JSON' do
|
|
40
40
|
let(:schema_registry_client) do
|
|
41
|
-
SchemaRegistry.new(
|
|
41
|
+
SchemaRegistry::Client.new(
|
|
42
42
|
registry_url: 'http://localhost:8081',
|
|
43
|
-
schema_type: SchemaRegistry::Schema::ProtoJsonSchema
|
|
43
|
+
schema_type: SchemaRegistry::Schema::ProtoJsonSchema.new
|
|
44
44
|
)
|
|
45
45
|
end
|
|
46
46
|
|
|
@@ -62,9 +62,9 @@ RSpec.describe 'decoding' do
|
|
|
62
62
|
describe 'with Avro' do
|
|
63
63
|
let(:schema_registry_client) do
|
|
64
64
|
SchemaRegistry.avro_schema_path = "#{__dir__}/schemas"
|
|
65
|
-
SchemaRegistry.new(
|
|
65
|
+
SchemaRegistry::Client.new(
|
|
66
66
|
registry_url: 'http://localhost:8081',
|
|
67
|
-
schema_type: SchemaRegistry::Schema::Avro
|
|
67
|
+
schema_type: SchemaRegistry::Schema::Avro.new
|
|
68
68
|
)
|
|
69
69
|
end
|
|
70
70
|
|
data/spec/encoding_spec.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
RSpec.describe 'encoding' do
|
|
4
4
|
let(:schema_registry_client) do
|
|
5
|
-
SchemaRegistry.new(
|
|
5
|
+
SchemaRegistry::Client.new(
|
|
6
6
|
registry_url: 'http://localhost:8081'
|
|
7
7
|
)
|
|
8
8
|
end
|
|
@@ -59,9 +59,9 @@ RSpec.describe 'encoding' do
|
|
|
59
59
|
|
|
60
60
|
describe 'with JSON' do
|
|
61
61
|
let(:schema_registry_client) do
|
|
62
|
-
SchemaRegistry.new(
|
|
62
|
+
SchemaRegistry::Client.new(
|
|
63
63
|
registry_url: 'http://localhost:8081',
|
|
64
|
-
schema_type: SchemaRegistry::Schema::ProtoJsonSchema
|
|
64
|
+
schema_type: SchemaRegistry::Schema::ProtoJsonSchema.new
|
|
65
65
|
)
|
|
66
66
|
end
|
|
67
67
|
|
|
@@ -104,9 +104,9 @@ RSpec.describe 'encoding' do
|
|
|
104
104
|
describe 'with Avro' do
|
|
105
105
|
let(:schema_registry_client) do
|
|
106
106
|
SchemaRegistry.avro_schema_path = "#{__dir__}/schemas"
|
|
107
|
-
SchemaRegistry.new(
|
|
107
|
+
SchemaRegistry::Client.new(
|
|
108
108
|
registry_url: 'http://localhost:8081',
|
|
109
|
-
schema_type: SchemaRegistry::Schema::Avro
|
|
109
|
+
schema_type: SchemaRegistry::Schema::Avro.new
|
|
110
110
|
)
|
|
111
111
|
end
|
|
112
112
|
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
4
4
|
# source: everything/everything.proto
|
|
5
5
|
|
|
6
|
-
require
|
|
6
|
+
require "google/protobuf"
|
|
7
7
|
|
|
8
|
-
require
|
|
9
|
-
require
|
|
8
|
+
require "simple/simple_pb"
|
|
9
|
+
require "google/protobuf/descriptor_pb"
|
|
10
10
|
|
|
11
11
|
descriptor_data = "\n\x1b\x65verything/everything.proto\x12\reverything.v1\x1a\x13simple/simple.proto\x1a google/protobuf/descriptor.proto\"*\n\x0e\x46oreignMessage\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0c\n\x04name\x18\x02 \x01(\t\"\xc0\x12\n\x0cTestAllTypes\x12\x16\n\x0eoptional_int32\x18\x01 \x01(\x05\x12\x16\n\x0eoptional_int64\x18\x02 \x01(\x03\x12\x17\n\x0foptional_uint32\x18\x03 \x01(\r\x12\x17\n\x0foptional_uint64\x18\x04 \x01(\x04\x12\x17\n\x0foptional_sint32\x18\x05 \x01(\x11\x12\x17\n\x0foptional_sint64\x18\x06 \x01(\x12\x12\x18\n\x10optional_fixed32\x18\x07 \x01(\x07\x12\x18\n\x10optional_fixed64\x18\x08 \x01(\x06\x12\x19\n\x11optional_sfixed32\x18\t \x01(\x0f\x12\x19\n\x11optional_sfixed64\x18\n \x01(\x10\x12\x16\n\x0eoptional_float\x18\x0b \x01(\x02\x12\x17\n\x0foptional_double\x18\x0c \x01(\x01\x12\x15\n\roptional_bool\x18\r \x01(\x08\x12\x17\n\x0foptional_string\x18\x0e \x01(\t\x12\x16\n\x0eoptional_bytes\x18\x0f \x01(\x0c\x12J\n\x17optional_nested_message\x18\x12 \x01(\x0b\x32).everything.v1.TestAllTypes.NestedMessage\x12?\n\x18optional_foreign_message\x18\x13 \x01(\x0b\x32\x1d.everything.v1.ForeignMessage\x12\x39\n\x17optional_import_message\x18\x14 \x01(\x0b\x32\x18.simple.v1.SimpleMessage\x12\x44\n\x14optional_nested_enum\x18\x15 \x01(\x0e\x32&.everything.v1.TestAllTypes.NestedEnum\x12\x39\n\x15optional_foreign_enum\x18\x16 \x01(\x0e\x32\x1a.everything.v1.ForeignEnum\x12\x33\n\x14optional_import_enum\x18\x17 \x01(\x0e\x32\x15.simple.v1.SimpleEnum\x12!\n\x15optional_string_piece\x18\x18 \x01(\tB\x02\x08\x02\x12\x19\n\roptional_cord\x18\x19 \x01(\tB\x02\x08\x01\x12\x1f\n\x13optional_bytes_cord\x18V \x01(\x0c\x42\x02\x08\x01\x12L\n\x15optional_lazy_message\x18\x1b \x01(\x0b\x32).everything.v1.TestAllTypes.NestedMessageB\x02(\x01\x12W\n optional_unverified_lazy_message\x18\x1c \x01(\x0b\x32).everything.v1.TestAllTypes.NestedMessageB\x02x\x01\x12\x16\n\x0erepeated_int32\x18\x1f \x03(\x05\x12\x16\n\x0erepeated_int64\x18 \x03(\x03\x12\x17\n\x0frepeated_uint32\x18! \x03(\r\x12\x17\n\x0frepeated_uint64\x18\" \x03(\x04\x12\x17\n\x0frepeated_sint32\x18# \x03(\x11\x12\x17\n\x0frepeated_sint64\x18$ \x03(\x12\x12\x18\n\x10repeated_fixed32\x18% \x03(\x07\x12\x18\n\x10repeated_fixed64\x18& \x03(\x06\x12\x19\n\x11repeated_sfixed32\x18' \x03(\x0f\x12\x19\n\x11repeated_sfixed64\x18( \x03(\x10\x12\x16\n\x0erepeated_float\x18) \x03(\x02\x12\x17\n\x0frepeated_double\x18* \x03(\x01\x12\x15\n\rrepeated_bool\x18+ \x03(\x08\x12\x17\n\x0frepeated_string\x18, \x03(\t\x12\x16\n\x0erepeated_bytes\x18- \x03(\x0c\x12J\n\x17repeated_nested_message\x18\x30 \x03(\x0b\x32).everything.v1.TestAllTypes.NestedMessage\x12?\n\x18repeated_foreign_message\x18\x31 \x03(\x0b\x32\x1d.everything.v1.ForeignMessage\x12\x39\n\x17repeated_import_message\x18\x32 \x03(\x0b\x32\x18.simple.v1.SimpleMessage\x12\x44\n\x14repeated_nested_enum\x18\x33 \x03(\x0e\x32&.everything.v1.TestAllTypes.NestedEnum\x12\x39\n\x15repeated_foreign_enum\x18\x34 \x03(\x0e\x32\x1a.everything.v1.ForeignEnum\x12\x33\n\x14repeated_import_enum\x18\x35 \x03(\x0e\x32\x15.simple.v1.SimpleEnum\x12!\n\x15repeated_string_piece\x18\x36 \x03(\tB\x02\x08\x02\x12\x19\n\rrepeated_cord\x18\x37 \x03(\tB\x02\x08\x01\x12L\n\x15repeated_lazy_message\x18\x39 \x03(\x0b\x32).everything.v1.TestAllTypes.NestedMessageB\x02(\x01\x12\x16\n\x0coneof_uint32\x18o \x01(\rH\x00\x12I\n\x14oneof_nested_message\x18p \x01(\x0b\x32).everything.v1.TestAllTypes.NestedMessageH\x00\x12\x16\n\x0coneof_string\x18q \x01(\tH\x00\x12\x15\n\x0boneof_bytes\x18r \x01(\x0cH\x00\x12\x18\n\noneof_cord\x18s \x01(\tB\x02\x08\x01H\x00\x12 \n\x12oneof_string_piece\x18t \x01(\tB\x02\x08\x02H\x00\x12R\n\x19oneof_lazy_nested_message\x18u \x01(\x0b\x32).everything.v1.TestAllTypes.NestedMessageB\x02(\x01H\x00\x1a\"\n\rNestedMessage\x12\x11\n\x02\x62\x62\x18\x01 \x01(\x05\x42\x05\x90\x82\x19\xd2\t\x1a\x1a\n\rOptionalGroup\x12\t\n\x01\x61\x18\x11 \x01(\x05\x1a\x1a\n\rRepeatedGroup\x12\t\n\x01\x61\x18/ \x01(\x05\"'\n\nNestedEnum\x12\x07\n\x03\x46OO\x10\x00\x12\x07\n\x03\x42\x41R\x10\x02\x12\x07\n\x03\x42\x41Z\x10\x03\x42\r\n\x0boneof_field*/\n\x0b\x46oreignEnum\x12\x0f\n\x0b\x46OREIGN_FOO\x10\x00\x12\x0f\n\x0b\x46OREIGN_BAR\x10\x01\x32Y\n\x0bTestService\x12J\n\nTestMethod\x12\x1b.everything.v1.TestAllTypes\x1a\x1d.everything.v1.ForeignMessage\"\x00:4\n\x0bsome_option\x12\x1d.google.protobuf.FieldOptions\x18\xa2\x90\x03 \x01(\x05\x62\x06proto3"
|
|
12
12
|
|
|
@@ -15,12 +15,12 @@ pool.add_serialized_file(descriptor_data)
|
|
|
15
15
|
|
|
16
16
|
module Everything
|
|
17
17
|
module V1
|
|
18
|
-
ForeignMessage = ::Google::Protobuf::DescriptorPool.generated_pool.lookup(
|
|
19
|
-
TestAllTypes = ::Google::Protobuf::DescriptorPool.generated_pool.lookup(
|
|
20
|
-
TestAllTypes::NestedMessage = ::Google::Protobuf::DescriptorPool.generated_pool.lookup(
|
|
21
|
-
TestAllTypes::OptionalGroup = ::Google::Protobuf::DescriptorPool.generated_pool.lookup(
|
|
22
|
-
TestAllTypes::RepeatedGroup = ::Google::Protobuf::DescriptorPool.generated_pool.lookup(
|
|
23
|
-
TestAllTypes::NestedEnum = ::Google::Protobuf::DescriptorPool.generated_pool.lookup(
|
|
24
|
-
ForeignEnum = ::Google::Protobuf::DescriptorPool.generated_pool.lookup(
|
|
18
|
+
ForeignMessage = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("everything.v1.ForeignMessage").msgclass
|
|
19
|
+
TestAllTypes = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("everything.v1.TestAllTypes").msgclass
|
|
20
|
+
TestAllTypes::NestedMessage = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("everything.v1.TestAllTypes.NestedMessage").msgclass
|
|
21
|
+
TestAllTypes::OptionalGroup = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("everything.v1.TestAllTypes.OptionalGroup").msgclass
|
|
22
|
+
TestAllTypes::RepeatedGroup = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("everything.v1.TestAllTypes.RepeatedGroup").msgclass
|
|
23
|
+
TestAllTypes::NestedEnum = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("everything.v1.TestAllTypes.NestedEnum").enummodule
|
|
24
|
+
ForeignEnum = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("everything.v1.ForeignEnum").enummodule
|
|
25
25
|
end
|
|
26
26
|
end
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
4
4
|
# source: referenced/referer.proto
|
|
5
5
|
|
|
6
|
-
require
|
|
6
|
+
require "google/protobuf"
|
|
7
7
|
|
|
8
|
-
require
|
|
8
|
+
require "simple/simple_pb"
|
|
9
9
|
|
|
10
10
|
descriptor_data = "\n\x18referenced/referer.proto\x12\rreferenced.v1\x1a\x13simple/simple.proto\"j\n\x08MessageA\x1a\x43\n\tMessageAA\x12\x0c\n\x04name\x18\x01 \x01(\t\x12(\n\x06simple\x18\x02 \x01(\x0b\x32\x18.simple.v1.SimpleMessage\x1a\x19\n\tMessageAB\x12\x0c\n\x04name\x18\x01 \x01(\t\"j\n\x08MessageB\x1a\x43\n\tMessageBA\x12\x0c\n\x04name\x18\x01 \x01(\t\x12(\n\x06simple\x18\x02 \x01(\x0b\x32\x18.simple.v1.SimpleMessage\x1a\x19\n\tMessageBB\x12\x0c\n\x04name\x18\x01 \x01(\tb\x06proto3"
|
|
11
11
|
|
|
@@ -14,11 +14,11 @@ pool.add_serialized_file(descriptor_data)
|
|
|
14
14
|
|
|
15
15
|
module Referenced
|
|
16
16
|
module V1
|
|
17
|
-
MessageA = ::Google::Protobuf::DescriptorPool.generated_pool.lookup(
|
|
18
|
-
MessageA::MessageAA = ::Google::Protobuf::DescriptorPool.generated_pool.lookup(
|
|
19
|
-
MessageA::MessageAB = ::Google::Protobuf::DescriptorPool.generated_pool.lookup(
|
|
20
|
-
MessageB = ::Google::Protobuf::DescriptorPool.generated_pool.lookup(
|
|
21
|
-
MessageB::MessageBA = ::Google::Protobuf::DescriptorPool.generated_pool.lookup(
|
|
22
|
-
MessageB::MessageBB = ::Google::Protobuf::DescriptorPool.generated_pool.lookup(
|
|
17
|
+
MessageA = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("referenced.v1.MessageA").msgclass
|
|
18
|
+
MessageA::MessageAA = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("referenced.v1.MessageA.MessageAA").msgclass
|
|
19
|
+
MessageA::MessageAB = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("referenced.v1.MessageA.MessageAB").msgclass
|
|
20
|
+
MessageB = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("referenced.v1.MessageB").msgclass
|
|
21
|
+
MessageB::MessageBA = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("referenced.v1.MessageB.MessageBA").msgclass
|
|
22
|
+
MessageB::MessageBB = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("referenced.v1.MessageB.MessageBB").msgclass
|
|
23
23
|
end
|
|
24
24
|
end
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
4
4
|
# source: simple/simple.proto
|
|
5
5
|
|
|
6
|
-
require
|
|
6
|
+
require "google/protobuf"
|
|
7
7
|
|
|
8
8
|
descriptor_data = "\n\x13simple/simple.proto\x12\tsimple.v1\"\x1d\n\rSimpleMessage\x12\x0c\n\x04name\x18\x01 \x01(\t*,\n\nSimpleEnum\x12\x0e\n\nSIMPLE_FOO\x10\x00\x12\x0e\n\nSIMPLE_BAR\x10\x01\x62\x06proto3"
|
|
9
9
|
|
|
@@ -12,7 +12,7 @@ pool.add_serialized_file(descriptor_data)
|
|
|
12
12
|
|
|
13
13
|
module Simple
|
|
14
14
|
module V1
|
|
15
|
-
SimpleMessage = ::Google::Protobuf::DescriptorPool.generated_pool.lookup(
|
|
16
|
-
SimpleEnum = ::Google::Protobuf::DescriptorPool.generated_pool.lookup(
|
|
15
|
+
SimpleMessage = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("simple.v1.SimpleMessage").msgclass
|
|
16
|
+
SimpleEnum = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("simple.v1.SimpleEnum").enummodule
|
|
17
17
|
end
|
|
18
18
|
end
|