Fork me on GitHub
#fulcro
<
2018-09-12
>
tony.kay05:09:56

What middleware? There is Fulcro logic, but all the middleware used comes from other libs, mainly ring. Encoding with transit

tony.kay15:09:23

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).

tony.kay15:09:02

It’s also the reason that I split easy server out into its own ns

pvillegas1219:09:24

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 🙂

tony.kay19:09:04

ah yes…that’s right…rolling your own

tony.kay19:09:18

I would not recommend using the other two options for production in general.

pvillegas1219:09:16

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

tony.kay19:09:25

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.

tony.kay19:09:00

And…rolling your own is very simple, can be used with standard Ring patterns very easily.

tony.kay19:09:27

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.

pvillegas1219:09:50

What modular stuff?

tony.kay19:09:17

Ha! I removed it from the docs, evidently…good on me 🙂

tony.kay19:09:29

It’s still in code so I don’t break anyone…

tony.kay19:09:51

but I hope (and think) no one used it

pvillegas1219:09:33

I’m still trying to understand the defmutation macro in the server file 😄

tony.kay19:09:09

It’s just a defmethod

tony.kay19:09:27

there is a central parser: server-parser…it has a read and write entry point function

pvillegas1219:09:32

Right, but it relies on injecting a database through the env?

tony.kay19:09:33

the write function is a multimethod

tony.kay19:09:41

OH…you can do that if you want

tony.kay19:09:54

depends on how you’re managing things

tony.kay19:09:14

switch to main thread and ask a question, I think 🙂

claudiu12:09:42

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.

pvillegas1219:09:54

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

tony.kay19:09:41

@pvillegas12 you can use lookup refs with pull

tony.kay19:09:50

which are “Fulcro idents”

pvillegas1219:09:14

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?

tony.kay19:09:05

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

tony.kay19:09:44

The built-in instance called server-parser predefines the read/write handlers, which the defmutation and defquery just create multimethod entries for

tony.kay19:09:25

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

tony.kay19:09:38

the env in your snippet above is {:config config}

tony.kay19:09:54

so, if you have things to “inject” into the env, add them to that map

pvillegas1219:09:32

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?

tony.kay19:09:33

or, if you use mount you could jst refer to the defstate items directly…up to you

tony.kay19:09:29

I’d inject a conncetion

tony.kay19:09:54

mutations often need that instead

tony.kay19:09:00

I personally refer to the defstate items in the wrap-api, so they appear in env, so everything is less coupled

tony.kay19:09:28

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.

tony.kay19:09:13

and my “connection” startup does things like conforms schema

tony.kay19:09:25

just a sec….typing code in here sucks 😜

pvillegas1219:09:34

yeah I know 😛

tony.kay20:09:50

(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))))

tony.kay20:09:05

then I get nice things like development-mode mocked connections, migrations, etc.

tony.kay20:09:08

so, then I’d put {:connection main-connection} in the env

tony.kay20:09:52

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

tony.kay20:09:10

all assuming, of course, that you use Fulcro’s config 🙂

tony.kay20:09:13

Highly recommended…really useful for testing as well.

pvillegas1220:09:17

thanks for all of the above very useful! 👍 What do you mean by migrations? I thought they were not necessary with datomic

tony.kay20:09:35

I mean schema conforms

tony.kay20:09:51

technically you do run into situations where you want things applied in order, and also I do “snapshot” migrations (I’ve elided those here)

tony.kay20:09:07

where if a schema change is named with “snapshot”, then it forces a mocked connection

tony.kay20:09:27

that lets me play with schema without having to roll back the dev database

tony.kay20:09:40

(I use a postgres dev database instead of a RAM-based one)

tony.kay20:09:11

that lets me keep dev data around, and play with schema without having to “undo” it