Slide 1

Slide 1 text

GraphQL API in Clojure GraphQL API in Clojure

Slide 2

Slide 2 text

lagénorhynque lagénorhynque (defprofile lagénorhynque :aliases [ ] :languages [Clojure Common-Lisp Scheme Haskell English français] :interests [programming Love-Live! language-learning/linguistics law mathematics] :committing [github.com/lagenorhynque/duct.module.pedestal] :contributing [github.com/japan-clojurians/clojure-site-ja])

Slide 3

Slide 3 text

1. GraphQL GraphQL query GraphQL schema 2. API implementation project structure API server GraphQL implementation

Slide 4

Slide 4 text

Clojure Lacinia GraphQL API

Slide 5

Slide 5 text

example example : AqoursQL, an example GraphQL API based on Lacinia-Pedestal & Duct lagenorhynque/aqoursql

Slide 6

Slide 6 text

GraphQL GraphQL venia & edn

Slide 7

Slide 7 text

GraphQL query GraphQL query venia

Slide 8

Slide 8 text

query: query: member_by_id member_by_id { member_by_id(id: 1) { id name organization_id organization_name } }

Slide 9

Slide 9 text

response (JSON) response (JSON) { "data": { "member_by_id": { "id": 1, "name": " ", "organization_id": 1, "organization_name": " " } } }

Slide 10

Slide 10 text

GraphiQL GraphiQL

Slide 11

Slide 11 text

