# Getting Started With Authoritex
## About
An Elixir library for searching and fetching controlled vocabulary authority terms, inspired by the [Samvera Community's](https://github.com/samvera) [Questioning Authority](https://github.com/samvera/questioning_authority).
`Authoritex` provides an [Elixir behaviour](https://elixir-lang.org/getting-started/typespecs-and-behaviours.html#behaviours) that defines a specification for creating authorities. Each authority is a module which has to implement at least 5 public functions: `can_resolve?/1`, `code/0`, `description/0`, `fetch/1`, and `search/2`.
* `can_resolve?/1` Returns true if the module can resolve the given identifier
* `code/0` Returns the unique short code for the authority
* `description/0` Returns a human-readable description of the authority
* `fetch/1` Fetches a label (and optional hint string) for a specified resource
* `search/2` Returns a list of search results (and optional hints) matching a query
## Installation
```elixir
Mix.install([
{:authoritex, "~> 0.7.0"}
])
```
## Configuration
```elixir
Application.put_env(:authoritex, :authorities, [
Authoritex.FAST.CorporateName,
Authoritex.FAST.EventName,
Authoritex.FAST.Form,
Authoritex.FAST.Geographic,
Authoritex.FAST.Personal,
Authoritex.FAST.Topical,
Authoritex.FAST.UniformTitle,
Authoritex.FAST,
Authoritex.GeoNames,
Authoritex.Getty.AAT,
Authoritex.Getty.TGN,
Authoritex.Getty.ULAN,
Authoritex.Getty,
Authoritex.LOC.Languages,
Authoritex.LOC.Names,
Authoritex.LOC.SubjectHeadings
])
```
## List configured authorities
`Authoritex.authorities/0` returns a list of tuples describing all configured authorities.
```elixir
Authoritex.authorities()
```
## Fetch records by id
`Authoritex.fetch/1` returns a map with the `:label`, `:id`, `:hint`, and `:qualified_label` for an authority record given an id (must be a string).
```elixir
# Known authority and record identifier
Authoritex.fetch("http://id.loc.gov/authorities/names/no2011087251")
```
`Authoritex.fetch/1` returns the error tuple `{:error, 404}` given an unknown id for a properly configured authority.
```elixir
# Known authority with unknown record identifier
Authoritex.fetch("http://id.loc.gov/authorities/names/unknown-id")
```
`Authoritex.fetch/1` returns the error tuple `{:error, :unknown_authority}` given an id for an unknown authority.
```elixir
# Unknown authority
Authoritex.fetch("http://fake.authority.org/not-a-real-thing")
```
## Search an authority
`Authoritex.search/2` takes an authority code and search term (both arguments must be strings), and responds with either an `:ok` or an `:error` tuple. Search results are returned as a list of maps containing the `:id`, `:label` and `:hint` values for each result.
Enter a search term in the field below and choose an authority to search from the select dropdown. Selecting a different authority will automatically re-run the search below:
<!-- livebook:{"livebook_object":"cell_input","name":"search term","type":"text","value":"test"} -->
<!-- livebook:{"livebook_object":"cell_input","name":"select authority","props":{"options":["aat","fast","fast-corporate-name","fast-event-name","fast-form","fast-geographic","fast-personal","fast-topical","fast-uniform-title","getty","lclang","lcnaf","lcsh","tgn","ulan"]},"reactive":true,"type":"select","value":"aat"} -->
```elixir
Authoritex.search(IO.gets("select authority: ") |> String.trim(), IO.gets("search term: "))
```
`Authoritex.search/3` takes the same arguments as `Authoritex.search/2` along with a third argument (must be an integer) to limit the result count of the search.
```elixir
Authoritex.search("lcsh", "library", 3)
```
```elixir
# Error recevied when searching an unknown authority
Authoritex.search("not-an-authority", "test")
```
## Testing
`Authoritex` provides a mock for testing purposes in consuming applications.
Configure the mock with a few lines of code:
<!-- livebook:{"force_markdown":true} -->
```elixir
# In test.exs:
config :authoritex, authorities: [Authoritex.Mock]
# In test_helper.exs:
Authoritex.Mock.init()
```
Use the `Authoritex.Mock.set_data/1` function to add data for testing purposes, typically in a `setup` block. The example module below demonstrates an `ExUnit` test using the `Authoritex.Mock`. The `Authoritex.Mock.search/1` function returns all mock data regardless of the string passed to the function. (Note: the following code is a code sample that is not runnable like the examples above):
<!-- livebook:{"force_markdown":true} -->
```elixir
defmodule MyTest do
alias Authoritex.Mock
use ExUnit.Case, async: true
@data [
%{
id: "mock:result1",
label: "First Result",
qualified_label: "First Result (1)",
hint: "(1)"
},
%{
id: "mock:result2",
label: "Second Result",
qualified_label: "Second Result (2)",
hint: "(2)"
},
%{id: "mock:result3", label: "Third Result", qualified_label: "Third Result (3)", hint: "(3)"}
]
setup do
Mock.set_data(@data)
:ok
end
test "results" do
with {:ok, results} <- Mock.search("any") do
assert length(results) == length(@data)
end
end
end
```