Skip to content

Instantly share code, notes, and snippets.

@mtnygard
Created May 18, 2017 13:06
Show Gist options
  • Select an option

  • Save mtnygard/ba94bdf50140ccaf09554517b1b91121 to your computer and use it in GitHub Desktop.

Select an option

Save mtnygard/ba94bdf50140ccaf09554517b1b91121 to your computer and use it in GitHub Desktop.
Mixing Vase routes with hand-written routes in a single service
;; This is a Component that starts up a Vase API from a descriptor file.
(ns control-server.api
(:require [com.stuartsierra.component :as component]
[com.cognitect.vase :as vase]))
(defrecord VaseAPI [api-root specs routes]
component/Lifecycle
(start [this]
(vase/ensure-schema specs)
(vase/specs specs)
(assoc this :routes (vase/routes api-root specs)))
(stop [this]
(assoc this :routes nil)))
(defn from-resource [api-root resource-name]
(->VaseAPI api-root [(vase/load-edn-resource resource-name)] nil))
(defn datomic-uri [api]
(-> api :specs first :datomic-uri))
;; This component has a route (on line 20) that maps to an ordinary Pedestal interceptor (control-events).
;; ---------
(defrecord Reactor [database datomic-uri controls conn routes tx-ch]
component/Lifecycle
(start [this]
(log/info :message "Starting event broadcaster")
(let [conn (database/connection database)
db (d/db conn)
control-eids (control-eids db)
clock-eid (d/entid db :world-clock)
actual-state (d/entid db :control/actual-state)
xf (classify-tx-report control-eids actual-state clock-eid)
tx-ch (a/chan (a/dropping-buffer 100) xf (log-error :tx-report-channel))]
(tx-report->channel conn tx-ch)
(channel->network tx-ch)
(assoc this
:conn conn
:routes #{["/api/control-server/v1/control-events" :get control-events]}
:tx-ch tx-ch)))
(stop [this]
(log/info :message "Stopping event broadcaster")
(when conn
(d/remove-tx-report-queue conn))
(when tx-ch
(a/close! tx-ch))
(killall-clients!)
(assoc this
:conn nil
:tx-ch nil
:routes nil)))
(defn reactor []
(map->Reactor {}))
;; This fragment is from a Component that starts a Pedestal listener. It gets its routes from 3 places:
;; 1. The healthcheck route built into this Component
;; 2. The API Component
;; 3. The Broadcaster Component (shown below)
;;
;; It merges the routes together and uses them for the endpoint.
(defn routes [& contribs]
(http.route/expand-routes
(reduce into #{["/healthcheck" :get `healthcheck]} (map :routes contribs))))
(defrecord HTTPEndpoint [service api broadcaster]
component/Lifecycle
(start [this]
(log/info :message "Starting HTTP endpoint" :port (::http/port service) :apis (:activated-apis api))
(assoc this :service
(-> service
;; TODO - make ::http/routes a val instead of a fn in prod.
(assoc ::http/routes #(routes api broadcaster))
http/default-interceptors
(cond-> (::dev? this) http/dev-interceptors)
http/create-server
http/start)))
(stop [this]
(when service
(log/info :message "Stopping HTTP endpoint" :port (::http/port service))
(try (http/stop service)
(catch Throwable t
(log/error :message "Error in Pedestal stop" :exception t))))
(assoc this :service nil)))
(defn service-map
"Returns initial service map for the Pedestal server."
[]
{::http/type :jetty
::http/port 8000
::http/join? false})
(defn http-endpoint
"Returns the Pedestal server component."
[]
(map->HTTPEndpoint {:service (service-map)}))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment