Liking cljdoc? Tell your friends :D


Clojars Project

A Clojure library to make Gemini requests that exposes some low-level API to handle network requests.


Import the library for e.g. with:

user=> (require '[gemini.core :as gemini])


fetch makes a Gemini request. The request needs to be closed afterwards using close.

Takes a map with the following keys (only :request is mandatory):

  • :proxy: a map of :host and :port, identifies the server to send the requests to. This allows to use a gemini server as a proxy, it doesn't do any other kind of proxying (e.g. SOCK5.)
  • :request the URI (as string) to require.
  • :follow-redirects? if false or nil don't follow redirects, if true follow up to 5 redirects, or the number of redirects to follow.

Returns a map with :error key if an error occur or with the following fields if it succeeds:

  • :uri: the URI of the request. May be different from the requested one if :follow-redirects? was specified.
  • :request: the object backing the request.
  • :code and :meta are the parsed header response.
  • :body an instance of a BufferedReader. Note: closing the body is not enough, always call clase on the returned map.
  • :redirected? true if a redirect was followed.
user=> (gemini/fetch {:request "gemini://"
                      :follow-redirects? true})
{:uri "gemini://",
 #object[com.omarpolo.gemini.Request 0x6fa9ec6f "com.omarpolo.gemini.Request@6fa9ec6f"],
 :code 20,
 :meta "text/gemini",
 #object[ 0x18a8d9e0 ""],
 :redirected? true}

body-as-string! reads all the response into a string and returns it. It also closes the request automatically.

user=> (-> {:request "gemini://"}
"# Project Gemini\n\n## Overview\n\nGemini is a new internet protocol which..."

close closes a request. It needs to be called after every request.

user=> (let [req (gemini/fetch {,,,})]
         (when-not (:error req)
           ;; do something with req
           (gemini/close req)))

with-request is a macro like with-open to making connection easily. It automatically closes the request and evaluates the body only when the request is successful, otherwise throws an exception.

user=> (gemini/with-request [req {:request "gemini://"}]

Streaming content

The :body keyword in the returned map is an instance of a Java BufferedReader, so streaming content is easy.

However, body-as-string! needs to materialise the full reply, so in case of a streaming request it will never return!


This library only implements the network part of Gemini, it doesn't try to handle any kind of content. To handle text/gemini you can use e.g. the gemtext library:

user=> (require '[gemtext.core :as gemtext])
user=> (gemini/with-request [req {:request "gemini://"}]
         (gemtext/parse (:body req)))
[[:header-1 "Project Gemini"]
 [:text ""]
 [:header-2 "Overview"]
 [:text ""]
 [:text "Gemini is a new internet protocol which:"]

The gemtext library supports streaming via the gemtext.core/parse transducer:

user=> (gemini/with-request [req {:request "gemini://"}]
         (transduce gemtext/parser conj [] (line-seq (:body req))))


Copyright © 2021 Omar Polo, all rights reserved.

Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.

Can you improve this documentation?Edit on GitHub

cljdoc is a website building & hosting documentation for Clojure/Script libraries

× close