Skip to content
This repository was archived by the owner on Aug 16, 2023. It is now read-only.

Latest commit

 

History

History
220 lines (164 loc) · 8.03 KB

File metadata and controls

220 lines (164 loc) · 8.03 KB
id ring
title Ring
sidebar_label Ring

GraphQLize built on top of Lacinia, a de-facto library for implementing GraphQL APIs in Clojure.

Getting started with GraphQLize using Ring involves only few steps. Let's dive in.

Adding Dependencies

Create a new Clojure project using deps (or leiningen) and add the GraphQLize and other dependencies.

Clojars Project

;; deps.edn
{:paths ["src" "resources"]
 :deps  {org.clojure/clojure              {:mvn/version "1.10.1"}
         org.graphqlize/graphqlize        {:mvn/version "0.1.0-alpha20"}
         ;; db connection pool
         hikari-cp                        {:mvn/version "2.10.0"}
         ;; for postgres
         org.postgresql/postgresql        {:mvn/version "42.2.8"}
         ;; for MySQL
         mysql/mysql-connector-java       {:mvn/version "8.0.19"}
         ;; Ring Router
         metosin/reitit             {:mvn/version "0.4.2"}
         ;; Web Server
         ring/ring-jetty-adapter    {:mvn/version "1.7.1"}}}

Configuring DataSource

The next step is configuring the DataSource. In this example, we are going to use Hikari Connection Pool to manage the database connection.

:::note For brevity, this sample uses def to define the states. In a real-world project, you can replace it with Component, Mount, or Integrant. :::

import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem";

<Tabs defaultValue="postgres" values={[ { label: 'Postgres', value: 'postgres' }, { label: 'MySQL', value: 'mysql' } ] }>

;; src/server.clj
(ns server
  (:require [hikari-cp.core :as hikari]))

(def db-spec (hikari/make-datasource {:adapter           "postgresql"
                                      :database-name     "sakila"
                                      :server-name       "localhost"
                                      :port-number       5432
                                      :maximum-pool-size 1
                                      :username          "postgres"
                                      :password          "postgres"}))
;; src/server.clj
(ns server
  (:require [hikari-cp.core :as hikari]))

(def db-spec (hikari/make-datasource {:server-name       "localhost"
                                      :maximum-pool-size 1
                                      :jdbc-url          "jdbc:mysql://localhost:3306/sakila"
                                      :driver-class-name "com.mysql.cj.jdbc.MysqlDataSource"
                                      :username          "root"
                                      :password          "mysql123"}))

:::note Make sure you are changing the above values to refer your database connection. The above example assumes that you are using the sakila database created from this JOOQ's example repository.
:::

Creating Lacinia Schema

Then create a lacinia schema from the data source using GraphQLize.

(ns server
  (:require ; ...
            [graphqlize.lacinia.core :as l]))

(def db-spec ...)

(def lacinia-schema (l/schema db-spec))

Adding GraphQL Endpoint

The final step is adding a Ring route /graphql to expose the GraphQL API.

(ns server
  (:require ;...
            [ring.adapter.jetty :as jetty]
            [ring.util.request :as request]
            [reitit.ring :as ring]
            [com.walmartlabs.lacinia :as lacinia]
            [clojure.data.json :as json]))
; ...

(def lacinia-schema ...)

(defn graphql-handler [request]
  (let [grapql-request (json/read-str (request/body-string request) :key-fn keyword)
        {:keys [query variables]} grapql-request
        result (lacinia/execute lacinia-schema query variables nil)]
    {:status  200
     :body    (json/write-str result)
     :headers {"Content-Type" "application/json"}}))

(def app
  (ring/ring-handler (ring/router ["/graphql" {:post handler}])))

(defn start-server []
  (jetty/run-jetty app {:join? false
                        :port  8080}))

(defn -main []
  (start-server))

The graphql-handler function does the following

  • It de-serializes the GraphQL request body from the Ring request.
  • Then using the lacinia-schema created in the previous step, it executes this GraphQL request by invoking the Lacinia's execute function.
  • Finally, it serializes the result of the execute function and send it back to the client as a Ring response.

:::note This sample uses Reitit without coercion for simplicity. An example of the above sample using Reitit's Spec coercion is available in this file. :::

Test Drive

To do a test drive of this implementation, start the server

> clj -m server

and hit the endpoint via curl.

> curl -X POST \
  --data '{"query": "query { actorByActorId(actorId: 1){firstName}}"}' \
  -H "Content-Type: application/json" \
  http://localhost:8080/graphql

You'll get a response like below.

{
  "data": {
    "actorByActorId": {
      "firstName": "PENELOPE"
    }
  }
}

GraphQL Playground and Voyager

With the GraphQL endpoint up and running, the next step is introspecting the GraphQL schema and try out some more queries.

To introspect, we are going to make use of Voyager, a tool to visualize GraphQL API as an interactive graph. To add Voyager, download this voyager.html file and put it under the resources/static directory.

Then configure Ring to use this static directory for serving static files.

(ns server
  (:require ;...
            [ring.middleware.resource :as resource]
            [ring.middleware.content-type :as content-type]
            [ring.middleware.not-modified :as not-modified]))
; ...
(defn handler ...)

(def app
  (-> (ring/ring-handler (ring/router ["/graphql" {:post handler}]))
      (resource/wrap-resource "static")
      content-type/wrap-content-type
      not-modified/wrap-not-modified))

When you restart the server, the Voyager will be available at http://localhost:8080/voyager.html. A sample output would look like this.

Then to interact with the GraphQL API, let's add the GraphQL Playground. Like Voyager, download this playground.html file and put in the static directory.

This GraphQL playground will be available at http://localhost:8080/playground.html after server restart.

Next Steps

Congrats! You are on course to build impressive applications using GraphQLize in less time. To save yourself some more time, do refer this documentation to know more about how GraphQLize generates the GraphQL schema and the queries.

The sample code is available in this GitHub Repository.

:::note You can also customize certain default behaviours of GraphQLize in future releases. :::