# NASA ADS Client for Elixir
Complete Elixir client for the NASA Astrophysics Data System (ADS) API with 80+ operations.
## Installation
```elixir
def deps do
[
{:adsabs_client, "~> 0.1.0"}
]
end
```
## Quick Start
```bash
# 1. Set your API token
export ADS_API_TOKEN='your_token_here'
# 2. Get dependencies
mix deps.get
# 3. Start IEx
iex -S mix
# 4. Search!
{:ok, results} = AdsabsClient.search("black holes", rows: 5)
IO.inspect(results.num_found)
```
## Configuration
```elixir
# config/config.exs
import Config
config :adsabs_client,
api_token: System.get_env("ADS_API_TOKEN"),
adapter: AdsabsClient.Adapter.Req,
default_timeout: 30_000,
max_retries: 3
```
## All 80+ APIs Included
### Search API
- `search/2` - Standard search
- `stream_search/2` - Lazy streaming
- `Search.bigquery/2` - Bulk search (max 2000 bibcodes)
### Metrics API
- `metrics/2` - Get bibliometric indicators
- Citation counts, h-index, i10-index, reads, downloads
### Export API (20+ formats)
- `export/3` - Export citations
- Formats: bibtex, endnote, aastex, ris, refworks, and more
- `Export.list_formats/0` - See all formats
### Libraries API
- `list_libraries/1` - List all libraries
- `get_library/2` - Get specific library
- `create_library/3` - Create new library
- `Libraries.add_documents/3` - Add papers
- `Libraries.delete_library/2` - Delete library
### Resolver API
- `resolve/3` - Get external links
- Link types: abstract, citations, references, esource, data, etc.
### Journals API
- `Journals.summary/2` - Get journal metadata
### Reference API
- `Reference.resolve_text/2` - Resolve text references
### Author Affiliation API
- `AuthorAffiliation.search/2` - Generate collaboration reports
### Objects API
- `Objects.query/2` - Search by astronomical object
### Visualizations API
- `Visualizations.author_network/2` - Author network graphs
- `Visualizations.word_cloud/2` - Word clouds
## Usage Examples
### Basic Search
```elixir
{:ok, results} = AdsabsClient.search("author:Einstein year:1905")
IO.inspect(results.num_found)
IO.inspect(results.docs)
```
### Advanced Search
```elixir
{:ok, results} = AdsabsClient.search(
"dark matter",
rows: 100,
sort: "citation_count desc",
fl: ["bibcode", "title", "author", "year"],
fq: ["property:refereed"]
)
```
### Stream Large Results
```elixir
AdsabsClient.stream_search("exoplanets", rows: 100) |> Stream.take(500)|> Enum.each(&process_paper/1)
```
### Get Metrics
```elixir
bibcodes = ["2020ApJ...123..456A", "2019MNRAS.456..789B"]
{:ok, metrics} = AdsabsClient.metrics(bibcodes)
IO.puts("Citations: #{metrics.citation_count}")
IO.puts("h-index: #{metrics.h_index}")
IO.puts("Reads: #{metrics.read_count}")
```
### Export Citations
```elixir
{:ok, bibtex} = AdsabsClient.export(bibcodes, :bibtex)
IO.puts(bibtex)
# With options
{:ok, bibtex} = AdsabsClient.export(
bibcodes,
:bibtex,
maxauthor: 10,
keyformat: "%1H:%Y"
)
```
### Library Management
```elixir
# List libraries
{:ok, libraries} = AdsabsClient.list_libraries()
# Create library
{:ok, library} = AdsabsClient.create_library(
"My Research",
"Papers on black holes"
)
# Add papers
{:ok, _} = AdsabsClient.Libraries.add_documents(library.id, bibcodes)
```
## Error Handling
```elixir
case AdsabsClient.search("neutron stars") do
{:ok, results} ->
process_results(results)
{:error, %AdsabsClient.Error{type: :rate_limit}} ->
IO.puts("Rate limited - wait and retry")
{:error, %AdsabsClient.Error{type: :api, status: 400}} ->
IO.puts("Invalid query")
{:error, error} ->
IO.puts("Error: #{Exception.message(error)}")
end
```
## Features
- ✅ All 80+ ADS API operations
- ✅ Automatic retries with exponential backoff
- ✅ Streaming support for large datasets
- ✅ Comprehensive error handling
- ✅ Telemetry integration
- ✅ Full type specs
- ✅ Mox-based testing support
## Testing
```elixir
# test/test_helper.exs
Mox.defmock(AdsabsClient.MockAdapter, for: AdsabsClient.Adapter)
# Your test
import Mox
setup :verify_on_exit!
test "search works" do
expect(AdsabsClient.MockAdapter, :request, fn _, _, _, _, _ ->
{:ok, %{status: 200, body: %{"response" => %{}}, headers: []}}
end)
assert {:ok, _} = AdsabsClient.search("test")
end
```
## Get API Token
1. Go to https://ui.adsabs.harvard.edu/
2. Create account / log in
3. Go to https://ui.adsabs.harvard.edu/user/settings/token
4. Generate a new key
5. Set environment variable: `export ADS_API_TOKEN='your_token'`
## Rate Limits
- Regular endpoints: 5,000 requests per day
- Bigquery endpoint: 100 requests per day
## Documentation
- Full docs: https://hexdocs.pm/adsabs_client
- ADS API: https://ui.adsabs.harvard.edu/help/api
- Examples: See `examples/` directory
## License
MIT
---
# Test File
```elixir
# test/adsabs_client_test.exs
defmodule AdsabsClientTest do
use ExUnit.Case, async: true
import Mox
alias AdsabsClient.MockAdapter
setup :verify_on_exit!
describe "search/2" do
test "returns search results" do
expect(MockAdapter, :request, fn :get, _url, _headers, nil, _opts ->
{:ok, %{
status: 200,
body: %{"response" => %{"numFound" => 100, "docs" => []}},
headers: []
}}
end)
assert {:ok, result} = AdsabsClient.search("black holes")
assert result.num_found == 100
end
end
describe "metrics/2" do
test "returns metrics" do
expect(MockAdapter, :request, fn :post, _url, _headers, _body, _opts ->
{:ok, %{
status: 200,
body: %{"citation count" => 42, "h" => 5},
headers: []
}}
end)
assert {:ok, metrics} = AdsabsClient.metrics(["test"])
assert metrics.citation_count == 42
end
end
describe "export/3" do
test "exports in bibtex format" do
expect(MockAdapter, :request, fn :post, _url, _headers, _body, _opts ->
{:ok, %{
status: 200,
body: %{"export" => "@ARTICLE{test}"},
headers: []
}}
end)
assert {:ok, bibtex} = AdsabsClient.export(["test"], :bibtex)
assert bibtex =~ "@ARTICLE"
end
end
end
```
```elixir
# test/test_helper.exs
Mox.defmock(AdsabsClient.MockAdapter, for: AdsabsClient.Adapter)
Application.put_env(:adsabs_client, :adapter, AdsabsClient.MockAdapter)
Application.put_env(:adsabs_client, :api_token, "test_token")
ExUnit.start()
```
---
# .formatter.exs
```elixir
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"],
line_length: 100
]
```
---
# .gitignore
```
/_build/
/cover/
/deps/
/doc/
*.ez
adsabs_client-*.tar
erl_crash.dump
.DS_Store
.env
.env.local
```
---
# CHANGELOG.md
```markdown
# Changelog
## [0.1.0] - 2024-12-11
### Added
- Initial release
- Complete implementation of 80+ ADS API operations
- Search API with streaming support
- Metrics API for bibliometric indicators
- Export API with 20+ format support
- Libraries API for collection management
- Resolver, Journals, Reference, Author Affiliation, Objects, Visualizations APIs
- Comprehensive error handling
- Automatic retries with exponential backoff
- Telemetry integration
- Full test coverage
- Complete documentation
```
---
# LICENSE
```
MIT License
Copyright (c) 2024
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```