GraphQL API in Clojure

245 Views

January 31, 19

スライド概要

Introduction to GraphQL API development in Clojure

profile-image

「楽しく楽にcoolにsmartに」を理想とするprogrammer/philosopher/liberalist/realist。 好きな言語はClojure, Haskell, Python, English, français, русский。 読書、プログラミング、語学、法学、数学が大好き! イルカと海も大好き🐬

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

GraphQL API in Clojure

2.

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

3.

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

5.

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

6.

GraphQL venia & edn

8.

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

9.

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

10.

GraphiQL

11.

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 " "}}}

12.

utility function 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

13.

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

14.

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

15.

GraphiQL

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

18.

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

19.

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 " "}}}}}

20.

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

21.

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)"}}}}}

22.

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

23.

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}}}

24.

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

25.

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

26.

API implementation Duct + Pedestal + Lacinia

29.

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 {}}

32.

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 {}}

34.

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}}} ... }

35.
[beta]
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))

36.

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})

37.

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

38.

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]))

39.

(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]) ... )

40.
[beta]
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 "
"}}}

44.

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