Anyone using om-next
+ graphql
backend?
I've played with it: https://github.com/danielstockton/omql
Maybe also check out https://github.com/wilkerlucio/pathom
Pathom looks really interesting, thanks.
And how about normalization? There is no problems around it?
I'm prototyping with reagent + lacinia
, and normalization is my main problem
Pathom looks interesting to me, because perhaps it could allow querying with om-next but also exposing the same backend API/parser to graphql queries
I have no desire to use graphql really, but i am interested in offering it to other API users who might prefer it
I'm looking for a write-once backend solution, that can expose both om and graphql APIs
Any good reason to support om and graphql api?
There is something possible on om
that isn't possible on graphql
?
I played with omql because i also have a case where the backend isn't written in Clojure. I tend to have to fix normalization issues myself in merge anyway.
I'm no expert in graphql tbh. Doesn't it force you to separate reads and mutations, whereas om can express them in a single query?
I also just prefer om syntax, but thats subjective
Actually no, one benefit is that it's data (instead of strings like graphql). Dealing with strings is much more painful.
Also, transit?
From clojurescript, it's clearly preferable to use cljs data structures
@danielstockton pathom integrations with graphql are mostly in the direction of consumption (consuming graphql from clojure, and integrate on the om style), there are docs in progress about using graphql endpoints strait from the client (the examples will be using custom fulcro networks, but shouldn't be hard to port into a send
function in om.next). that said, consuming gql is much easier than exposing it. the tricky is that the om model is flexible and schema free, so we have no restrictions about combinations of attributes, that's not true for graphql, trying to expose a graphql from a pathom implementation means having to figure out how to define the entities and interfaces, I see no easy way to do it automatically, a feasible way could be manually defining some external gql schema that uses the underling implementation, I would be interested in help with advice if you wanna take the adventure
@souenzzo I think the parser model we do in om is more flexible than the gql, exactly because we are not forced to have rigid schemas, it's a different way of thinking, it's like Prismatic Schema vs Spec. in Schema you are encouraged to think on entities first, every attribute lives on an entity, the entities are the primary building block. on spec the primary building blocks are the attributes, you start with then and later combine as you find suitable. IMO the later evolves easier, allowing you to do as many combinations as you wish, it's a different way o thinking really
@wilkerlucio there is something like Voyager to om?
I don't know Voyager, what is it?
@souenzzo just found it, not yet (that I know), but it's part of OgE (https://github.com/wilkerlucio/oge) roadmap to have something like that 🙂
I'm trying, one more time, to use om-next But I always stuck at this point ("recursive" parser): https://gist.github.com/souenzzo/6db3917911884d44e7da768958c7f242
@souenzzo had you tried fulcro?
@wilkerlucio yep, I see (almost) all the videos, but I really want to understand om-next before start to use fulco stuff
well, learning how to write parsers is not really necessary to use a lot of fulcro/om.next, but it can surely hold you up if you trying to learn the deal 🙂
let me take a look on your example
@souenzzo interesting, the third argument for the parser
, the target
, I didn't knew it existed, it's the first time I see it
and there is a chance that nobody was using it, really, might had never worked, but I'm just guessing
I did a few changes to your example, sending the target
manually (I used a namespaced version, seems like the plain :target
is special somehow), and it works:
(ns com.wsscode.pathom.tmp
(:require [om.next :as om]
[clojure.test :refer :all]))
(defmulti om-read om/dispatch)
(defmethod om-read :default
[_ k _]
(throw (ex-info (str "read: " k) {:k k})))
(defmethod om-read :db/id
[{::keys [target]} k _]
{:value (get target k)})
(defmethod om-read :user/name
[{::keys [target]} k _]
{:value (get target k)})
(defmethod om-read :user/id
[{::keys [target]} k _]
{:value (get target k)})
(defmethod om-read :me
[{:keys [state query parser] :as env} k v]
;; Why parser returns '[]'
{:value (parser (assoc env ::target (get @state k)) query)})
(def parser
(om/parser
{:read om-read}))
(deftest recursive-read
(let [state (atom {:me {:db/id 1 :user/name "abc" :user/id "1"}})
env {:state state}]
(is
(= (parser env [{:me [:db/id :user/name]}])
{:me {:db/id 1 :user/name "abc"}}))))
instead of sending as the third argument, I assoc on the env during the recursive call
that's how pathom does it, but it's called ::p/entity
there (by default, it's configurable)
So, this is the "standard" method to do a recursive parser?
I can't say it's standard, but that's how I've been doing it since I started, not sure if other people were aware of the :target
thing
in the past I used to give specific names for the entity (like :user
, :item
, etc...), but after a while I realised giving a standard name (`::p/entity`) makes generalisations easier
if you like to read more about it, I wrote an article about those parsing details: https://medium.com/@wilkerlucio/implementing-custom-om-next-parsers-f20ca6db1664
but I can't express in text how much I recommend you try fulcro, it's not just about the local parser, it takes so much overhead out of your face when compared to stock om, and you still need all those parsing skills to write the backend, the front-end works pretty well with just db->tree