サーバサイドKotlinでGraphQLをやってみよう - Kotlin Fest 2019 - / Server side Kotlin + GraphQL

8d887e6605353ca5fb1e05f38564ef50?s=47 Shiraji
August 24, 2019

サーバサイドKotlinでGraphQLをやってみよう - Kotlin Fest 2019 - / Server side Kotlin + GraphQL

8d887e6605353ca5fb1e05f38564ef50?s=128

Shiraji

August 24, 2019
Tweet

Transcript

  1. αʔόαΠυKotlinͰ GraphQLΛ΍ͬͯΈΑ͏ ͠Β͡

  2. Who am I? • Kotlin + GraphQL 1+ year •

    Open Source kotlin-graphql-sample • Love Kotlin • Works for Ubie, Inc @shiraji @shiraj_i
  3. ςΫϊϩδʔͰਓʑΛద੾ͳҩྍʹҊ಺͢Δ

  4. Kotlin Fest Organizer & Speakers We are hiring!!! https://ubie.life/

  5. ͜͜ʹ͍Δਓͨͪ • KotlinΛ৮ͬͨ͜ͱ͕͋Δ • αʔόαΠυKotlinɺGraphQLʹڵຯ͕͋Δ • GET/POST΍ϨεϙϯείʔυͳͲͷHTTPͷجૅతͳ஌͕ࣝ͋Δ • ηογϣϯதʹ൓Ԡͯ͘͠ΕΔ

  6. ͜͜ʹ͍Δਓͨͪ • KotlinΛ৮ͬͨ͜ͱ͕͋Δ • αʔόαΠυKotlinɺGraphQLʹڵຯ͕͋Δ • GET/POST΍ϨεϙϯείʔυͳͲͷHTTPͷجૅతͳ஌͕ࣝ͋Δ • ηογϣϯதʹ൓Ԡͯ͘͠ΕΔ

  7. ࣭ͬͦ͘͞໰ αʔόαΠυKotlin΍ͬͨ͜ͱ͋Δਓʔʁ

  8. ࣭໰2 αʔόαΠυKotlin+GraphQL΍ͬͨ͜ͱ͋Δਓʔʁ

  9. ࿩͢͜ͱ • GraphQLͱ͸Կʁ • Kotlin+GraphQLͷίʔυͷྲྀΕ • Kotlin+GraphQLͷςετ • Kotlin+GraphQLͷೝূ •

    Kotlin+GraphQLͷपลπʔϧ
  10. ࿩͢͜ͱ • GraphQLͱ͸Կʁ • Kotlin+GraphQLͷίʔυͷྲྀΕ • Kotlin+GraphQLͷςετ • Kotlin+GraphQLͷೝূ •

    Kotlin+GraphQLͷपลπʔϧ
  11. ɾɾɾͷલʹɺ͜Μͳܦݧ͋Γ·ͤΜ͔ʁ Ϣʔβͷ໊લҰཡͷAPI͕ཉ͍͠

  12. ɾɾɾͷલʹɺ͜Μͳܦݧ͋Γ·ͤΜ͔ʁ { [ "name": “Nagasawa Taro” ], [ "name": “Isogai

    Yoshinori” ] }
  13. ɾɾɾͷલʹɺ͜Μͳܦݧ͋Γ·ͤΜ͔ʁ ͜ͷOSͰ͸first name͚ͩཉ͍͠

  14. ɾɾɾͷલʹɺ͜Μͳܦݧ͋Γ·ͤΜ͔ʁ { [ “first_name”: “Taro” ], [ “first_name": “Yoshinori” ]

    }
  15. ɾɾɾͷલʹɺ͜Μͳܦݧ͋Γ·ͤΜ͔ʁ ͜ͷαΠτ͸ TwitterΞΧ΢ϯτ͕ཉ͍͠

  16. ɾɾɾͷલʹɺ͜Μͳܦݧ͋Γ·ͤΜ͔ʁ { [ “twitter”: “ngsw_taro” ], [ “twitter": “shiraji” ]

    }
  17. ɾɾɾͷલʹɺ͜Μͳܦݧ͋Γ·ͤΜ͔ʁ ͜ͷAPI͸icon͚ͩͰྑ͍

  18. ɾɾɾͷલʹɺ͜Μͳܦݧ͋Γ·ͤΜ͔ʁ { [ “icon”: “https://…” ], [ “icon”: “https://…” ]

    }
  19. ɾɾɾͷલʹɺ͜Μͳܦݧ͋Γ·ͤΜ͔ʁ { [ "name": “Nagasawa Taro”, “first_name”: “Taro”, “twitter”: “ngsw_taro”,

    “icon”: “https://…” ] }
  20. GraphQLͱ͸Կʁ • A query language for your API • εΩʔϚͱΫΤϦ

    • GraphQL Fundation • OSS • e.g. GitHub API v4
  21. εΩʔϚͱΫΤϦ type User { id: ID! name: String! account: String

    }
  22. εΩʔϚͱΫΤϦ type Query { user(id: ID!) : User } type

    Mutation { createUser(name: String!) } type User { id: ID! name: String! account: String }
  23. εΩʔϚͱΫΤϦ query { user(id: "aaa") { id name account }

    }
  24. εΩʔϚͱΫΤϦ type Query { user(id: ID!) : User } type

    User { id: ID! name: String! account: String }
  25. εΩʔϚͱΫΤϦ type Query { user(id: ID! ) a : User

    } type User {a id: ID! name: String! account: String }a
  26. εΩʔϚͱΫΤϦ query { user(id: "aaa" ) a {a id name

    account }a }
  27. εΩʔϚͱΫΤϦ { "data" : {a "id": "aaa", "name": "ү֋Ղయ", "account":

    "shiraji" }a }
  28. εΩʔϚͱΫΤϦ query { user(id: "aaa") {ccc id name account }a

    }b
  29. εΩʔϚͱΫΤϦ query { user(id: "aaa") {ccc id name }a }b

  30. εΩʔϚͱΫΤϦ { "data" : {ccc "id": "aaa", "name": "ү֋Ղయ" }a

    }b
  31. εΩʔϚ type Query { users: [User!]! } type User {

    id: ID! name: String! first_name: String! twitter: String! icon: String! }
  32. ΫΤϦ query user() { name } query user() { first_name

    } query user() { twitter } query user() { Id } query user() { Icon }
  33. Ͳ͏͍͏ͱ͜ΖͰ࢖͏ͱྑ͍͔ʁ • FE/BEෳ਺ਓ͕։ൃΛ୲౰ • ϦϞʔτͳͲର໘ରԠ͕Ͱ͖ͳ͍ • ରԠ͢ΔλΠϛϯάʹ͕࣌ࠩ͋Δ

  34. ࣄྫ Ubie, Inc

  35. ࣄྫ Ubie, Inc

  36. ࿩͢͜ͱ • GraphQLͱ͸Կʁ • Kotlin+GraphQLͷίʔυͷྲྀΕ • Kotlin+GraphQLͷςετ • Kotlin+GraphQLͷೝূ •

    Kotlin+GraphQLͷपลπʔϧ
  37. kotlin-graphql-sample dependencies { implementation("org.springframework.boot:spring-boot-starter") implementation("com.graphql-java-kickstart:graphql-spring-boot-starter") implementation("com.graphql-java-kickstart:graphiql-spring-boot-starter") implementation(“com.graphql-java-kickstart:graphql-java-tools") implementation("org.springframework.boot:spring-boot-starter-jdbc") }

  38. εΩʔϚ type Drug { id: String! name: String! yjCode: String!

    description: String } type Disease { icd: String! name: String! }
  39. εΩʔϚ data class Drug( val id: String, val name: String,

    val yjCode: String, val description: String? ) data class Disease( val icd: String, val name: String )
  40. Query type Query { drug(id: String!) : Drug drugs(yjCode: String!)

    : [Drug!]! diseases(icd: String!) : [Disease!]! }
  41. GraphQLQueryResolver • GraphQLQueryResolverΛܧঝ • ΞϓϦέʔγϣϯ಺ͷ͢΂ͯͷܧঝͨ͠ΫϥεΛࢀর • ϝιου໊ɺҾ਺ɺ໭Γ஋ͰϚοϐϯά • ϝιου໊͸getterͰ΋OK

  42. εΩʔϚ type Query {a drugs(yjCode: String!) : [ Drug !]!

    }a
  43. εΩʔϚ @Component class DrugQueryResolver : GraphQL Query Resolver {a fun

    drugs(yjCode: String ! ) : List< Drug > = TODO() }a
  44. εΩʔϚ @Component class DrugQueryResolver : GraphQL Query Resolver { fun

    drugs(yjCode: String ! ) : List< Drug > = TODO() }
  45. Query type Query { drug(id: String! ) a : a

    Drug drugs(yjCode: String! ) a : a [Drug!]! diseases(icd: String! ) a : a [Disease!]! }
  46. Query @Component class DrugQueryResolver : GraphQLQueryResolver { fun drug(id: String

    ) a : a Drug? = TODO() fun drugs(yjCode: String ) a : a List< Drug > = TODO() } @Component class DiseaseQueryResolver : GraphQLQueryResolver { fun diseases(icd: String ) a : a List< Disease > = TODO() }
  47. Request

  48. Response

  49. ෮श • εΩʔϚ͕ॏཁ • type͕͋Δ • KotlinͰ͸data classͰදݱͰ͖Δ • type

    Query(ͱMutation)͕ಛघ • GraphQLQueryResolverͷϝιουʹ Ϛοϐϯά͞ΕΔ type Drug { id: ID! name: String! description: String } type Query { drugs(code: String) : [Drug]! }
  50. ෮श໰୊ type User { name: String } data class User(

    val name: String ) data class User( val name: String? ) data class User( val name: List<String> )
  51. ͜͜ʹ͍Δਓͨͪ • KotlinΛ৮ͬͨ͜ͱ͕͋Δ • αʔόαΠυKotlinɺGraphQLʹڵຯ͕͋Δ • GET/POST΍ϨεϙϯείʔυͳͲͷHTTPͷجૅతͳ஌͕ࣝ͋Δ • ηογϣϯதʹ൓Ԡͯ͘͠ΕΔ

  52. ෮श໰୊ type User { name: String } data class User(

    val name: String ) data class User( val name: String? ) data class User( val name: List<String> )
  53. typeͷؔ܎

  54. typeͷؔ܎ type Drug { id: ID! name: String! yjCode: String!

    description: String kinkiDiseases: [Disease!]! } type Disease { icd: String! name: String! kinkiDrugs: [Drug!]! } data class Drug( val id: String, val name: String, val yjCode: String, val description: String? ) data class Disease( val icd: String, val name: String )
  55. GraphQLResolver • GraphQLResolverΛܧঝ • ܕม਺͕ϝιουͷҾ਺ • ͋ͱ͸GraphQLQueryResolverͱಉ͡

  56. typeͷؔ܎ type Drug { … kinkiDiseases: [Disease!]! } Drug

  57. typeͷؔ܎ class DrugResolver : GraphQLResolver< Drug > { fun kinkiDiseases

    (drug: Drug): List< Disease > { TODO() } }
  58. Kotlinݺͼग़͞ΕΔॱ൪

  59. Kotlinݺͼग़͞ΕΔॱ൪

  60. Kotlinݺͼग़͞ΕΔॱ൪

  61. type Drug { id: ID! name: String! yjCode: String! description:

    String kinkiDiseases: [Disease!]! } data class Drug( val id: String, val name: String, val yjCode: String, val description: String? ) εΩʔϚͱKotlinͷϚοϐϯά·ͱΊ
  62. type Drug { id: ID! name: String! yjCode: String! description:

    String kinkiDiseases: [Disease!]! } class DrugResolver : GraphQLResolver<Drug> { fun kinkiDiseases(drug: Drug): List<Disease> {…} } εΩʔϚͱKotlinͷϚοϐϯά·ͱΊ
  63. type Drug { id: ID! name: String! yjCode: String! description:

    String kinkiDiseases: [Disease!]! } data class Drug( val id: String, val name: String, val yjCode: String, val description: String? ) class DrugResolver : GraphQLResolver<Drug> { fun kinkiDiseases(drug: Drug): List<Disease> {…} } εΩʔϚͱKotlinͷϚοϐϯά·ͱΊ
  64. ࿩͢͜ͱ • GraphQLͱ͸Կʁ • Kotlin+GraphQLͷίʔυͷྲྀΕ • Kotlin+GraphQLͷςετ • Kotlin+GraphQLͷೝূ •

    Kotlin+GraphQLͷपลπʔϧ
  65. • mock͢Ε͹OK Kotlin+GraphQLͷςετ Ҏ্ɻ

  66. ࿩͢͜ͱ • GraphQLͱ͸Կʁ • Kotlin+GraphQLͷίʔυͷྲྀΕ • Kotlin+GraphQLͷςετ • Kotlin+GraphQLͷೝূ •

    Kotlin+GraphQLͷपลπʔϧ
  67. Kotlin+GraphQLͷೝূ • ೝূํ๏͸͍͔ͭ͋͘Δ • Auth HeaderͷtokenͰೝূ͢Δํ๏Λ঺հ • Authorization: Bearer <credentials>

  68. DataFetchingEnvironment • ֤छResolver͔ΒΞΫηεՄೳ • Fetch͢΂͖৘ใ • ϑΟʔϧυͷҾ਺ • ϑΟʔϧυͷ਌ͷ৘ใ

  69. DataFetchingEnvironment @Component class DrugQueryResolver : GraphQLQueryResolver { fun drug(id: String):

    Drug? { TODO() }a }a
  70. DataFetchingEnvironment @Component class DrugQueryResolver : GraphQLQueryResolver { fun drug( id:

    String, environment: DataFetchingEnvironment): Drug? { TODO() }a }a
  71. DataFetchingEnvironment @Component class DrugQueryResolver : GraphQLQueryResolver { fun drug( environment:

    DataFetchingEnvironment, id: String): Drug? { TODO() }a }a ເͷ࿩Ͱ͢
  72. DataFetchingEnvironment @Component class DrugQueryResolver : GraphQLQueryResolver { fun DataFetchingEnvironment. drug(

    id: String): Drug? { TODO() }a }a ເͷ࿩Ͱ͢
  73. Context • DataFetchingEnvironment͔ΒContextʹΞΫηεͰ͖Δ • ΫΤϦड͚औΓʙऴΘΓ·Ͱੜ͖Δ • ͲΜͳ஋Ͱ΋OK • GraphQLContextΛܧঝ͢Δ •

    ެ͕͓ࣜ͢͢Ί
  74. Context class AuthContext(httpServletRequest: HttpServletRequest, val userId: Long?) : GraphQLContext(httpServletRequest)

  75. GraphQLContextBuilder @Bean fun contextBuilder(): GraphQLContextBuilder { return object : DefaultGraphQLContextBuilder()

    { }b }a
  76. GraphQLContextBuilder @Bean fun contextBuilder(): GraphQLContextBuilder { return object : DefaultGraphQLContextBuilder()

    { override fun build( httpServletRequest: HttpServletRequest, httpServletResponse: HttpServletResponse ): GraphQLContext { }c }b }a
  77. GraphQLContextBuilder @Bean fun contextBuilder(): GraphQLContextBuilder { return object : DefaultGraphQLContextBuilder()

    { override fun build( httpServletRequest: HttpServletRequest, httpServletResponse: HttpServletResponse ): GraphQLContext { val authHeader = httpServletRequest.getHeader(“Authorization") }c }b }a
  78. GraphQLContextBuilder @Bean fun contextBuilder(): GraphQLContextBuilder { return object : DefaultGraphQLContextBuilder()

    { override fun build( httpServletRequest: HttpServletRequest, httpServletResponse: HttpServletResponse ): GraphQLContext { val authHeader = httpServletRequest.getHeader("Authorization") val token = authHeader?.removePrefix("Bearer ") val userId = TODO() // ͳΜͱ͔͢Δ }c }b }a
  79. GraphQLContextBuilder @Bean fun contextBuilder(): GraphQLContextBuilder { return object : DefaultGraphQLContextBuilder()

    { override fun build( httpServletRequest: HttpServletRequest, httpServletResponse: HttpServletResponse ): GraphQLContext { val authHeader = httpServletRequest.getHeader("Authorization") val token = authHeader?.removePrefix("Bearer ") val userId = TODO() return AuthContext(httpServletRequest, userId) }c }b }a
  80. DataFetchingEnvironment @Component class DrugQueryResolver : GraphQLQueryResolver { fun drug(id: String,

    environment: DataFetchingEnvironment): Drug? { TODO(“DrugΛऔಘ͢Δॲཧ”) }b }a
  81. DataFetchingEnvironment @Component class DrugQueryResolver : GraphQLQueryResolver { fun drug(id: String,

    environment: DataFetchingEnvironment): Drug? { environment.getContext<AuthContext>().userId ?: throw Exception(“ೝূ͞Εͯͳ͍Α”) TODO(“DrugΛऔಘ͢Δॲཧ”) }b }a
  82. Kotlin + GraphQLೝূ·ͱΊ • DataFetchingEnvironment͸֤छResolverͰΞΫηεՄೳ • ಠࣗͷContextΛ࡞੒Մೳ • GraphQLContextΛܧঝ͢Δ •

    Context͸GraphQLContextBuilder#build಺Ͱੜ੒ • Contextʹೝূ৘ใ࣋ͨͤͯResolver಺Ͱೝূ͢Δ
  83. ࿩͢͜ͱ • GraphQLͱ͸Կʁ • Kotlin+GraphQLͷίʔυͷྲྀΕ • Kotlin+GraphQLͷςετ • Kotlin+GraphQLͷೝূ •

    Kotlin+GraphQLͷपลπʔϧ
  84. GraphiQL • ϒϥ΢βΛGraphQLͷΫΤϦฤूIDEʹ • dependenciesʹॻ͚͹ɺαʔό্ཱͪ͛Ε͹ಈ͘ʂ dependencies { implementation("com.graphql-java-kickstart:graphiql-spring-boot-starter") }

  85. σϞ

  86. Altair • GraphiQLͱ΄΅ಉ͡ • HeaderͷઃఆΛϒϥ΢β্Ͱ؆୯ʹग़དྷΔ dependencies { implementation("com.graphql-java-kickstart:altair-spring-boot-starter") }

  87. apollo-android • GraphQLΛ࢖͏ଆ • Androidͱॻ͔Ε͍ͯΔ͚ͲɺJavaϕʔεͰར༻Մೳ

  88. ͝੩ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