Liking cljdoc? Tell your friends :D

Rocksky Clojure SDK

Clojars

An idiomatic, pipe-friendly Clojure client for the Rocksky XRPC API.

  • Plain maps in, plain maps out — no records, no protocols to learn.
  • Client-first arg — every endpoint threads through ->.
  • No global state — clients are values you can pass around and reuse across threads.
  • Two real verbsquery (GET) and procedure (POST) cover the whole XRPC surface. Resource namespaces are thin wrappers on top.

Install

deps.edn:

{:deps {app.rocksky/sdk {:mvn/version "0.1.1-SNAPSHOT"}}}

Leiningen / Boot:

[app.rocksky/sdk "0.1.1-SNAPSHOT"]

Or, to track a specific commit instead of a release:

{:deps {app.rocksky/sdk {:git/url   "https://github.com/tsirysndr/rocksky"
                         :git/sha   "..."
                         :deps/root "sdk/clojure"}}}

Quickstart

(require '[rocksky.core :as rs])

(def client (rs/client))                ;; defaults to https://api.rocksky.app

(rs/get-profile client {:did "did:plc:7vdlgi2bflelz7mmuxoqjfcr"})
;; => {:handle "tsiry-sandratraina.com" :followersCount 42 ...}

For authenticated endpoints, pass a bearer token:

(def client (rs/client {:token (System/getenv "ROCKSKY_TOKEN")}))

(require '[rocksky.scrobble :as scrobble])
(scrobble/create-scrobble client
                          {:title  "Paranoid Android"
                           :artist "Radiohead"
                           :album  "OK Computer"})

Pipe-friendly composition

Clients are immutable values; every helper that mutates state returns a new client. That makes it natural to build, authenticate, and call in one threading expression:

(require '[rocksky.client :as c]
         '[rocksky.actor  :as actor])

(-> (c/client {:base-url "https://api.rocksky.app"})
    (c/with-token (System/getenv "ROCKSKY_TOKEN"))
    (actor/get-profile {:did "did:plc:7vdlgi2bflelz7mmuxoqjfcr"})
    :handle)
;; => "tsiry-sandratraina.com"

Or reshape responses inline:

(require '[rocksky.charts :as charts])

(->> (charts/get-top-tracks (c/client) {:limit 5})
     :tracks
     (map :title))
;; => ("Paranoid Android" "Karma Police" ...)

Calling URLs the SDK doesn't wrap

Anything missing from the resource namespaces is one line away — the generic query / procedure helpers accept any NSID.

(c/query    client :app.rocksky.feed.describeFeedGenerator)
(c/procedure client :app.rocksky.shout.createShout {:message "hi"})

Errors

Non-2xx responses throw ex-info. Catch it and inspect the ex-data:

(try
  (album/get-album client {:uri "at://missing"})
  (catch clojure.lang.ExceptionInfo e
    (let [{:keys [status nsid body]} (ex-data e)]
      (println status nsid body))))

Concurrency

A client is a value — share it across threads with pmap / future:

(pmap #(actor/get-profile client {:did %}) handles)

Available namespaces

NamespaceWraps
rocksky.actorapp.rocksky.actor.*
rocksky.albumapp.rocksky.album.*
rocksky.apikeyapp.rocksky.apikey.*
rocksky.artistapp.rocksky.artist.*
rocksky.chartsapp.rocksky.charts.*
rocksky.dropboxapp.rocksky.dropbox.*
rocksky.feedapp.rocksky.feed.*
rocksky.googledriveapp.rocksky.googledrive.*
rocksky.graphapp.rocksky.graph.*
rocksky.likeapp.rocksky.like.*
rocksky.mirrorapp.rocksky.mirror.*
rocksky.playerapp.rocksky.player.*
rocksky.playlistapp.rocksky.playlist.*
rocksky.scrobbleapp.rocksky.scrobble.*
rocksky.shoutapp.rocksky.shout.*
rocksky.songapp.rocksky.song.*
rocksky.spotifyapp.rocksky.spotify.*
rocksky.statsapp.rocksky.stats.*

Conventions

  • Kebab-case Clojure side, camelCase wire side. The SDK translates :start-datestartDate, :album-artalbumArt, etc., so you can write idiomatic Clojure params. The raw HTTP body / query string still uses camelCase, matching the lexicons under apps/api/lexicons.
  • Nil values are dropped. Pass :limit nil and the param won't appear on the wire — handy for building params with cond->.
  • Booleans round-trip. :enabled false is preserved (not coerced to nil) so toggles work correctly.

Examples

Browse the examples/ directory:

FileShows
01_quickstart.cljSmallest possible call
02_pipe_friendly.cljThreading construction → auth → request
03_paginate_scrobbles.cljLazy pagination over offset endpoints
04_scrobble_a_track.cljAuthenticated POST
05_search_and_listen.cljSearch → drill down
06_error_handling.cljCatching ex-info from non-2xx
07_concurrent_requests.cljpmap across a shared client

Development

# Run the test suite
clojure -X:test

# Start an nREPL on localhost:7888
clojure -M:nrepl

The tests mock the HTTP layer by passing :http-fn to client, so they run offline and finish in well under a second.

Publishing

The SDK ships with a tools.build + deps-deploy pipeline. From this directory:

clojure -T:build clean
clojure -T:build jar        # build the jar in target/
clojure -T:build install    # install locally to ~/.m2 for testing
clojure -T:build deploy     # publish to Clojars

Deploying needs Clojars credentials in the environment:

export CLOJARS_USERNAME=your-username
export CLOJARS_PASSWORD=your-clojars-deploy-token   # NOT your password
clojure -T:build deploy

Bump version in build.clj and add a new entry to CHANGELOG.md before deploying. The default release tag pattern is sdk-clojure-v<version>.

License

MIT © Tsiry Sandratraina.

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close