Skip to content

Latest commit

 

History

History
121 lines (105 loc) · 5.47 KB

README.md

File metadata and controls

121 lines (105 loc) · 5.47 KB

Sample-Spring-Graphql-Project (feat.Netflix DGS)

Background

: 2022.11월 기준으로 들어가는 사이드프로젝트에 사용할 기술스택으로 graphql이 선정되었고 기존에 spring에 대한 지식을 쌓는게 목적에 있었으므로 DGS를 체택 후 공부용으로 제작했습니다. 기획서가 나오기까지 3일 남은 시점에서 짧은 기간동안 빠르게 학습하다보니 코드의 가독성은 약간 떨어질 수 있는 점 양해바랍니다.(나머진 사프하면서 학습....)

ERD

: https://github.com/terry960302/sample-spring-webflux-pattern 에서 사용했던 같은 스키마 구조를 ORM으로 녹였습니다. 최대한 시간을 절약하기 위해.ㅎㅎ

  • UserCredential, CredentialRole, AccountRole 테이블이 Security 기능을 온전히 구현하기 위해 추가되었습니다.

Issues

  • MappedBatchLoader with default value

    // common function example used in dataloader
      fun getAccountRolesByCredentialIds(ids: List<Long>): MutableMap<Long, List<AccountRole>> {
        val roles: List<CredentialRole> = credentialRoleRepository.getCredentialRolesByCredentialIds(ids)
        return roles.groupBy { it.userCredential!!.user!!.id } 
            .map { uc -> uc.key to uc.value.map { cred -> cred.accountRole!! } }.toMap().toMutableMap()
    }
    But `groupBy` method not include all ids. 
    
    Some accountRoles entities under credential entity will set to be `null`.
    But we want it be `empty list`.
    
    So made `groupFillBy` method.
    // use this function
    inline fun <T, K> Iterable<T>.groupFillBy(keys : Iterable<K>, keySelector: (T) -> K): Map<K, List<T>> {
        val groups = LinkedHashMap<K, MutableList<T>>()
        for (key in keys){
            groups[key] = mutableListOf()
        }
        for (element in this) {
            val key : K = keySelector(element)
            val list = groups.getOrPut(key) { ArrayList<T>() }
            list.add(element)
        }
        return groups
    }

Need to Study

  • Setup DGS
    • [Issue] graphql.java library version conflict issue => resolved
  • Relations (1:1, 1:N, N:N) using JPA
    • Implement N:N relation using double OneToMany in (Posting & PostingImage & Image) if want to set extra column in JoinTable
    • Fetch extra custom fields with entity not in DB columns using @Transient & @Postload annotations
  • Apply DataFetcher
  • Apply DataLoader in join column
    • [Performance Tested] getAllPostings : 2 posting each has 500 images => fast enough
    • [Performance Tested] getAllPostings : 100 postings each has 500 images => 1300ms
    • [Performance Tested] getAllPostings(+pagination) : 10 postings each has 100 images(normal use case in production) => 111ms
    • [Performance Tested] getAllPostings(+pagination) : 10 postings each has 100 images with 10 comments => 180ms
  • Aggregate(Count) field
    • aggregate용 쿼리를 따로 제작(기존 쿼리안에 _count 필드로 녹이는 법은 반환 객체를 감싸는 객체를 만든 후, 거기에다 _count를 넣으면 되지만 filter나 input에 대해 분기처리가 많아지는 경우 로직이 복잡해지기 쉽고, 개인적으로 프론트에서 작업할 때도 독립적인 query로 가져오는 방식을 더 사용하게 됨. 성능적인 이슈도 존재)
  • Pagination(Pageable), OrderBy(Sort) etc.. Filter input
  • Security
    • Single Endpoint authentication(그래프큐엘이 단일 엔드포인트이기 때문에)
    • Query, Mutation authentication, authorization using 'Pre-Authorize'(쿼리별로 보안 설정)
    • Jwt stateless authentication, authorization(세션이 아닌 Jwt 토큰 방식 사용)
    • Set auth related db tables in entities, graphql schemas(단순히 인메모리 데이터가 아닌 ERD 적용하여 디비 데이터를 테스트에 사용)
  • Instrumentation(logging, metrics) => check turnaround per each method

ENV

dgs:
  graphql:
    graphiql:
      title: "Sample-Spring-Graphql"
      enabled: true
    path: /graphql/**
server:
  host: localhost
  port: 8000

spring:
  datasource:
    driver-class-name: org.postgresql.Driver
    url: jdbc:postgresql://localhost:5432/postgres
    username: postgres
    password: postgres
  jpa:
    open-in-view: true
    hibernate:
      ddl-auto: create-drop # create-drop, create, update, validate, none
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
      use-new-id-generator-mappings: false
    show-sql: true
    properties:
      hibernate:
        format_sql: true
      dialect: org.hibernate.dialect.PostgreSQLDialect

logging:
  level:
    org.hibernate.SQL: debug
    org.hibernate.type: trace

References