Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
GraphQL API in Clojure
Search
Kent OHASHI
January 31, 2019
Programming
0
69
GraphQL API in Clojure
Introduction to GraphQL API development in Clojure
Kent OHASHI
January 31, 2019
Tweet
Share
More Decks by Kent OHASHI
See All by Kent OHASHI
関数型言語テイスティング: Haskell, Scala, Clojure, Elixirを比べて味わう関数型プログラミングの旨さ
lagenorhynque
1
92
純LISPから考える関数型言語のプリミティブ: Clojure, Elixir, Haskell, Scala
lagenorhynque
1
93
From Scala/Clojure to Kotlin
lagenorhynque
0
43
TDD with RDD: Changed Developer Experience through Clojure/Lisp REPLs
lagenorhynque
0
75
My Favourite Book in 2024: Get Rid of Your Japanese Accent
lagenorhynque
1
110
do Notation Equivalents in JVM languages: Scala, Kotlin, Clojure
lagenorhynque
0
78
map関数の内部実装から探るJVM言語のコレクション: Scala, Kotlin, Clojureコレクションの基本的な設計を理解しよう
lagenorhynque
0
72
Kotlin Meets Data-Oriented Programming
lagenorhynque
0
66
Introduction to Tree Representations in RDB 2024
lagenorhynque
0
97
Other Decks in Programming
See All in Programming
Microsoft Orleans, Daprのアクターモデルを使い効率的に開発、デプロイを行うためのSekibanの試行錯誤 / Sekiban: Exploring Efficient Development and Deployment with Microsoft Orleans and Dapr Actor Models
tomohisa
0
240
複雑なドメインに挑む.pdf
yukisakai1225
5
1k
私の後悔をAWS DMSで解決した話
hiramax
4
200
AIを活用し、今後に備えるための技術知識 / Basic Knowledge to Utilize AI
kishida
20
5.1k
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
380
プロポーザル駆動学習 / Proposal-Driven Learning
mackey0225
2
960
基礎から学ぶ大画面対応(Learning Large-Screen Support from the Ground Up)
tomoya0x00
0
280
MLH State of the League: 2026 Season
theycallmeswift
0
230
Protocol Buffersの型を超えて拡張性を得る / Beyond Protocol Buffers Types Achieving Extensibility
linyows
0
110
Claude Codeで挑むOSSコントリビュート
eycjur
0
200
開発チーム・開発組織の設計改善スキルの向上
masuda220
PRO
18
10k
[FEConf 2025] 모노레포 절망편, 14개 레포로 부활하기까지 걸린 1년
mmmaxkim
0
1.5k
Featured
See All Featured
KATA
mclloyd
32
14k
The Cult of Friendly URLs
andyhume
79
6.6k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
30
9.6k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
229
22k
Navigating Team Friction
lara
189
15k
Site-Speed That Sticks
csswizardry
10
810
GitHub's CSS Performance
jonrohan
1032
460k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.1k
The Invisible Side of Design
smashingmag
301
51k
For a Future-Friendly Web
brad_frost
180
9.9k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
656
61k
Transcript
GraphQL API in Clojure GraphQL API in Clojure
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])
1. GraphQL GraphQL query GraphQL schema 2. API implementation project
structure API server GraphQL implementation
Clojure Lacinia GraphQL API
example example : AqoursQL, an example GraphQL API based on
Lacinia-Pedestal & Duct lagenorhynque/aqoursql
GraphQL GraphQL venia & edn
GraphQL query GraphQL query venia
query: query: member_by_id member_by_id { member_by_id(id: 1) { id name
organization_id organization_name } }
response (JSON) response (JSON) { "data": { "member_by_id": { "id":
1, "name": " ", "organization_id": 1, "organization_name": " " } } }
GraphiQL GraphiQL
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 " "}}}
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/graphqlquery com.walmartlabs.lacinia/execute
query: query: songs songs { songs { name artist {
name members { name } } } }
response (JSON) response (JSON) { "data": { "songs": [ {
"name": " ", "artist": { "name": "Aqours", "members": [ { "name": " " }, ... ] } }, ... ] }
GraphiQL GraphiQL
Clojure REPL Clojure REPL dev> (q #:venia{:queries [[:songs [:name [:artist
[:name [:members [:name]]]]]]]}) {:data {:songs ({:name " ", :artist {:name "Aqours", :members ({:name " "} ...
GraphQL schema GraphQL schema edn
object de nition: object de nition: Member Member """ """
type Member { """ ID""" id: Int! """ """ name: String! """ ID""" organization_id: Int! """ """ organization_name: String! }
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 " "}}}}}
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! }
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)"}}}}}
query de nition: query de nition: member_by_id member_by_id type Query
{ """ID """ member_by_id( " ID" id: Int! ): Member }
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}}}
query de nition: query de nition: songs songs type Query
{ """ """ songs( " ( )" name: String ): [Song] }
{:queries {:songs {:type (list :Song) :description " " :args {:name
{:type String :description " ( )"}} :resolve :query/songs}}}
API implementation API implementation Duct + Pedestal + Lacinia
project structure project structure Duct
Clojure Duct
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 {}}
API server API server Pedestal duct.module.pedestal
Clojure Pedestal
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 {}}
GraphQL implementation GraphQL implementation Lacinia Lacinia-Pedestal
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}}} ... }
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))
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})
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?)))
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]))
(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]) ... )
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 " "}}}
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
Duct Duct : Duct module for Pedestal Duct duct.module.pedestal Clojure
Duct
Pedestal Pedestal Pedestal Clojure Pedestal
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