Introduction
The pathom
library provides a set of functionality for building robust parsers to
process EQL requests.
If you are not familiar with EQL, check its docs for a general intro on EDN Graph Queries
.
In case you are not sure what this library is for, check the rationale to understand the motivations for it.
Pathom 3
Hello, if you are new here, I suggest you have a look at Pathom 3!
Pathom 3 still in alpha, but it’s the library that will get updated ahead, and most of the API is already stable, Pathom 2 (current here) is only updating in case of bug fixes.
What does it look like?
Let’s start with a demo! Use the buttons to load pre-defined queries and feel free to
edit and try around (start typing inside the []
and it will auto-complete to help you explore the API!).
Source code for this demo:
(ns com.wsscode.pathom.book.intro.demo
(:require [com.wsscode.pathom.core :as p]
[com.wsscode.pathom.connect :as pc]))
(pc/defresolver answer [_ _]
{::pc/output [:answer-to-everything]}
{:answer-to-everything 42})
(pc/defresolver answer-plus-one [_ {:keys [answer-to-everything]}]
{::pc/input #{:answer-to-everything}
::pc/output [:answer-plus-one]}
{:answer-plus-one (inc answer-to-everything)})
(def registry
[answer answer-plus-one])
(def parser
(p/parser
{::p/env {::p/reader [p/map-reader
pc/reader2
pc/open-ident-reader
p/env-placeholder-reader]
::p/placeholder-prefixes #{">"}}
::p/mutate pc/mutate
::p/plugins [(pc/connect-plugin {::pc/register registry})
p/error-handler-plugin
p/trace-plugin]}))
(comment
; to call the parser and get some data out of it, run:
(parser {} [:answer-to-everything]))
I hope you had a good time playing around! The intention of this library is to make it as easy as possible to implement API’s like the one you saw you in the demo above.
How it works
The following diagram illustrates the main pieces that make a pathom
parser:
To break down in parts, let’s imagine we are processing the following request:
[:answer-to-everything :answer-plus-one]
Parser
The parser receives the whole query to process and iterates over each attribute calling the reader on each one of them.
In our example, the parser receives the full query
[:answer-to-everything :answer-plus-one]
.
Readers
A reader processes a single entry from the query, the entry can be a property, a join or an ident. It is common to have a chain of readers (as shown in the photo and demo), when it’s a chain, it tries each reader in order. A reader can respond with either a value or signal the engine that it can’t process the key, in which case, it triggers the next reader.
In our example, the reader gets called once for :answer-to-everything
and then again with
:answer-plus-one
.
Resolvers
Pathom is capable of traversing a graph of dependencies to resolve data. This feature is called Connect and each resolver is an edge of this graph traversal. You can find more information about them in connect resolvers docs.
In the Pathom
library
The library includes:
-
A composable reader abstraction.
-
The concept of entity, which works as a base framework for reusable and sharable readers.
-
A plugin system with some built-in plugins:
-
Error handler: Handles errors at an attribute level.
-
Request cache: For caching the results of possibly repetitive parsing which can happen on a single request.
-
Tracer: A plugin to measure and debug each step of the parsing process.
-
-
Connect: A higher-level abstraction that can resolve attribute relationships automatically. For example, automatic traversal of database joins or resolving data through network requests. This enables exploratory capabilities and a much simpler access model when the need arises to do extra work for resolving a single conceptual join.
-
GraphQL integration: Use GraphQL endpoints directly from your query system (in development).
Most people find the most leverage in the Connect features, which allows you to quickly build dynamic query processing systems to satisfy client data requests with ease.
Aliases Used in Code Examples
Throughout the book, our code examples use aliases instead of explicit namespaces. The aliases used, assume that you have the following namespace requires in your environment:
(ns my-namespace
(:require
[com.wsscode.pathom.core :as p]
[com.wsscode.pathom.connect :as pc]
[com.wsscode.pathom.connect.graphql2 :as pcg]
[com.wsscode.pathom.graphql :as pg]
[com.wsscode.pathom.sugar :as ps]
[com.wsscode.pathom.trace :as pt]
; clj only
[com.wsscode.common.async-clj :refer [let-chan go-catch <? <?maybe]
; cljs only
[com.wsscode.common.async-cljs :refer [let-chan <!p go-catch <? <?maybe]]))
So, any time you see the usage of a namespace in a keyword or a function like p/parser
or ::p/reader
you should remember
that these are the namespaces involved.
Contributing
In every page of this documentation, you can find an icon at the top right, click on that icon to edit the current page (it opens the Github link to edit the page source).
How to Use This Library
Most of our current user base is made up of Fulcro
users, however this library is a stand-alone thing
that you can use to fulfill any system using EQL queries. The purpose of this library is to make it
much easier to build code that can process EQL on both the client and server-side.
We expect you to have one or more of the following needs:
-
You want to fulfill a client UI query from some server-side data source(s).
-
You want to build a client-side parser for directly filling local UI data queries from a local data source.
-
You want to build a parser (client or server) that uses async APIs to fulfill different parts of a query. Perhaps gluing together data sources from various micro-services.
-
You want to use a GraphQL API from the client.
-
You want to provide third-party users a GraphQL API (Future Work)
When building most parsers, you’ll want to use Pathom Connect.
To process EQL queries against GraphQL you’ll use the GraphQL Integration.