Skip to content

Commit

Permalink
Add tests and docs for JSONSkooma::Sources
Browse files Browse the repository at this point in the history
  • Loading branch information
skryukov committed Apr 28, 2024
1 parent a63c484 commit 9731020
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 2 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning].

## [Unreleased]

### Fixed

- Fix `JSONSkooma::Sources::Remote` to allow remote refs. ([@killondark])

## [0.2.2] - 2023-04-09

### Fixed
Expand Down Expand Up @@ -42,6 +46,7 @@ and this project adheres to [Semantic Versioning].
- Initial implementation. ([@skryukov])

[@skryukov]: https://github.com/skryukov
[@killondark]: https://github.com/killondark

[Unreleased]: https://github.com/skryukov/json_skooma/compare/v0.2.2...HEAD
[0.2.2]: https://github.com/skryukov/json_skooma/compare/v0.2.1...v0.2.2
Expand Down
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ gemspec
gem "rake", "~> 13.0"

gem "rspec", "~> 3.0"
gem "webmock"

gem "standard", "~> 1.35.0"
41 changes: 40 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ JSONSkooma is a Ruby library for validating JSONs against JSON Schemas.
- Supports custom schema resolvers

<a href="https://evilmartians.com/?utm_source=json_skooma&utm_campaign=project_page">
<img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54">
<img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Built by Evil Martians" width="236" height="54">
</a>

## Installation
Expand Down Expand Up @@ -117,6 +117,45 @@ result.output(:basic)
# "error"=>"The instance value \"bar\" must be equal to one of the elements in the defined enumeration: [\"baz\"]"}]}
```

### Handling External `$ref`s in JSON Schemas

In `JSONSkooma`, you can map `$ref` identifiers in your JSON schemas to local or remote sources.

This configuration allows `JSONSkooma` to automatically link `$ref` URIs to their corresponding schemas from specified sources:

```yaml
# schema.yml
$schema: https://json-schema.org/draft/2020-12/schema
type: object
properties:
user:
$ref: http://local.example/user_definition.yaml
product:
$ref: http://remote.example/product_definition.yaml
```

```ruby
# Initialize the JSONSkooma registry
schema_registry = JSONSkooma.create_registry("2020-12")

# Add a local source for user definitions
local_schemas_path = File.join(__dir__, "schemas", "local")
schema_registry.add_source(
"http://local.example/",
JSONSkooma::Sources::Local.new(local_schemas_path)
)

# Add a remote source for product definitions
schema_registry.add_source(
"http://remote.example/",
JSONSkooma::Sources::Remote.new("http://example.com/schemas/")
)

# JSONSkooma now automatically resolves `$refs` to the appropriate schemas:
# - http://local.example/user_definition.yaml -> ./schemas/local/user_definition.yaml
# - http://remote.example/product_definition.yaml -> http://example.com/schemas/product_definition.yaml
```

## Alternatives

- [json_schemer](https://github.com/davishmcclurg/json_schemer) – Draft 4, 6, 7, 2019-09 and 2020-12 compliant
Expand Down
2 changes: 1 addition & 1 deletion lib/json_skooma/sources.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class Remote < Base
def read(relative_path)
path = suffix ? relative_path + suffix : relative_path
url = URI.join(base, path)
url.open.read
url.read
rescue OpenURI::HTTPError, SocketError
raise Error, "Could not fetch #{url}"
end
Expand Down
3 changes: 3 additions & 0 deletions spec/fixtures/key_value.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"key": "value"
}
1 change: 1 addition & 0 deletions spec/fixtures/key_value.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
key: value
37 changes: 37 additions & 0 deletions spec/json_skooma/sources/local_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# frozen_string_literal: true

require "spec_helper"

RSpec.describe JSONSkooma::Sources::Local do
subject(:local_source) { described_class.new(base, suffix: suffix) }

let(:base) { File.expand_path(File.join(__dir__, "..", "..", "fixtures")) }
let(:suffix) { ".json" }

describe "#call" do
context "when json file exists" do
let(:relative_path) { "key_value" }

it "returns parsed content of the file" do
expect(local_source.call(relative_path)).to eq({"key" => "value"})
end
end

context "when yaml file exists" do
let(:relative_path) { "key_value" }
let(:suffix) { ".yml" }

it "returns parsed content of the file" do
expect(local_source.call(relative_path)).to eq({"key" => "value"})
end
end

context "when file does not exist" do
let(:relative_path) { "non_existent_file" }

it "raises an error" do
expect { local_source.call(relative_path) }.to raise_error(JSONSkooma::Sources::Error)
end
end
end
end
59 changes: 59 additions & 0 deletions spec/json_skooma/sources/remote_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# frozen_string_literal: true

require "spec_helper"

RSpec.describe JSONSkooma::Sources::Remote do
subject(:remote_source) { described_class.new(base, suffix: suffix) }

let(:base) { "http://example.com/" }
let(:suffix) { ".yml" }
let(:relative_path) { "test" }

describe "#call" do
context "when the remote file exists and is valid yaml" do
before do
stub_request(:get, "#{base}#{relative_path}#{suffix}")
.to_return(body: "---\nkey: value\n")
end

it "returns the parsed YAML content" do
expect(remote_source.call(relative_path)).to eq({"key" => "value"})
end
end

context "when the remote file exists and is valid json" do
let(:suffix) { ".json" }

before do
stub_request(:get, "#{base}#{relative_path}#{suffix}")
.to_return(body: "{\"key\":\"value\"}")
end

it "returns the parsed JSON content" do
expect(remote_source.call(relative_path)).to eq({"key" => "value"})
end
end

context "when the remote file does not exist" do
before do
stub_request(:get, "#{base}#{relative_path}#{suffix}")
.to_return(status: 404)
end

it "raises an error" do
expect { remote_source.call(relative_path) }.to raise_error(JSONSkooma::Sources::Error)
end
end

context "when the remote file is not valid YAML" do
before do
stub_request(:get, "#{base}#{relative_path}#{suffix}")
.to_return(body: "not: valid: yaml:")
end

it "raises an error" do
expect { remote_source.call(relative_path) }.to raise_error(JSONSkooma::Sources::Error)
end
end
end
end
2 changes: 2 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

require "json_skooma"

require "webmock/rspec"

RSpec.configure do |config|
# Enable flags like --only-failures and --next-failure
config.example_status_persistence_file_path = ".rspec_status"
Expand Down

0 comments on commit 9731020

Please sign in to comment.