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
71
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
100
純LISPから考える関数型言語のプリミティブ: Clojure, Elixir, Haskell, Scala
lagenorhynque
1
110
From Scala/Clojure to Kotlin
lagenorhynque
0
49
TDD with RDD: Changed Developer Experience through Clojure/Lisp REPLs
lagenorhynque
0
80
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
83
map関数の内部実装から探るJVM言語のコレクション: Scala, Kotlin, Clojureコレクションの基本的な設計を理解しよう
lagenorhynque
0
76
Kotlin Meets Data-Oriented Programming
lagenorhynque
0
70
Introduction to Tree Representations in RDB 2024
lagenorhynque
0
100
Other Decks in Programming
See All in Programming
育てるアーキテクチャ:戦い抜くPythonマイクロサービスの設計と進化戦略
fujidomoe
1
160
高度なUI/UXこそHotwireで作ろう Kaigi on Rails 2025
naofumi
4
3.7k
複雑化したリポジトリをなんとかした話 pipenvからuvによるモノレポ構成への移行
satoshi256kbyte
1
920
Django Ninja による API 開発効率化とリプレースの実践
kashewnuts
0
1.1k
AI Coding Meetup #3 - 導入セッション / ai-coding-meetup-3
izumin5210
0
640
Model Pollution
hschwentner
1
190
Web Components で実現する Hotwire とフロントエンドフレームワークの橋渡し / Bridging with Web Components
da1chi
3
2k
そのpreloadは必要?見過ごされたpreloadが技術的負債として爆発した日
mugitti9
2
3.1k
overlayPreferenceValue で実現する ピュア SwiftUI な AdMob ネイティブ広告
uhucream
0
170
CSC509 Lecture 05
javiergs
PRO
0
300
Cloudflare AgentsとAI SDKでAIエージェントを作ってみた
briete
0
130
Advance Your Career with Open Source
ivargrimstad
0
400
Featured
See All Featured
Learning to Love Humans: Emotional Interface Design
aarron
274
40k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
507
140k
Optimising Largest Contentful Paint
csswizardry
37
3.4k
It's Worth the Effort
3n
187
28k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
120k
YesSQL, Process and Tooling at Scale
rocio
173
14k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
36
2.5k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
9.7k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
5.6k
Java REST API Framework Comparison - PWX 2021
mraible
33
8.8k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
132
19k
GraphQLの誤解/rethinking-graphql
sonatard
73
11k
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