avro_turf 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a708d217a7af1550daca801dec09f63eee619c882bf099dc456ce300e2414aee
4
- data.tar.gz: e4fe1fa9f4b8af78f36a2eb59caeb6946aa1ef3a1dc0db20d548d122c8ab7802
3
+ metadata.gz: 8fc2d29f1112e649cc2cd5ec96f2126a0ea5fa8f46ebee01d908cdceeac8da0d
4
+ data.tar.gz: e1989abd9d9b0e5db24f360e96e7bce7ce18e5f488cc794d25a2b3fae6102e66
5
5
  SHA512:
6
- metadata.gz: 5476655050a88e2e38ccedaa9cf3228810802507fa8fb0c6b7b345b2da617577a8f6d015d3d5290630ebf07476fe1aa1b2c3eea3c7de7bcf6969ee511039eff6
7
- data.tar.gz: 7a61be786f276dec7a62385413f89be39188670337d739e2eddfcfc2b2ed7cf8fa73c5148d06a4a4f113cfa7d8627885529d1900b58e7f5ba624b68a8137b1b9
6
+ metadata.gz: f562a66ba746d2c0e4bee8b8f3a0e7fcf65900f261eca444986c8ff6c68231e67aa9c4dc659213721d0d09c65fd9273e12e158938c0773baa48cf86598d6bef9
7
+ data.tar.gz: 53e3640900a3b64038fe063f5dadab2049417490be1833bb5f17124307abe628af64ea0c68b5bdc2bd4ef2f6e58bbfac287696eaf5ece9a35ddb7c2ab8e5127e
@@ -2,6 +2,11 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## v1.2.0
6
+
7
+ - Expose `fetch_schema`, `fetch_schema_by_id` and `register_schema` schema in `Messaging` interface (#117, #119)
8
+ - Add ability to validate message before encoding in `Messaging#encode` interface (#116, #118)
9
+
5
10
  ## v1.1.0
6
11
 
7
12
  - Compatibility with Avro v1.10.x.
data/README.md CHANGED
@@ -178,6 +178,10 @@ data = avro.encode({ "title" => "hello, world" }, subject: 'greeting', version:
178
178
  # of the same schema version will be served by the cache.
179
179
  data = avro.encode({ "title" => "hello, world" }, schema_id: 2)
180
180
 
181
+ # Message can be validated before encoding to get a description of problem through
182
+ # Avro::SchemaValidator::ValidationError exception
183
+ data = avro.encode({ "titl" => "hello, world" }, schema_name: "greeting", validate: true)
184
+
181
185
  # When decoding, the schema will be fetched from the registry and cached. Subsequent
182
186
  # instances of the same schema id will be served by the cache.
183
187
  avro.decode(data) #=> { "title" => "hello, world" }
@@ -189,6 +193,20 @@ result.message #=> { "title" => "hello, world" }
189
193
  result.schema_id #=> 3
190
194
  result.writer_schema #=> #<Avro::Schema: ...>
191
195
  result.reader_schema #=> nil
196
+
197
+ # You can also work with schema through this interface:
198
+ # Fetch latest schema for subject from registry
199
+ schema, schema_id = avro.fetch_schema(subject: 'greeting')
200
+ # Fetch specific version
201
+ schema, schema_id = avro.fetch_schema(subject: 'greeting', version: 1)
202
+ # Fetch schema by id
203
+ schema, schema_id = avro.fetch_schema_by_id(3)
204
+ # Register schema fetched from store by name
205
+ schema, schema_id = avro.register_schema(schema_name: 'greeting')
206
+ # Specify namespace (same as schema_name: 'somewhere.greeting')
207
+ schema, schema_id = avro.register_schema(schema_name: 'greeting', namespace: 'somewhere')
208
+ # Customize subject under which to register schema
209
+ schema, schema_id = avro.register_schema(schema_name: 'greeting', namespace: 'somewhere', subject: 'test')
192
210
  ```
193
211
 
194
212
  ### Confluent Schema Registry Client
@@ -84,19 +84,26 @@ class AvroTurf
84
84
  # the data. Must match the schema used when encoding (optional).
85
85
  # schema_id - The integer id of the schema that should be used to encode
86
86
  # the data.
87
+ # validate - The boolean for performing complete message validation before
88
+ # encoding it, Avro::SchemaValidator::ValidationError with
89
+ # a descriptive message will be raised in case of invalid message.
87
90
  #
88
91
  # Returns the encoded data as a String.
89
- def encode(message, schema_name: nil, namespace: @namespace, subject: nil, version: nil, schema_id: nil)
90
- schema_id, schema = if schema_id
92
+ def encode(message, schema_name: nil, namespace: @namespace, subject: nil, version: nil, schema_id: nil, validate: false)
93
+ schema, schema_id = if schema_id
91
94
  fetch_schema_by_id(schema_id)
92
95
  elsif subject && version
93
- fetch_schema(subject, version)
96
+ fetch_schema(subject: subject, version: version)
94
97
  elsif schema_name
95
- register_schema(subject, schema_name, namespace)
98
+ register_schema(subject: subject, schema_name: schema_name, namespace: namespace)
96
99
  else
97
100
  raise ArgumentError.new('Neither schema_name nor schema_id nor subject + version provided to determine the schema.')
98
101
  end
99
102
 
103
+ if validate
104
+ Avro::SchemaValidator.validate!(schema, message, recursive: true, encoded: false, fail_on_extra_fields: true)
105
+ end
106
+
100
107
  stream = StringIO.new
101
108
  writer = Avro::IO::DatumWriter.new(schema)
102
109
  encoder = Avro::IO::BinaryEncoder.new(stream)
@@ -169,31 +176,29 @@ class AvroTurf
169
176
  raise SchemaNotFoundError.new("Schema with id: #{schema_id} is not found on registry")
170
177
  end
171
178
 
172
- private
173
-
174
179
  # Providing subject and version to determine the schema,
175
180
  # which skips the auto registeration of schema on the schema registry.
176
181
  # Fetch the schema from registry with the provided subject name and version.
177
- def fetch_schema(subject, version)
182
+ def fetch_schema(subject:, version: 'latest')
178
183
  schema_data = @registry.subject_version(subject, version)
179
184
  schema_id = schema_data.fetch('id')
180
185
  schema = Avro::Schema.parse(schema_data.fetch('schema'))
181
- [schema_id, schema]
186
+ [schema, schema_id]
182
187
  end
183
188
 
184
189
  # Fetch the schema from registry with the provided schema_id.
185
190
  def fetch_schema_by_id(schema_id)
186
191
  schema_json = @registry.fetch(schema_id)
187
192
  schema = Avro::Schema.parse(schema_json)
188
- [schema_id, schema]
193
+ [schema, schema_id]
189
194
  end
190
195
 
191
196
  # Schemas are registered under the full name of the top level Avro record
192
197
  # type, or `subject` if it's provided.
193
- def register_schema(subject, schema_name, namespace)
198
+ def register_schema(schema_name:, subject: nil, namespace: nil)
194
199
  schema = @schema_store.find(schema_name, namespace)
195
200
  schema_id = @registry.register(subject || schema.fullname, schema)
196
- [schema_id, schema]
201
+ [schema, schema_id]
197
202
  end
198
203
  end
199
204
  end
@@ -1,3 +1,3 @@
1
1
  class AvroTurf
2
- VERSION = "1.1.0"
2
+ VERSION = "1.2.0"
3
3
  end
@@ -297,4 +297,106 @@ describe AvroTurf::Messaging do
297
297
  end
298
298
  end
299
299
  end
300
+
301
+ context "validating" do
302
+ subject(:encode){ avro.encode(message, schema_name: "person", validate: true) }
303
+
304
+ context "for correct message" do
305
+ it { expect { encode }.not_to raise_error }
306
+ end
307
+
308
+ context "when message has wrong type" do
309
+ let(:message) { { "full_name" => 123 } }
310
+
311
+ it { expect { encode }.to raise_error(Avro::SchemaValidator::ValidationError, /\.full_name expected type string, got int/) }
312
+ end
313
+
314
+ context "when message contains extra fields (typo in key)" do
315
+ let(:message) { { "fulll_name" => "John Doe" } }
316
+
317
+ it { expect { encode }.to raise_error(Avro::SchemaValidator::ValidationError, /extra field 'fulll_name'/) }
318
+ end
319
+ end
320
+
321
+ context 'fetching and registering schema' do
322
+ let(:schema_store) { AvroTurf::SchemaStore.new(path: "spec/schemas") }
323
+
324
+ let(:registry) { AvroTurf::ConfluentSchemaRegistry.new(registry_url, logger: logger) }
325
+
326
+ let(:avro) do
327
+ AvroTurf::Messaging.new(
328
+ registry: registry,
329
+ schema_store: schema_store,
330
+ logger: logger
331
+ )
332
+ end
333
+
334
+ let(:schema_id) { 234 }
335
+
336
+ context 'using fetch_schema' do
337
+ subject { avro.fetch_schema(subject: subj, version: version) }
338
+
339
+ let(:subj) { 'subject' }
340
+
341
+ let(:version) { 'version' }
342
+
343
+ let(:response) { {'id' => schema_id, 'schema' => schema_json} }
344
+
345
+ before do
346
+ allow(registry).to receive(:subject_version).with(subj, version).and_return(response)
347
+ end
348
+
349
+ it 'gets schema from registry' do
350
+ expect(subject).to eq([schema, schema_id])
351
+ end
352
+ end
353
+
354
+ context 'using fetch_schema_by_id' do
355
+ subject { avro.fetch_schema_by_id(schema_id) }
356
+
357
+ before do
358
+ allow(registry).to receive(:fetch).with(schema_id).and_return(schema_json)
359
+ end
360
+
361
+ it 'gets schema from registry' do
362
+ expect(subject).to eq([schema, schema_id])
363
+ end
364
+ end
365
+
366
+ context 'using register_schema' do
367
+ let(:schema_name) { 'schema_name' }
368
+
369
+ let(:namespace) { 'namespace' }
370
+
371
+ before do
372
+ allow(schema_store).to receive(:find).with(schema_name, namespace).and_return(schema)
373
+ end
374
+
375
+ context 'when subject is not set' do
376
+ subject { avro.register_schema(schema_name: schema_name, namespace: namespace) }
377
+
378
+ before do
379
+ allow(registry).to receive(:register).with(schema.fullname, schema).and_return(schema_id)
380
+ end
381
+
382
+ it 'registers schema in registry' do
383
+ expect(subject).to eq([schema, schema_id])
384
+ end
385
+ end
386
+
387
+ context 'when subject is set' do
388
+ subject { avro.register_schema(schema_name: schema_name, namespace: namespace, subject: subj) }
389
+
390
+ let(:subj) { 'subject' }
391
+
392
+ before do
393
+ allow(registry).to receive(:register).with(subj, schema).and_return(schema_id)
394
+ end
395
+
396
+ it 'registers schema in registry' do
397
+ expect(subject).to eq([schema, schema_id])
398
+ end
399
+ end
400
+ end
401
+ end
300
402
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: avro_turf
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Schierbeck
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-30 00:00:00.000000000 Z
11
+ date: 2020-08-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: avro