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
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Kent OHASHI
January 31, 2019
Programming
78
0
Share
GraphQL API in Clojure
Introduction to GraphQL API development in Clojure
Kent OHASHI
January 31, 2019
More Decks by Kent OHASHI
See All by Kent OHASHI
"Simple Made Easy" Made Easier: Clojureに学ぶsimplicity
lagenorhynque
0
9
Property-Based Testing with test.check and clojure.spec
lagenorhynque
0
44
🐬の推し本紹介2025: 『コーディングを支える技術 ――成り立ちから学ぶプログラミング作法』
lagenorhynque
0
100
KotlinでミニマルなResult実装による関数型エラーハンドリング
lagenorhynque
0
57
Functional Calisthenics in Kotlin: Kotlinで「関数型エクササイズ」を実践しよう
lagenorhynque
1
400
関数型言語テイスティング: Haskell, Scala, Clojure, Elixirを比べて味わう関数型プログラミングの旨さ
lagenorhynque
1
220
純LISPから考える関数型言語のプリミティブ: Clojure, Elixir, Haskell, Scala
lagenorhynque
1
250
From Scala/Clojure to Kotlin
lagenorhynque
0
110
TDD with RDD: Clojure/LispのREPLで変わる開発体験
lagenorhynque
0
130
Other Decks in Programming
See All in Programming
These Five Tricks Can Make Your Apps Greener, Cheaper, & Nicer
hollycummins
0
200
ECR拡張スキャンでSBOMを収集して サプライチェーン攻撃の影響調査を 爆速で終わらせてみた
akihisaikeda
2
200
Old Dog, New Tricks: The Java 25 Reinvention - JNation
bazlur_rahman
0
130
サーバーレスで作る、動画データ管理基盤
oyasumipants
0
270
権限チェックの一貫性を型で守る TypeScript による多層防御
mnch
4
630
Transactional Change Stream Processing With Debezium and Apache Flink
gunnarmorling
1
130
New "Type" system on PicoRuby
pocke
1
180
CLIであることを活かしたGitHub Copilot CLI活用術 / GitHub Copilot CLI Pro Tips & Tricks
nao_mk2
1
1.1k
AI駆動開発勉強会 広島支部 第一回勉強会 AI駆動開発概要とワークショップ
hayatoshimiu
0
380
気づいたらRubyで100作品 ー クリエイティブコーディングが生活の一部になるまで / 100 Ruby Sketches Later: How Creative Coding Became Part of My Life
chobishiba
2
330
AI時代だからこそ「Bloc」を採用する価値があるのかもしれない
takuroabe
0
240
TypeScriptだけでAIエージェントを作る フロント・エージェント・インフラのフルスタック実践
har1101
6
1k
Featured
See All Featured
So, you think you're a good person
axbom
PRO
2
2k
Writing Fast Ruby
sferik
630
63k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4.3k
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
710
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9k
Bash Introduction
62gerente
615
210k
Google's AI Overviews - The New Search
badams
0
1k
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
540
Utilizing Notion as your number one productivity tool
mfonobong
4
310
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
5.9k
The World Runs on Bad Software
bkeepers
PRO
72
12k
B2B Lead Gen: Tactics, Traps & Triumph
marketingsoph
0
120
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