Dox is an Elixir library for interacting with the DigitalOcean API v2. It provides a clean, idiomatic Elixir interface for managing DigitalOcean resources.
- Complete API Coverage - Supports all DigitalOcean API resources including Droplets, Volumes, Databases, Kubernetes, and more
- Plugin System - Extend request behavior with custom plugins for retry logic, logging, caching, metrics, etc.
- Type-safe Responses - Returns structured response objects with type specifications
- Error Handling - Comprehensive error handling with detailed error information
- HTTP Client - Built on top of Finch for reliable HTTP requests
- OTP Application - Supervised HTTP connection pools for production use
Add dox to your dependencies in mix.exs:
def deps do
[
{:dox, "~> 0.1.0"}
]
end# Configure your API token
token = System.get_env("DIGITALOCEAN_TOKEN")
# List all droplets
{:ok, response} = Dox.Droplets.list(token: token)
# Get a specific droplet
{:ok, response} = Dox.Droplets.get(12345, token: token)
# Create a droplet
{:ok, response} = Dox.Droplets.create(
name: "my-droplet",
region: "nyc1",
size: "s-1vcpu-1gb",
image: "ubuntu-20-04-x64",
token: token
)
# Use bang versions to raise on error
response = Dox.Droplets.list!(token: token)You can set your API token in your application config:
# config/config.exs
config :dox, api_token: System.get_env("DIGITALOCEAN_TOKEN")Then use resources without passing the token each time:
# Uses token from config
{:ok, response} = Dox.Droplets.list()Alternatively, you can pass the token directly to each function:
{:ok, response} = Dox.Droplets.list(token: "your_api_token")The per-request token takes precedence over the config token if both are set.
Configure custom plugins in your application config:
# config/config.exs
config :dox, plugins: [MyPlugin]Dox provides modules for all DigitalOcean API resources:
| Module | Description |
|---|---|
Dox.Account |
Account information and SSH keys |
Dox.Actions |
Actions (async operations) |
Dox.Apps |
App Platform |
Dox.Cdn |
CDN endpoints |
Dox.Certificates |
SSL certificates |
Dox.Databases |
Managed databases |
Dox.Domains |
DNS domains |
Dox.Droplets |
Virtual servers |
Dox.Firewalls |
Firewall rules |
Dox.FloatingIps |
Floating IPs |
Dox.Images |
Images and snapshots |
Dox.Kubernetes |
Kubernetes clusters |
Dox.LoadBalancers |
Load balancers |
Dox.OneClicks |
1-Click applications |
Dox.Projects |
Projects |
Dox.Regions |
Available regions |
Dox.Registries |
Container registries |
Dox.ReservedIps |
Reserved IPs |
Dox.Sizes |
Available droplet sizes |
Dox.Snapshots |
Snapshots |
Dox.Tags |
Resource tags |
Dox.Volumes |
Block storage volumes |
Dox.Vpcs |
Virtual private clouds |
Each function returns a tuple {:ok, response} or {:error, error}. You can also use bang versions that raise on errors:
# Non-bang version - returns error tuple
case Dox.Droplets.get(12345, token: token) do
{:ok, droplet} ->
IO.puts("Got droplet: #{droplet.name}")
{:error, %Dox.Error{message: message}} ->
IO.puts("Error: #{message}")
end
# Bang version - raises on error
droplet = Dox.Droplets.get!(12345, token: token)The Dox.Error struct contains:
message- Human-readable error messagestatus_code- HTTP status code (if available)response- Full API response body (if available)reason- Atom indicating the error type (:api_error,:timeout,:connect_timeout, etc.)
Dox supports plugins that can modify request and response behavior. Plugins are useful for:
- Retry logic
- Logging and debugging
- Caching
- Metrics collection
- Request/response transformation
defmodule MyPlugin do
@behaviour Dox.Plugin
@impl true
def init(opts) do
# Initialize plugin state
{:ok, %{request_count: 0}}
end
@impl true
def before_request(request, state) do
# Modify request (add headers, log, etc.)
new_headers = [{"x-my-plugin", "active"} | request.headers]
{%{request | headers: new_headers}, state}
end
@impl true
def after_response(response, state, request) do
# Process response (log, cache, etc.)
IO.puts("Request completed with status #{response.status}")
{:ok, response, state}
end
endOr use the use Dox.Plugin macro for default implementations:
defmodule SimplePlugin do
use Dox.Plugin
@impl true
def init(opts) do
{:ok, opts}
end
# before_request and after_response use default implementations
endPlugins can be configured globally or per-request:
# Per-request plugins
Dox.Droplets.list(token: token, plugins: [MyPlugin])
# Global plugins (in config/config.exs)
# config :dox, :plugins, [MyPlugin]All resource functions accept the following options:
| Option | Type | Description |
|---|---|---|
token |
string | Required. Your DigitalOcean API token |
params |
map | Query parameters |
body |
map | Request body (for POST/PUT/PATCH) |
plugins |
list | List of plugins to apply |
receive_timeout |
integer | Response receive timeout (default: 30000ms) |
connect_timeout |
integer | Connection timeout (default: 10000ms) |
# List all droplets with pagination
{:ok, response} = Dox.Droplets.list(
token: token,
params: %{per_page: 100, page: 1}
)
# Create a droplet with user data
{:ok, response} = Dox.Droplets.create(
name: "web-server",
region: "nyc1",
size: "s-2vcpu-2gb",
image: "ubuntu-20-04-x64",
user_data: "#!/bin/bash\necho 'Hello World' > /tmp/hello",
backups: true,
ipv6: true,
token: token
)
# Delete a droplet
{:ok, _response} = Dox.Droplets.delete(12345, token: token)
# Get droplet action status
{:ok, response} = Dox.Droplets.action(12345, action_id: 123, token: token)# Create a volume
{:ok, response} = Dox.Volumes.create(
name: "my-volume",
region: "nyc1",
size_gigabytes: 10,
token: token
)
# Attach volume to droplet
{:ok, response} = Dox.Volumes.attach(
volume_id: "volume-uuid",
droplet_id: 12345,
token: token
)# Create a Kubernetes cluster
{:ok, response} = Dox.Kubernetes.create_cluster(
name: "my-cluster",
region: "nyc1",
version: "1.27",
node_pools: [
%{
name: "worker-pool",
size: "s-2vcpu-2gb",
count: 3
}
],
token: token
)
# Get cluster credentials
{:ok, response} = Dox.Kubernetes.get_credentials(cluster_id: "cluster-uuid", token: token)# Create a managed database
{:ok, response} = Dox.Databases.create(
name: "my-db",
engine: "pg",
version: "15",
region: "nyc1",
size: "db-s-dev-git",
token: token
)
# Create a database user
{:ok, response} = Dox.Databases.create_user(
cluster_id: "cluster-uuid",
name: "admin",
token: token
)mix test # Run tests
mix test --cover # Run tests with coverage
mix credo --strict # Run linter
mix dialyxir # Run type checker
mix ci # Run full CI pipelinemix docs # Generate documentation
mix hex.build # Build package for Hex
mix hex.publish # Publish to HexMIT License - see LICENSE for details.
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests and linter
- Submit a pull request
- Finch - HTTP client used by Dox
- DigitalOcean API Documentation - Official API reference