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
67
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
76
純LISPから考える関数型言語のプリミティブ: Clojure, Elixir, Haskell, Scala
lagenorhynque
1
66
From Scala/Clojure to Kotlin
lagenorhynque
0
29
TDD with RDD: Changed Developer Experience through Clojure/Lisp REPLs
lagenorhynque
0
55
My Favourite Book in 2024: Get Rid of Your Japanese Accent
lagenorhynque
1
88
do Notation Equivalents in JVM languages: Scala, Kotlin, Clojure
lagenorhynque
0
63
map関数の内部実装から探るJVM言語のコレクション: Scala, Kotlin, Clojureコレクションの基本的な設計を理解しよう
lagenorhynque
0
58
Kotlin Meets Data-Oriented Programming
lagenorhynque
0
55
Introduction to Tree Representations in RDB 2024
lagenorhynque
0
85
Other Decks in Programming
See All in Programming
なぜ「共通化」を考え、失敗を繰り返すのか
rinchoku
1
380
セキュリティマネジャー廃止とクラウドネイティブ型サンドボックス活用
kazumura
1
190
C++20 射影変換
faithandbrave
0
500
明示と暗黙 ー PHPとGoの インターフェイスの違いを知る
shimabox
1
140
CursorはMCPを使った方が良いぞ
taigakono
0
140
Enterprise Web App. Development (2): Version Control Tool Training Ver. 5.1
knakagawa
1
120
XSLTで作るBrainfuck処理系
makki_d
0
210
コード書くの好きな人向けAIコーディング活用tips #orestudy
77web
3
330
カクヨムAndroidアプリのリブート
numeroanddev
0
430
GoのWebAssembly活用パターン紹介
syumai
3
10k
Select API from Kotlin Coroutine
jmatsu
1
180
ドメインモデリングにおける抽象の役割、tagless-finalによるDSL構築、そして型安全な最適化
knih
11
2k
Featured
See All Featured
Six Lessons from altMBA
skipperchong
28
3.8k
Java REST API Framework Comparison - PWX 2021
mraible
31
8.6k
Being A Developer After 40
akosma
90
590k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
120k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
137
34k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
16
940
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
8
790
BBQ
matthewcrist
89
9.7k
Git: the NoSQL Database
bkeepers
PRO
430
65k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
281
13k
How GitHub (no longer) Works
holman
314
140k
Keith and Marios Guide to Fast Websites
keithpitt
411
22k
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