{"id":13801401,"url":"https://github.com/nervous-systems/kvlt","last_synced_at":"2025-05-13T11:31:09.621Z","repository":{"id":62433030,"uuid":"47879084","full_name":"nervous-systems/kvlt","owner":"nervous-systems","description":"Multi-target Clojure/script HTTP client","archived":true,"fork":false,"pushed_at":"2018-01-19T08:26:36.000Z","size":78,"stargazers_count":69,"open_issues_count":11,"forks_count":8,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-12-10T07:57:27.937Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nervous-systems.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-12-12T13:23:55.000Z","updated_at":"2024-03-01T09:56:00.000Z","dependencies_parsed_at":"2022-11-01T21:01:34.063Z","dependency_job_id":null,"html_url":"https://github.com/nervous-systems/kvlt","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nervous-systems%2Fkvlt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nervous-systems%2Fkvlt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nervous-systems%2Fkvlt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nervous-systems%2Fkvlt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nervous-systems","download_url":"https://codeload.github.com/nervous-systems/kvlt/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253932820,"owners_count":21986454,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T00:01:22.452Z","updated_at":"2025-05-13T11:31:07.228Z","avatar_url":"https://github.com/nervous-systems.png","language":"Clojure","funding_links":[],"categories":["HTTP"],"sub_categories":[],"readme":"![Hail Satan](https://raw.githubusercontent.com/nervous-systems/kvlt/master/doc/assets/kvlt.png) [![Build Status](https://travis-ci.org/nervous-systems/kvlt.svg?branch=master)](https://travis-ci.org/nervous-systems/kvlt)\n\nAttempts to present a uniform, asychronous client interface for HTTP across JVM / Node / browsers.\n\n[Latest documentation / examples](//nervous.io/doc/kvlt)\n\n[![Clojars Project](http://clojars.org/io.nervous/kvlt/latest-version.svg)](http://clojars.org/io.nervous/kvlt)\n\n### Features\n - Supports Clojure/JVM, Clojurescript/Node and Clojurescript/Browser\n - Individual deferred values are exposed via promises ([kvlt.core](//nervous.io/doc/kvlt/kvlt.core.html)), or asynchronous channels ([kvlt.chan](//nervous.io/doc/kvlt/kvlt.chan.html))\n - `core.async`-based support for Websockets and Server-sent Events\n - Raw responses available as Javascript typed arrays (on Node, and in browsers with [XHR Level 2](https://www.w3.org/TR/XMLHttpRequest2/) support)\n - Ring-like API\n\n### Requirements\n\n - Clojure use requires JDK8\n\n### Todo / Notes\n - Automated/CI testing is currently limited to JVM, Node and recent Chrome \u0026 Firefox builds\n - No support for streamed requests/responses.  Open to suggestions about how this might be handled across platforms\n - Young project, etc. - please file issues\n\n# Examples\n\n[kvlt.core/request!](//nervous.io/doc/kvlt/kvlt.core.html#var-request.21)\nreturns a [promesa](https://github.com/funcool/promesa) promise, which\ncan be manipulated using promise-specific (e.g. `promesa/then`)\noperations, or treated as a monad using the primitives from\n[cats](https://github.com/funcool/cats).  Below, we're working with\nsomething like:\n\n```clojure\n(ns kvlt.examples\n  (:require [kvlt.core :as kvlt]\n            [promesa.core :as p]))\n```\n\nThe default `:method` is `:get`:\n\n```clojure\n(p/alet [{:keys [status]} (p/await (kvlt/request! {:url url}))]\n  (is (= status 200)))\n```\n\n## Explicit Callback\n\n```clojure\n(p/then\n (kvlt/request! {:url url})\n (fn [{:keys [status]}]\n   (is (= status 200))))\n```\n\n## core.async\n\nThe [kvlt.chan](//nervous.io/doc/kvlt/kvlt.chan.html) namespace\nparallels the promise-driven `kvlt.core`, using asynchronous channels\nto communicate deferred values.\n\n```clojure\n(go\n  (let [{:keys [status]} (\u003c! (kvlt.chan/request! {:url url}))]\n    (is (= status 200))))\n```\n\n## Writing Data\n\nIn addition to Ring-style `:form-params`/`:type`, metadata may be\napplied to `:body`, indicating the desired content-type and body\nserialization:\n\n```clojure\n(p/alet [{:keys [body]}\n         (p/await\n          (kvlt/request!\n           {:url    url\n            :method :post\n            :body   ^:kvlt.body/edn {:hello \"world\"}\n            :as     :auto}))]\n  (is (= (body :hello) \"world\")))\n```\n\n`:as :auto` causes the `:body` key in the response to be processed in\naccord with the response's content-type.  `:as :edn`, in this case,\nwould have the same effect.\n\n## Errors\n\n```clojure\n(p/catch\n (kvlt/request! {:url (str url \"/404\")})\n (fn [e]\n   (is (= :not-found ((ex-data e) :type)))))\n```\n\nAll requests resulting in exceptional response codes, or more\nfundamental (e.g. transport) errors will cause the returned promise's\nerror branch to be followed with an\n[ExceptionInfo](https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/ExceptionInfo.java)\ninstance - i.e. an Exception/Error with an associated response map\nretrievable via `ex-data`.\n\n### Example Map\n\n``` clojure\n{:headers {:content-type \"text/plain\" ...}\n :type   :not-found\n :reason :not-found\n :status 404\n ...}\n```\n\n[More request/response examples](https://nervous.io/doc/kvlt/01-req-resp-examples.html)\n\n## [Server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)\n\n```clojure\n(def events (kvlt.core/event-source! url))\n```\n\n`events` is a `core.async` channel (rather, something a lot like a\n`core.async` channel, which'll terminate the SSE connection when\n`async/close!`'d).\n\nAssuming no event types or identifiers are supplied by the server, a\nvalue on `events` looks something like:\n\n```clojure\n{:type :message\n :data \"String\\nfrom\\nthe server\"}\n```\n\n[More SSE examples](//nervous.io/doc/kvlt/02-event-source-examples.html)\n\n## Websockets\n\n[kvlt.core/websocket!](https://nervous.io/doc/kvlt/kvlt.core.html#var-websocket.21)\ntakes a URL, and returns a promise which'll resolve to a `core.async`\nchannel:\n\n``` clojure\n(p/alet [ws (p/await (kvlt/websocket! \"http://localhost:5000/ws\" {:format :edn}))]\n  (go\n    (\u003e! ws {:climate :good, :bribery :tolerated})\n    (let [instructions (\u003c! ws)]\n      (is (instructions :proceed?)))))\n```\n\nClosing the `ws` channel will terminate the websocket connection.\n\n[More Websocket examples](https://nervous.io/doc/kvlt/03-websocket-examples.html)\n\n# License\n\nkvlt is free and unencumbered public domain software. For more\ninformation, see http://unlicense.org/ or the accompanying UNLICENSE\nfile.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnervous-systems%2Fkvlt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnervous-systems%2Fkvlt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnervous-systems%2Fkvlt/lists"}