Lacinia Pedestal¶
Working from the REPL is important, but ultimately GraphQL exists to provide a web-based API. Fortunately, it is very easy to get your Lacinia application up on the web, on top of the Pedestal web tier, using the lacinia-pedestal library.
In addition, for free, we get GraphQL’s own REPL: GraphiQL.
Add Dependencies¶
{:paths ["src" "resources"]
:deps {org.clojure/clojure {:mvn/version "1.11.1"}
com.walmartlabs/lacinia {:mvn/version "1.2-alpha-4"}
com.walmartlabs/lacinia-pedestal {:mvn/version "1.1"}
io.aviso/logging {:mvn/version "1.0"}}
:aliases
{:run-m {:main-opts ["-m" "my.clojure-game-geek"]}
:run-x {:ns-default my.clojure-game-geek
:exec-fn greet
:exec-args {:name "Clojure"}}
:build {:deps {io.github.seancorfield/build-clj
{:git/tag "v0.8.2" :git/sha "0ffdb4c"
;; since we're building an app uberjar, we do not
;; need deps-deploy for clojars.org deployment:
:deps/root "slim"}}
:ns-default build}
:dev {:extra-paths ["dev-resources"]}
:test {:extra-paths ["test"]
:extra-deps {org.clojure/test.check {:mvn/version "1.1.1"}
io.github.cognitect-labs/test-runner
{:git/tag "v0.5.0" :git/sha "48c3c67"}}}}}
We’ve added two libraries: lacinia-pedestal
and io.aviso/logging
.
The former brings in quite a few dependencies, including Pedestal, and the underlying Jetty layer that Pedestal builds upon.
The io.aviso/logging
library sets up
Logback as the logging library.
Clojure and Java are both rich with web and logging frameworks; Pedestal and Logback are simply particular choices that we’ve made and prefer; many other people are using Lacinia on the web without using Logback or Pedestal.
Some Configuration¶
For best results, we can configure Logback; this keeps startup and request handling from being very chatty:
<configuration scan="true" scanPeriod="1 seconds">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<root level="warn">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
This configuration hides log events below the warning level (that is, debug and info events). If any warnings or errors do occur, minimal output is sent to the console.
A logback-test.xml
takes precendence over the production logback.xml
configuration
we will eventually supply.
User Namespace¶
We’ll add more scaffolding to the user
namespace, to make it possible to start and stop
the Pedestal server.
(ns user
(:require [my.clojure-game-geek.schema :as s]
[com.walmartlabs.lacinia :as lacinia]
[com.walmartlabs.lacinia.pedestal2 :as lp]
[io.pedestal.http :as http]
[clojure.java.browse :refer [browse-url]]
[clojure.walk :as walk])
(:import (clojure.lang IPersistentMap)))
(def schema (s/load-schema))
(defn simplify
"Converts all ordered maps nested within the map into standard hash maps, and
sequences into vectors, which makes for easier constants in the tests, and eliminates ordering problems."
[m]
(walk/postwalk
(fn [node]
(cond
(instance? IPersistentMap node)
(into {} node)
(seq? node)
(vec node)
:else
node))
m))
(defn q
[query-string]
(-> (lacinia/execute schema query-string nil nil)
simplify))
(defonce server nil)
(defn start-server
[_]
(let [server (-> (lp/default-service schema nil)
http/create-server
http/start)]
(browse-url "http://localhost:8888/ide")
server))
(defn stop-server
[server]
(http/stop server)
nil)
(defn start
[]
(alter-var-root #'server start-server)
:started)
(defn stop
[]
(alter-var-root #'server stop-server)
:stopped)
This new code is almost entirely boilerplate for Pedestal and for Lacinia-Pedestal.
The core function is com.walmartlabs.lacinia.pedestal2/default-service
[1] which is passed the compiled schema
and a map of options, and returns a Pedestal service map which is then used
to create the Pedestal server.
By default, incoming GraphQL POST requests are handled at the /api
path.
The default port is 8888. We’ll get to the details later.
The /ide
path (which is opened at startup), and related JavaScript and CSS resources, can only be accessed
when GraphiQL is enabled.
Starting The Server¶
With the above scaffolding in place, it is just a matter of starting the REPL and evaluating (start)
.
At this point, your web browser should open to the GraphiQL application:
Tip
It’s really worth following along with this section, especially if you haven’t played with GraphiQL before. GraphiQL assists you with formatting, provides pop-up help, flags errors in your query, and supplies automatic input completion. It can even pretty print your query. It makes for quite the demo!
Running Queries¶
We can now type a query into the large text area on the left and then click
the right arrow button (or type Command+Enter
), and see the server response as pretty-printed JSON on the right:
Notice that the URL bar in the browser has updated: it contains the full query string.
This means that you can bookmark a query you like for later (though it’s easier to access prior
queries using the the History
button).
Importantly, you can copy that URL and provide it to other developers. They can start up the application on their workstations and see exactly what you see, a real boon for describing and diagnosing problems.
This approach works even better when you keep a GraphQL server running on a shared staging server. On split [2] teams, the developers creating the application can easily explore the interface exposed by the GraphQL server, even before writing their first line of client-side code.
Trust me, they love that.
You’ll notice that the returned map is in JSON format, not EDN, and that it includes a lot more information in the extensions
key. This is optional tracing information, where Lacinia identifies how it spent time processing the request. This is an example of something that’s automatic when using default-service
that you’ll definitely want to turn off in production.
Documentation Browser¶
The < Docs
button on the right opens the documentation browser:
The documentation browser is invaluable: it allows you to navigate around your schema, drilling down
to objects, fields, and types to see a summary of each
declaration, as well as documentation - those
:description
values we added way back
at the beginning.
Take some time to learn what GraphiQL can do for you.
Summary¶
It takes very little effort, just a dependency change and a little boilerplate code, to expose our little application to the web, and along the way, we gain access to the powerful GraphiQL IDE.
Next up, we’ll look into reorganization our code for later growth by adding a layer of components atop our code.
[1] | Why pedestal2 ? The initial version of lacinia-pedestal had a slightly different
approach to setting up Pedestal that proved to be problematic, it also supported some outdated
ideas about how to process incoming requests.
For compatibility, the
original namespace, com.walmartlabs.lacinia.pedestal was left functionally s-is, but a new namespace,
pedestal2 was created to address the concerns. |
[2] | That is, where one team or set of developers just does the user interface, and the other team just does the server side (including Lacinia). Part of the value proposition for GraphQL is how clean and uniform this split can be. |