Hex.pm Hexdocs CI Coverage Status License: MIT

Elixir client for the Dropbox API v2, built on Req.

Like the bird, Magpie collects and stashes your things — in your Dropbox.

Installation

def deps do
  [
    {:magpie, "~> 0.5"}
  ]
end

No configuration is required. Endpoint URLs and extra Req options can be set with config :magpie, ... — see the Magpie module docs.

Quick start

# A refresh token keeps the client working indefinitely — Magpie mints
# access tokens as needed (see the OAuth guide)
client =
  Magpie.Client.new(
    refresh_token: System.fetch_env!("DROPBOX_REFRESH_TOKEN"),
    app_key: System.fetch_env!("DROPBOX_APP_KEY"),
    app_secret: System.fetch_env!("DROPBOX_APP_SECRET")
  )

# For a quick script, a static access token works too (Dropbox expires it in ~4h)
client = Magpie.Client.new("DROPBOX_ACCESS_TOKEN")

alias Magpie.Storage

{:ok, %Magpie.FileMetadata{size: size}} =
  Storage.put(client, "/Backup/report.pdf", {:file, "priv/report.pdf"})

{:ok, contents} = Storage.get(client, "/Backup/report.pdf")
{:ok, url} = Storage.url(client, "/Backup/report.pdf")

# Large downloads stream directly to disk instead of living in BEAM memory
{:ok, "tmp/report.pdf"} =
  Storage.download(client, "/Backup/report.pdf", "tmp/report.pdf", mkdir_p: true)

Every call returns {:ok, result} on success or {:error, %Magpie.Error{}} on API errors — with the HTTP status, Dropbox's error_summary and the full error body. Files, folders and deleted entries come back as Magpie.FileMetadata, Magpie.FolderMetadata and Magpie.DeletedMetadata structs:

for %Magpie.FileMetadata{name: name, size: size, server_modified: at} <- entries do
  "#{name}: #{size} bytes, modified #{DateTime.to_date(at)}"
end

Features

  • Simple storage APIMagpie.Storage covers the common path with put, get, download, delete, exists?, stat, list, stream and temporary URLs. Upload a local file, binary/iodata or arbitrary stream; large transfers automatically use Dropbox upload sessions and downloads stream atomically to disk.
  • Complete coverage — all current user-scoped routes of the Dropbox API v2 (files, sharing, file_properties, file_requests, users, account, auth, check, contacts, openid), verified against the official dropbox-api-spec. Dropbox Business (/team/*) routes are out of scope.
  • Typed metadata — the files endpoints decode Dropbox's metadata into structs with DateTime timestamps and a first-class content_hash, and Magpie.Metadata.content_hash/1 computes the same hash locally to verify a transfer
  • OAuth 2 & token refresh — authorization URL, PKCE, code exchange, and a supervised Magpie.Auth.TokenServer that keeps access tokens fresh (proactively, and on expired_access_token) with single-flight refreshes. Store tokens wherever you want by implementing Magpie.Auth.TokenProvider.
  • High-level flowsMagpie.Files.upload_file/4 picks single request or chunked upload session by size and streams from disk; Magpie.Pager hides cursor pagination behind a lazy Stream; Magpie.Async.await/4 polls async batch jobs with exponential backoff.
  • Phoenix & LiveView uploadsMagpie.LiveView.UploadWriter streams a LiveView upload straight into a Dropbox upload session (no disk spooling), and Magpie.LiveView.presign_upload/4 lets the browser post directly to Dropbox. Magpie does not depend on :phoenix_live_view.
  • Offline testing — route every request to Req.Test stubs with config :magpie, req_options: [plug: {Req.Test, Magpie}].

Documentation

The API reference lives on HexDocs, along with the guides:

  • Examples — the complete Magpie.Storage workflow plus recipes for lower-level uploads, downloads, lazy listing, batch jobs, shared links, error handling and testing your app
  • OAuth 2 & token refresh — getting a refresh token, the web redirect flow, PKCE, running the token server, persisting tokens and custom providers
  • Phoenix & LiveView uploads — controllers, UploadWriter, direct browser → Dropbox uploads
  • Upgrading to 0.4 — every call whose result changed with typed metadata, with 0.3 and 0.4 side by side

Development

The test suite runs entirely offline against Req.Test stubs:

mix test            # run the suite
mix coveralls       # run with coverage report

Origin

Magpie started as a fork of sger/elixir_dropbox, which is no longer maintained. It has since been rewritten on top of Req/Jason with a new offline test suite. Credit and thanks to the original Elixir Dropbox contributors.

License

MIT — see LICENSE.