`graphql-code-generator` 에서 `typescript-resolvers`...
# 질문
x
graphql-code-generator
에서
typescript-resolvers
플러그인을 사용하여 리졸버 타입을 생성하려고 하는 중인데요, 반환 타입이 전체 필드를 다 채울 것을 요구해서 타입 내부 리졸버에서 채워넣을 만한 값들을 전부 미리 채워넣어야지만 타입이 맞게 되는 것 같은데 혹시 리졸버 반환 타입들에 대해 Recursive하게 `Partial<T>`를 먹인다거나 할 방법이 있을까요?
h
엥 제 기억엔 기본이 옵셔널이였는데
아 리졸버가 옵셔널인게 아니라
리졸버의 리턴타입을 바꾸고 싶다는거군요
제너레이터 옵션으로는 resolver fn 을 바꾸면 되고요
그 쪽 옵션 안바꿀거면 생성된 타입을 재귀적으로 변경하는 타입레벨 유틸리티를 짜면 됩니다
기본이
(parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo) => Promise<TResult> | TResult
인데
(parent: TParent, args: TArgs, context: TContext, info: GraphQLResolveInfo) => Promise<DeepPartial<TResult>> | DeepPartial<TResult>
이 되면 되는거죠
좋은 방법은 아니라 별로 추천하지 않습니다.
x
음 그럼 어떤 방법을 추천하시나요…?
h
그렇게 하지 않는거요..
x
아 제 말은 이 문제를 해결할 다른 방법이 있는지
h
실제 문제는 어떤건지 모릅니다 질문에 포함이 안되어있어서요
이미 수단이 정해져서 질문을 하셔서요
저건 그냥 타입스크립트 수준에서 하셔도 됩니다
사실 타입스크립트 수준에서 해결을 해야 그걸 옵션으로 타입 제너레이터에 넣을 수 있죠
근데 그 타입이라는게 나는 이걸 이렇게 쓸거야 하고 주장하는거고 컴파일러는 그걸 믿을 수 밖에 없는데요
아시다시피 DeepPartial 을 먹여버리면 사실 타입을 쓰는 장점을 거의 포기하게 됩니다
x
아 대충 SDL에
type Foo { item: Item, value: String }
같이 정의된 타입이 있다고 치면 전체 리졸버에서는
{ itemId: String, value: String }
을 리턴하고 `Foo`의 리졸버에
item
에 대한 리졸버를 추가해서
parent.itemId
를 읽어서 가져오게 하고 싶은 상황입니다
h
질문이 거의 DeepPartial 은 어떻게 구현하나요? 였는데 DeepPartial 구현은 찾아보면 많이 존재합니다. 타입스크립트 타입라이브러리들이 거의다 제공하고 있어서 그걸 쓰셔도 됩니다
GraphQL 리졸버는 실행맥락을 반영하기 때문에
resolver의 리턴 타입이 해당 오브젝트 타입을 반영할거라는건 너무 단순한 가정이고 사실 codegen 은 GraphQL 타입에 대한 정보밖에 가지고 있지 않기 때문에 어쩔 수 없는 부분이기도 한데요
사실 이 문제에 대한 답은 실행맥락을 알고있는 쪽에서 정해주는거 밖에 방법이 없습니다.
리졸버의 첫번째 인자는 항상 추상적이에요 언어가 그렇게 설계되었기 때문에
그 추상화 수준은 어플리케이션 주인장 밖에 모릅니다
이걸 어떻게 표현하냐
이걸 표현하는 가장 적절한 옵션은요
GraphQL Type 과 애플리케이션 맥락을 매핑할 수 있는 모델을 만들고 매퍼에 넘겨줘야해요
DDD 보셨으면 거기서 포트라고 부르는 것, 아님 다른 프레임워크에서 DTO라고 부르는 것과 비슷합니다
x
음 그러면 결국 개별 타입에 대한 정의는 따로 해주는 방향으로 사용을 해야 하나 보네요… 뭐 다른 방법이 있을 수가 없을 것 같긴 한데 ㅋㅋㅋㅋㅋ 암튼 감사합니다
h
물론 저런걸 일반화한 시도도 많이 있긴 합니다
좀 옛날에 본거같은데
아 이건 런타임이지 타입에 대한 해결책이 아니군요
타입 수준에서는 직접 추상화 하셔야할듯
👍 1
그냥 partial 하고 뭉개셔도 되는데요 그럼 타입수준에서 안정성을 다 잃어버리니 대충하지 않는걸 추천드립니다
id 만 가지고 초기화 되는건 그럴 수 있지만
적어도 사용하는 쪽에서 필요한 데이터를 밸리데이션하는게 보장되는 방식으로 만들 수 있을거같습니다
이미 엔티티 프레임워크를 사용하시는 경우 그런걸 담당할 레이어가 이미 구현되어 있을 수 있고요
아님 데이터로더 같은거 스까서 대충 만들면 많이 씁니다
로더가 몇중으로 나오는지 같은 것도 실제 스키마에 따라 필요한 수준이 다르기 때문에 위 라이브러리 같은거 말고 일반화된건 좀 찾기 어렵습니다
일반화 하면 유연성이 떨어져서요...
x
그러게요 클래스 만들어서 게터 같은 걸 붙여야 하나 싶어지는
h
사실 데이터로더만 해도 어느정도 스케일까지는 충분하긴 해요
보통 찾으시는 물건은 테이블이 너무 거대해지거나 등등의 이유로 DB IOPS가 빡세지면 고려하게되는데
그마저도 앞에서 캐싱을 잘해주면 많이 미룰 수 있는지라
레이지 로딩을 고려하는 순간 프로그래밍 모델에 어렵거나 불편해지는 부분이 굉장히 많은데요
안할 수 있으면 안하는게 좋지 않나... 합니다
x
혹시 Postgraphile 쓰면 쿼리 옵티마이저에서 이런 거 다 처리해주려나요
h
그걸 정말 잘 만든(?) 사례가 뭐냐면 액티브레코드 라고 불리는 물건인데요
아 Postgraphile 은 GraphQL-to-SQL 에 가깝습니다
쿼리가 컴파일되서 나가기 때문에 그런걸 신경을 안씁니다
네 그니까 다 처리해주는게 맞긴 한데요. 여전히 유연성과의 트레이드오프입니다.
애초에 이 솔루션의 이름에서 알 수 있듯이 백엔드를 단일 모놀리스 SQL로 전제하고 시작한다는 함정이 있습니다
유연성이란 그런것
x
유연성 트레이드오프라는 건 스키마가 DB 모델에 영향받는 부분을 말씀하시는 건가요?
h
DB와 커플링하는거죠
GraphQL 자체가 해당 DB에 대한 액티브레코드가 되는겁니다.
이쯤에서 액티브 레코드에 대한 논평도 굉장히 읽을만합니다
x
뭔가 많이 쏟아졌는데….찬찬히 읽어봐야겠군요
ㅋㅋㅋㅋㅋ
h
덕분에 제 트위터에 그럴싸한 말이 +1 https://twitter.com/KrComet/status/1494920089157586945
😂 1
몇년후에 이걸 또 쓸것입니다
👍 1