Home

Awesome

Kekkonen Build Status

<img src="https://raw.githubusercontent.com/wiki/metosin/kekkonen/kekkonen.png" align="right"/>

A lightweight, data-driven library for creating and consuming remote service with Clojure(Script). Key features:

Bubblin' Under:

<sub>Picture of UKK © Pressfoton Etyk 1975 -team, Museovirasto</sub>

See Live demo & Wiki.

Latest version

Clojars Project

Quickstart: lein new kekkonen kakkonen

Basic building blocks

Handler

{:name ::plus
 :type :handler
 :interceptors []
 :input {:data {:y s/Int
                :x s/Int}}
 :output s/Int
 :handle (fn [{{:keys [x y]} :data}]
           (+ x y))}

Interceptor

{:name ::require-roles
 :enter (fn [context]
          (let [roles (-> context :user :roles)]
            (if (seq (clojure.set/intersection roles required))
              context)))}

Hello World (local dispatch)

(require '[kekkonen.core :as k])

(def dispatcher
  (k/dispatcher
    {:handlers
     {:api (k/handler {:name :hello
                       :handle (constantly "hello world"))}}}))

(k/invoke dispatcher :api/hello)
; => "hello world"

Hello World (ring-based Query API)

(require '[kekkonen.cqrs :refer :all])
(require '[org.httpkit.server :as server])

(defn ^:query hello
  {:input {:data {:name String}}}
  [ctx]
  (success (str "Hello, " (-> ctx :data :name))))

(server/run-server
  (cqrs-api {:core {:handlers #'hello}}})
  {:port 4000})

you can invoke the hello api with http://localhost:4000/hello?name=World

CQRS API with Swagger Docs

(ns example.api
  (:require [org.httpkit.server :as server]
            [kekkonen.cqrs :refer :all]
            [plumbing.core :refer [defnk]]
            [schema.core :as s]))

;;
;; Schemas
;;

(s/defschema Pizza
  {:name s/Str
   (s/optional-key :description) s/Str
   :size (s/enum :S :M :L)
   :origin {:country (s/enum :FI :PO)}})

;;
;; Handlers
;;

(defnk ^:query ping []
  (success {:ping "pong"}))

(defnk ^:command echo-pizza
  "Echoes a pizza"
  {:responses {:default {:schema Pizza}}}
  [data :- Pizza]
  (success data))

(defnk ^:query plus
  [[:data x :- s/Int, y :- s/Int]]
  (success {:result (+ x y)}))

(defnk ^:command inc! [counter]
  (success {:result (swap! counter inc)}))

;;
;; Application
;;

(def app
  (cqrs-api
    {:swagger {:ui "/api-docs"
               :spec "/swagger.json"
               :data {:info {:title "Kekkonen example"}}}
     :core {:handlers {:api {:pizza #'echo-pizza
                             :example [#'ping #'inc! #'plus]}}
            :context {:counter (atom 0)}}}))

;;
;; Start it
;;

(comment
  (server/run-server #'app {:port 3000}))

Start the server and browse to http://localhost:3000/api-docs and you should see the following:

swagger-example

More examples at /examples and info in the Wiki.

Roadmap

Mostly written as issues. Biggest things:

Presentations

Thinking aloud

Why not just use multimethods for dispatch?

Clojure multimethods introduce mutable implicit state. With multimethods, by requiring a namespace x you could get an extra methods for a multimethod as a side-effect. For internal functionality (like in the cljs frontends), it's totally awesome and polymorphic.

For remoting, things should be explicit and secure. With Kekkonen, handler registration is explicit and security works like the UNIX directory structure: by not having access to namespace :api.admin, you can't have access to any anything (sub-namespaces or handler) under that, regardless of their access policies.

HTTP is awesome, why hide it?

Yes, it is awesome, and is used as a transport. But do you really want to handcraft you domain into POSTs, PUTs and PATCHes do reverse-engineer back in the client? Is it easy to consume APIs that return status codes 451 or the 226?

Kekkonen tries to keep things simple. By abstracting the HTTP we can use plain clojure, websockets or queues without change in the interaction semantics.

Looks similar to Fnhouse?

Yes, we have reused many great ideas from fnhouse, see Special Thanks. Initial version of Kekkonen was supposed to be built on top of fnhouse but the we realized that most of the fnhouse internals would have had to be overridden due to difference in opinions.

Is this an actor lib?

No. But we might integrate into Pulsar.

Special thanks

License

Copyright © 2015-2018 Metosin Oy

Distributed under the Eclipse Public License 2.0.