Clojure REPL Clojure REPL dev> (q #:venia{:queries [[:member_by_id {:id 1} [:id :name :organization_id :organization_name]]]}) {:data {:member_by_id {:id 1, :name " ", :organization_id 1, :organization_name " "}}}

Slide 12

Slide 12 text

utility function utility function q q (defn q ([query] (q query nil)) ([query variables] (lacinia/execute (:aqoursql.graphql/schema system) (venia/graphql-query query) variables {:db (:duct.database.sql/hikaricp system)}))) venia.core/graphql­query com.walmartlabs.lacinia/execute

Slide 13

Slide 13 text

query: query: songs songs { songs { name artist { name members { name } } } }

Slide 14

Slide 14 text

response (JSON) response (JSON) { "data": { "songs": [ { "name": " ", "artist": { "name": "Aqours", "members": [ { "name": " " }, ... ] } }, ... ] }

Slide 15

Slide 15 text

GraphiQL GraphiQL

Slide 16

Slide 16 text

Clojure REPL Clojure REPL dev> (q #:venia{:queries [[:songs [:name [:artist [:name [:members [:name]]]]]]]}) {:data {:songs ({:name " ", :artist {:name "Aqours", :members ({:name " "} ...

Slide 17

Slide 17 text

GraphQL schema GraphQL schema edn

Slide 18

Slide 18 text

object de nition: object de nition: Member Member """ """ type Member { """ ID""" id: Int! """ """ name: String! """ ID""" organization_id: Int! """ """ organization_name: String! }

Slide 19

Slide 19 text

resources/aqoursql/graphql-schema.edn {:objects {:Member {:description " " :fields {:id {:type (non-null Int) :description " ID"} :name {:type (non-null String) :description " "} :organization_id {:type (non-null Int) :description " ID"} :organization_name {:type (non-null String) :description " "}}}}}

Slide 20

Slide 20 text

object de nition: object de nition: Song Song """ """ type Song { """ ID""" id: Int! """ """ name: String! """" ID"" artist_id: Int! """ """ artist: Artist! """ (YYYY-MM-DD)""" release_date: String! }

Slide 21

Slide 21 text

resources/aqoursql/graphql-schema.edn {:objects {:Song {:description " " :fields {:id {:type (non-null Int) :description " ID"} :name {:type (non-null String) :description " "} :artist_id {:type (non-null Int) :description " ID"} :artist {:type (non-null :Artist) :description " "} :release_date {:type (non-null String) :description " (YYYY-MM-DD)"}}}}}

Slide 22

Slide 22 text

query de nition: query de nition: member_by_id member_by_id type Query { """ID """ member_by_id( " ID" id: Int! ): Member }

Slide 23

Slide 23 text

resources/aqoursql/graphql-schema.edn {:queries {:member_by_id {:type :Member :description "ID " :args {:id {:type (non-null Int) :description " ID"}} :resolve :query/member-by-id}}}

Slide 24

Slide 24 text

query de nition: query de nition: songs songs type Query { """ """ songs( " ( )" name: String ): [Song] }

Slide 25

Slide 25 text

{:queries {:songs {:type (list :Song) :description " " :args {:name {:type String :description " ( )"}} :resolve :query/songs}}}

Slide 26

Slide 26 text

API implementation API implementation Duct + Pedestal + Lacinia

Slide 27

Slide 27 text

project structure project structure Duct

Slide 28

Slide 28 text

Clojure Duct

Slide 29

Slide 29 text

resources/aqoursql/con g.edn {:duct.profile/base {:duct.core/project-ns aqoursql :duct.server/pedestal { ... } :aqoursql.graphql/schema {} :aqoursql.graphql/service { ... }} :duct.profile/dev #duct/include "dev" :duct.profile/test #duct/include "test" :duct.profile/local #duct/include "local" :duct.profile/prod {} :duct.module/logging {} :duct.module/sql { ... } :duct.module/pedestal {}}

Slide 30

Slide 30 text

API server API server Pedestal duct.module.pedestal

Slide 31

Slide 31 text

Clojure Pedestal

Slide 32

Slide 32 text

resources/aqoursql/con g.edn {:duct.profile/base {:duct.core/project-ns aqoursql :duct.server/pedestal {:base-service #ig/ref :aqoursql.graphql/service :service #:io.pedestal.http{:join? true :host #duct/env "SERVER_HOST" :port #duct/env ["SERVER_PORT" Int :or 8888]}} ... } ... :duct.module/pedestal {}}

Slide 33

Slide 33 text

GraphQL implementation GraphQL implementation Lacinia Lacinia-Pedestal

Slide 34

Slide 34 text

resources/aqoursql/con g.edn {:duct.profile/base {:duct.core/project-ns aqoursql ... :aqoursql.graphql/schema {} :aqoursql.graphql/service {:schema #ig/ref :aqoursql.graphql/schema :options {:graphiql true :app-context {:db #ig/ref :duct.database/sql} :env :prod}}} ... }

Slide 35

Slide 35 text

src/aqoursql/graphql.clj (defmethod ig/init-key ::schema [_ _] (-> (io/resource "aqoursql/graphql-schema.edn") slurp edn/read-string (util/attach-resolvers resolver-map) schema/compile)) (defmethod ig/init-key ::service [_ {:keys [schema options]}] (lacinia/service-map schema options))

Slide 36

Slide 36 text

resolver (function) resolver (function) src/aqoursql/graphql.clj (def resolver-map {:query/artist-by-id artists/fetch-artist-by-id :query/artists artists/list-artists :query/member-by-id members/fetch-member-by-id :query/members members/list-members :query/song-by-id songs/fetch-song-by-id :query/songs songs/list-songs})

Slide 37

Slide 37 text

resolver function spec src/aqoursql/resolver/members.clj (defn fetch-member-by-id [{:keys [db]} {:keys [id]} _] (db.member/find-member-by-id db id)) (s/fdef resolver :args (s/cat :app-context map? :arguments (s/nilable map?) :resovled-value (s/nilable map?)))

Slide 38

Slide 38 text

boundary (DB) boundary (DB) src/aqoursql/boundary/db/member.clj (s/def ::id nat-int?) (s/def ::name string?) (s/def ::organization_id ::organization/id) (s/def ::organization_name ::organization/name) (s/def ::artist_id ::artist/id) (s/def ::artist_ids (s/coll-of ::artist/id)) (s/def ::member (s/keys :req-un [::id ::name ::organization_id] :opt-un [::organization_name ::artist_id]))

Slide 39

Slide 39 text

(s/fdef find-member-by-id :args (s/cat :db ::db/db :id ::id) :ret (s/nilable ::member)) ... (defprotocol Member (find-member-by-id [db id]) ... )

Slide 40

Slide 40 text

dev> (aqoursql.boundary.db.member/find-member-by-id (:duct.database.sql/hikaricp system) 1) {:id 1, :name " ", :organization_id 1, :organization_name " "} dev> (aqoursql.resolver.members/fetch-member-by-id {:db (:duct.database.sql/hikaricp system)} {:id 1} nil) {:id 1, :name " ", :organization_id 1, :organization_name " "} dev> (q #:venia{:queries [[:member_by_id {:id 1} [:name :organization_name]]]}) {:data {:member_by_id {:name " ", :organization_name " "}}}

Slide 41

Slide 41 text

Further Reading Further Reading Lacinia Lacinia : Expose Lacinia GraphQL as Pedestal endpoints example: Lacinia Lacinia-Pedestal Clojure Lacinia GraphQL API lagenorhynque/aqoursql Clojure GraphQL Lacinia Tips

Slide 42

Slide 42 text

Duct Duct : Duct module for Pedestal Duct duct.module.pedestal Clojure Duct

Slide 43

Slide 43 text

Pedestal Pedestal Pedestal Clojure Pedestal

Slide 44

Slide 44 text

GraphQL GraphQL : Clojure(Script) graphql query generation venia GraphQL | A query language for your API How to GraphQL - The Fullstack Tutorial for GraphQL GraphQL ─ REST API Learning GraphQL