Fork me on GitHub
#fulcro
<
2022-08-31
>
njj15:08:51

We are working on upgrading to FC3. Is it possible to have both FC2 EQL parser and pathom?

tony.kay16:08:05

Hey there, not sure what you mean. On the back-end?

tony.kay16:08:43

EQL is EQL. Fulcro doesn’t care. If you mean you’d like to use existing helpers from F2 on the server, then I don’t see a problem (off-hand)

tony.kay16:08:02

The only danger of having F2 and F3 on the classpath at the same time is accidental usage of an old F2 ns in F3 code. I made sure there are no ns overlaps, but that doesn’t fix the “IDE Autocomplete” features that might do that.

njj16:08:50

I’m referring to the porting guide here: > Fulcro 3 no longer supplies server-side macros for mutations and reads, as pathom is a much better choice for EQL service.

njj16:08:30

I’m trying to determine if its best to try and swap all of the backend to pathom, prior to fully upgrading to fc3

tony.kay16:08:43

True, using Pathom’s supplied defresolver and defmutation are better, but there’s no reason the existing things won’t work, other than you have to figure out how to do the dispatch

tony.kay16:08:42

I’d probably just define two remotes and two URIs like /api and /api-new, then you can have the app select the remote. That would let you port over time.

njj16:08:52

That’s a great idea

njj16:08:30

What are you referring to when you say “figure out how to do the dispatch”?

tony.kay16:08:21

If I do a query [:x :y :z] that could involve 3 difference resolvers (in Pathom). In F2 you probably were just doing full query resolution per top-level keyword…so there was no need to dispatch to multiple code units to complete the query

tony.kay16:08:27

As you port to Pathom, you’ll have resolvers that do smaller units of work, and Pathom will coordinate them (dispatch based on context and EQL)

njj17:08:00

Sounds like testing it out in a smaller chunk might help me figure out the best course of action

njj17:08:08

w/ the /api-new idea

tony.kay17:08:31

but if you issue a query where :x and :y need to come from new API and :z needs to come from old api, then you have a dispatch problem. One EQL query won’t hit “both”

👍 1
tony.kay17:08:32

That said, if you’re doing what I think you’re doing for F2, then porting may not be as bad as you think. Mutations are trivial (change which macro you use, and the notation slightly). Queries, if you’re mainly doing things where you’re not processing the EQL but just blindly responding to what you know you need, will be very simple as well.

njj17:08:22

I feel like I could do it on a component by component basis and pull over the APIs needed for each query. As I get closer to the end of them, I imagine I would have ported a majority of things

njj17:08:41

Most of our routes follow an initial load pattern which have a defmethod mutate and look something like:

