# `JSV.Resolver.Local`
[🔗](https://github.com/lud/jsv/blob/v0.18.3/lib/jsv/resolver/local.ex#L1)

This module allows to build `JSV.Resolver` implementations that resolves
schemas based on disk based on their `$id` property. It is not itself a
`JSV.Resolver` implementation.

To define your own local resolver, `use` this module by providing the
`:source` option with a path to a directory, a path to a file, or a list of
paths to directories and files:

```elixir
schemas_dir = "priv/messaging/schemas"
other_schema = "priv/users/user-schema.schema.json"

defmodule MyApp.LocalResolver do
  use JSV.Resolver.Local, source: [schemas_dir, other_schema]
end
```

The macro will read all `.json` files from the given sources and build an
index mapping the `$id` property of each schema to its JSON-deserialized
value.

For convenience, nested lists are accepted. Duplicated files accepted as well
but not duplicates due to symlinks.

### Compilation and caching

Schemas are loaded directly into the generated module code. The module will
recompile everytime a loaded schema file is modified or deleted.

Recompilation will also happen when new files are added in directories listed
as sources.

### Debugging

The `use JSV.Resolver.Local` also accepts the following options:

* `:warn` - A `boolean` flag enabling compilation warnings when a `.json` file
  cannot be read or loaded properly. Defaults to `true`.
* `:debug` - A `boolean` flag enabling printouts of the loaded schemas on
  compilation. Defaults to `false`.

### Example

The `"priv/schemas/user-schema.schema.json"` file contains the following JSON
text:

```json
{
  "$id": "myapp:user-0.0.1",
  "type": "object",
  "properties": {
    "username": {
      "type": "string"
    }
  }
}
```

Then this can be used as a source in your module.

```elixir
defmodule MyApp.LocalResolver do
  use JSV.Resolver.Local, source: "priv/schemas"
end
```

You can now build validation roots (`JSV.Root`) by referencing this user
schema in `$ref` and by providing your resolver to the `JSV.build!/2`
function:

    iex> schema = %{"$ref" => "myapp:user-0.0.1"}
    iex> root   = JSV.build!(schema, resolver: MyApp.LocalResolver)
    iex> # Here we pass an invalid username (an integer)
    iex> result = JSV.validate(%{"username" => 123}, root)
    iex> match?({:error, %JSV.ValidationError{}}, result)
    true

You can also directly fetch a schema from the defined module:

    iex> MyApp.LocalResolver.resolve("myapp:user-0.0.1")
    {:ok,
      %{
        "$id" => "myapp:user-0.0.1",
        "type" => "object",
        "properties" => %{"username" => %{"type" => "string"}}
      }}

    iex> MyApp.LocalResolver.resolve("myapp:other")
    {:error, {:unknown_id, "myapp:other"}}

Remember that schemas are identified and resolved by their `$id` property and
not their path.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
