This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-09-12
Channels
- # beginners (63)
- # boot (3)
- # braveandtrue (153)
- # cider (19)
- # cljdoc (2)
- # clojure (80)
- # clojure-dev (25)
- # clojure-italy (73)
- # clojure-losangeles (1)
- # clojure-nl (4)
- # clojure-spec (67)
- # clojure-sweden (1)
- # clojure-uk (83)
- # clojurescript (56)
- # clojutre (11)
- # core-logic (37)
- # cursive (18)
- # datomic (14)
- # editors (10)
- # emacs (13)
- # figwheel-main (11)
- # fulcro (62)
- # graphql (11)
- # jobs (3)
- # klipse (1)
- # leiningen (6)
- # off-topic (91)
- # onyx (7)
- # pedestal (3)
- # portkey (5)
- # re-frame (14)
- # reagent (13)
- # remote-jobs (1)
- # shadow-cljs (111)
- # tools-deps (4)
- # yada (10)
What middleware? There is Fulcro logic, but all the middleware used comes from other libs, mainly ring. Encoding with transit
https://github.com/fulcrologic/fulcro/blob/develop/src/main/fulcro/server.clj#L214
So, that was in response to people asking for minimal dependencies, as expressed in the comments on line 138. You see, it is highly desirable to use the server namespace to get the API logic, but you don’t have to use Ring (unless you use the other nses like easy server that require it dynamically).
Thanks @U0CKQ19AQ currently trying to build my own server using http://book.fulcrologic.com/#BuildingAServer and this one uses various ring middlewares. That’s why I started to wonder 🙂
Why is that?
I want to expose this as an ion, so the web server is really a way to interact with it in dev. I’ll only expose the handler as an ion when I push this to production
Well, easy server was an early addition for quick dev startup, and started to turn into a swiss army knife. The modular server was an attempt to make the server extensible for external libraries, but since adopting the central server-mutate and read, it is unnecessary, and also too complicated to set up…so, rolling your own for production is best. Easy server is great for getting started, but as soon as you get to the point of needing to add middleware you should move to rolling your own.
And…rolling your own is very simple, can be used with standard Ring patterns very easily.
The modular stuff is just baggage from too rapidly adding something to the lib before we’d run it through real paces…it’s why I’m trying to do things like that in incubator now…easier to promote them than to remove them later.
What modular stuff?
nice 😛
I’m still trying to understand the defmutation
macro in the server file 😄
there is a central parser: server-parser…it has a read and write entry point function
Right, but it relies on injecting a database through the env?
https://clojureverse.org/t/what-are-paradigm-differences-between-different-front-end-clojurescript-libraries/2832 hoping this will turn into an interesting thread 🙂 No clue how to "properly" describe fulcro "paradigm and approaches" compared to the others there.
Is it not possible to have a single way to handle querying rooted at an entity id using datomic? The pattern seems to be to get a particular collection through a query in datomic using the datalog API and then using pull once you want a particular entity tree without change to the query
@pvillegas12 you can use lookup refs with pull
I guess
(defn wrap-api [handler uri]
(fn [request]
(if (= uri (:uri request))
(server/handle-api-request
server-parser
;; this map is `env`. Put other defstate things in this map and they'll be in the mutations/query env on server.
{:config config}
(:transit-params request))
(handler request))))
is the only part that makes defmutation
work, but I’m not sure how the wiring works around the parameters defmutation
receives. How does the parser work at a conceptual level?The parser is described elsewhere in the book….it is a function that parses the query/tx, and calls a read and write hook for each element of the tx
The built-in instance called server-parser
predefines the read/write handlers, which the defmutation and defquery just create multimethod entries for
The handle-api-request calls this parser every time an incoming request is handled, and it passes the env to the parser, which forwards it to the mutations/queries
Integrating with datomic, I could either inject the db
there or manually call the the connection and client in each defmutation
. Does that sound right?
I personally refer to the defstate items in the wrap-api, so they appear in env, so everything is less coupled
so, my Datomic stuff goes in config, then I refer to the config stuff in the defstate
thing that holds the connection…so states refer to states, but the rest of the app can just think about the env.
yeah I know 😛
(defstate main-connection
:start (try
(let [db-uri (get config :db-uri)
db (d/create-database db-uri)
c (if (should-mock? db-uri)
(mock-conn (d/db (d/connect db-uri)))
(d/connect db-uri))]
(log/info (format "Starting database %s" db-uri))
(when (should-mock? db-uri)
(log/warn "USING A MOCKED CONNECTION. No changes to the database will persist.")
(when-not mocking-ok?
(throw (ex-info "REFUSING TO START a database that has SNAPSHOT migrations. Please set allow.mocked.connection JVM property if you want to allow this." {}))))
(log/info "Running Migrations")
(try
(run-migrations c)
(catch Exception e
(.printStackTrace e)
(log/error "Database Migration failed:")
(throw e)))
c)
(catch Exception e
(log/error "Database startup failed." e)
(throw e))))
and {:db-uri "datomic..."}
in my defaults.edn
config file.
Of course, if you want to support more databases, you might use a more complex structure in the config
mock-conn
comes from https://github.com/vvvvalvalval/datomock
thanks for all of the above very useful! 👍 What do you mean by migrations? I thought they were not necessary with datomic
technically you do run into situations where you want things applied in order, and also I do “snapshot” migrations (I’ve elided those here)
where if a schema change is named with “snapshot”, then it forces a mocked connection
I see