(df/load reconciler [:profile/by-id sso-id] ProfileForm etc...

njj17:08:48

where the backend is:

(defmethod api-read :profile/by-id etc..

njj17:08:47

In reading a bit about pathom it sounds like I could have a defresolver that does something similar to the api-read above

tony.kay17:08:16

the api-read is dispatching on single keywords. That is the ::pc/output setting on a resolver.

tony.kay17:08:07

for ident loading, you’d use a ::pc/input of #{:profile/by-id}, which would then give you the id in the input params of the resolver.

tony.kay17:08:58

Once you start using it you’ll rapidly see why I abandoned the old stuff.

njj19:08:22

@tony.kay re multiple remotes: Is there any of examples of this in the docs? I have diving into the source code a bit and found this:

`:networking` (optional). An instance of FulcroNetwork that will act as the default remote (named :remote). If
  you want to support multiple remotes, then this should be a map whose keys are the keyword names of the remotes
  and whose values are FulcroNetwork instances.

tony.kay19:08:27

just look at the constructor function for new fulcro apps doc string, and implementation (source). It creates :remote for you. Just do that again with an addl kw. On the server: the middleware lets you specify the URI.

tony.kay19:08:32

not much to it really

njj19:08:44

(defn new-client-with-defaults []
  (fc/new-fulcro-client :started-callback on-app-started
                        :network-error-callback
                        (fn [_ _ {:keys [type message]}]
                          (log/error type ":" message))
    {:networking {:pathom-remote (fulcro-http-remote {:url "/pathom/api"})}}))

njj20:08:21

and then I would just make another instance of make-fulcro-server? Where the app-name refers to this url above? (fulcro.easy-server/make-fulcro-server :app-name "pathom" *...*)

njj20:08:48

I’m mostly referring to this https://book.fulcrologic.com/fulcro2/#_modifying_the_api_route but I’m not sure its the right path since I don’t have two apps, its more like one app with two api routes

tony.kay02:09:52

I thought you were doing F3?

tony.kay02:09:26

on the client:

(app/fulcro-app …
  :remotes              {:remote   (net/fulcro-http-remote
                                        {:url                 "/api"
                                         :response-middleware response-middleware
                                         :request-middleware  secured-request-middleware})
                          :newapi (net/fulcro-http-remote
                                        {:url                 "/api-new"
                                         :response-middleware response-middleware
                                         :request-middleware  secured-request-middleware})
refer to: https://book.fulcrologic.com/#_creating_a_remote https://book.fulcrologic.com/#_remote_mutations

tony.kay02:09:47

on the server, just install the middleware the new F3 middleware with /api-new:

(wrap-api "/api-new")
and then in df/load use :remote :newapi when you want to load from the new one. In mutations use the (remote [_] true) to mutate against old API and (newapi [_] true) to mutate against the new one.

tony.kay02:09:45

where wrap-api is something like:

(defn wrap-api [handler uri]
  (fn [request]
    (if (= uri (:uri request))
      (handle-api-request
        (:transit-params request)
        (fn [tx] (parser {:ring/request request} tx)))
      (handler request))))
and `
[com.fulcrologic.fulcro.server.api-middleware :refer [handle-api-request]]
is where handle-api-request comes from

njj11:09:44

The current app is in FC2, I’m concerned that our backend apis will break once I upgrade so I’m attempting to make a path to convert them over to pathom in the current FC2 setup prior to upgrading.

njj13:09:30

Is it possible to do the API split like we are referring to in FC2?

tony.kay14:09:35

Yes of course. Like I said, both can be on the class path, and EQL hasn't changed, so the front end will have no idea what is implementing the back end.

njj14:09:48

Ok great, I’ll try to follow what your example above but in the FC2 context

genekim17:08:39

@tony.kay You posted about your connect-macros to create resolvers that don’t require restarting Pathom, which is posted here: https://gist.github.com/awkay/86a3d7b3be912f79961e7bffba91a6f2 Can you also post the source the [app.lib.pathom.registry :refer [register!]], which it requires? Many thanks! (I’d love to give this a try!)

tony.kay17:08:12

(ns app.lib.pathom.registry
  (:require
    [com.wsscode.pathom.connect :as pc]
    [taoensso.timbre :as log]))

(defonce pathom-registry (atom {}))

(defn register! [resolver]
  (log/debug "Registering resolver" (::pc/sym resolver))
  (swap! pathom-registry assoc (::pc/sym resolver) resolver))

tony.kay17:08:20

just as I said on the thread: It’s just an atom

tony.kay17:08:32

Then when you make the parser somewhere you’ve got a list of all your resolvers, just include it there:

resolvers                [form/resolvers
                                  (blob/resolvers r.model/all-attributes)
                                  (res/generate-resolvers r.model/all-attributes)
                                  (rad-datomic/generate-resolvers attributes-with-security :main)
                                  (vec (vals @pathom-registry))]

tony.kay17:08:16

The registry uses a map so that if you re-eval something it doesn’t get duplicated (unless you renamed it, which is just like def and namespaces)

genekim18:09:34

Thank you, @tony.kay! I can’t wait to try this out — maybe in the next period of downtime. I love love love the idea of not hot-reloading!