GraphQL 실행 결과를 쉽게 입력하는 방법 단계별 가이드
한 마디로 하면
Fragment
첫 번째 방법은 TypeScript를 쉽게 처리할 수 있다는 것을 알게 되었다.왜?그것은 유형 정의의 중용성을 가속화시켰다.그것이 어떻게 일을 하는지 우리에게 보여 주시오.[편집]
나는 현실 세계의 전단 프로젝트(프리랜서로서)를 실현하려고 시도할 때Colocating Fragment가GraphQL+TypeScript에 가장 적합하다는 것을 깨달았다.이런 모델은 좀 지루하지만 성명성을 가지고 있어 확장하기 쉽다.그러므로 본문을 읽는 것보다 자세히 읽는 것이 낫다. https://www.apollographql.com/docs/react/data/fragments/#colocating-fragments
[/편집]
1단계 - 유형 없음
the example from react-apollo에서 아래 코드를 볼 수 있습니다.
import { useQuery, gql } from "@apollo/client"
const EXCHANGE_RATES = gql`
query GetExchangeRates {
rates(currency: "USD") {
currency
rate
}
}
`
function ExchangeRates() {
const { loading, error, data } = useQuery(EXCHANGE_RATES)
if (loading) return <p>Loading...</p>
if (error) return <p>Error :(</p>
return data.rates.map(({ currency, rate }) => (
<div key={currency}>
<p>
{currency}: {rate}
</p>
</div>
))
}
그것은 보기에는 괜찮지만 data
의 유형을 상상해 보세요.네, 네.그것은 유형의 안전을 파괴했다. 너는 미칠 것이다.Note: technically not
any
butRecord
, although they are almost same in this context
2단계 - 수동 입력
any
가 data
로 바뀌는 것을 피하기 위해서 우리는 TypeScript의 일반 기능을 사용하여 조회 결과를 입력할 수 있다.import { useQuery, gql } from "@apollo/client"
interface GetExchangeRates {
rates: {
currency: string
rate: number
}[]
}
const EXCHANGE_RATES = gql`
query GetExchangeRates {
rates(currency: "USD") {
currency
rate
}
}
`
function ExchangeRates() {
const { loading, error, data } = useQuery<GetExchangeRates>(EXCHANGE_RATES)
if (loading) return <p>Loading...</p>
if (error) return <p>Error :(</p>
// Type signature of `data` is:
// {
// rates: {
// currency: string
// rate: number
// }[]
// }
return data.rates.map(({ currency, rate }) => (
<div key={currency}>
<p>
{currency}: {rate}
</p>
</div>
))
}
보시다시피 이것은 너무 고통스럽다!질의를 업데이트할 때마다 인터페이스를 수동으로 업데이트해야 합니다.3단계 - codegen 을 입력합니다.
다행히도, GraphQL 조회에서TypeScript의 형식 정의를 생성할 수 있습니다.
https://github.com/apollographql/apollo-tooling#apollo-clientcodegen-output
Note: there are some tools other than apollo, but I prefer apollo because it is the most minimal one.
형식 정의를 만들기 위해 명령을 실행합시다.
npx apollo client:codegen \
--localSchemaFile schema.gql \
--target typescript \
--includes 'src/**/*.{ts,tsx}'
Note: If you run the above command it will fail, because you won't have
schema.gql
in local.
네가 있는지 확인해라
any
.GraphQL 서버는 GraphQL 모드를 파일로 보내는 기능을 갖추어야 합니다.명령이 실행되면 다음 코드가 포함된 출력 파일이 표시됩니다.
// __generated__/GetExchangeRates.ts
export interface GetExchangeRates_rate {
currency: string
rate: number
}
export interface GetExchangeRates {
rates: GetExchangeRates_rate[]
}
그래서 우리는 생성된 형식으로 마지막 코드를 바꿀 수 있다.import { useQuery, gql } from "@apollo/client"
import { GetExchangeRates } from "./__generated__/GetExchangeRates"
const EXCHANGE_RATES = gql`
query GetExchangeRates {
rates(currency: "USD") {
currency
rate
}
}
`
function ExchangeRates() {
const { loading, error, data } = useQuery<GetExchangeRates>(EXCHANGE_RATES)
if (loading) return <p>Loading...</p>
if (error) return <p>Error :(</p>
return data.rates.map(({ currency, rate }) => (
<div key={currency}>
<p>
{currency}: {rate}
</p>
</div>
))
}
이것은 훨씬 쉽다!단점은 GraphQL 코드를 편집할 때마다 명령을 실행해서 형식 정의를 만들어야 하는데, 이것은 수동으로 입력하는 것보다 훨씬 쉽다는 것이다.
나는 이것이 비교적 작은 프로젝트에 있어서 이미 충분하다고 생각한다.그러나 프로젝트가 계속 늘어나면 유형의 중용성에 문제가 생길 수 있다.
단계 4 - 유형 정의 재사용
apollo-tooling
덕분에 우리는 유형 정의를 생성할 수 있다.그러나 어떻게 이런 유형의 정의를 다시 사용합니까?상상해 보세요. 우리는 이렇게 우리의 구성 요소를 분리하고 싶습니다.
// ExchangeRates.tsx
import { useQuery, gql } from "@apollo/client"
import { GetExchangeRates } from "./__generated__/GetExchangeRates"
import { ExchangeRateItem } from "./ExchangeRateItem"
const EXCHANGE_RATES = gql`
query GetExchangeRates {
rates(currency: "USD") {
currency
rate
}
}
`
function ExchangeRates() {
const { loading, error, data } = useQuery<GetExchangeRates>(EXCHANGE_RATES)
if (loading) return <p>Loading...</p>
if (error) return <p>Error :(</p>
return data.rates.map((rate) => (
<ExchangeRateItem rate={rate} key={rate.currency} />
))
}
// ExchangeRateItem.tsx
import { GetExchangeRates_rate } from "./__generated__/GetExchangeRates"
interface ExchangeRateItemProps {
rate: GetExchangeRates_rate
}
export function ExchangeRateItem({ rate }: ExchangeRateItemProps) {
const { currency, rate } = rate
return (
<div>
<p>
{currency}: {rate}
</p>
</div>
)
}
보시다시피 GraphQL 형식 정의는 생성된 코드에서 가져올 수 있습니다.그러나 그것은 혼란스러워야 한다. 왜냐하면:schema.gql
.apollo
-> ExchangeRateItem
-> ExchangeRateItem
-> __generated__
Note: Technically
__generated__
does not depends onExchangeRates
, but conceptually it depends, as type definitions are generated from it.
나는 아직 이 문제를 어떻게 처리하는지 완전히 이해하지 못했지만, 두 가지 해결 방안이 있는데, 사용
ExchangeRates
이다.단계 4.1 - 공용 쿼리 및 세션 작성
첫 번째는 영역 분리에 기반한 것이다.GraphQL과 관련된 공용 파일을 만들고 구성 요소가 아닌 로직을 작성하는 것이 좋습니다.
// graphql/Rate.ts
import { useQuery, gql } from "@apollo/client"
import {
GetExchangeRates,
GetExchangeRates_rate,
} from "./__generated__/GetExchangeRates"
// Re-export fragment type because of reusability
export type { RateFragment } from "./ExchangeRateItem"
const RATE_FRAGMENT = gql`
fragment RateFragment on Rate {
currency
rate
# ...And other props in the future
}
`
const EXCHANGE_RATES = gql`
query GetExchangeRates {
rates(currency: "USD") {
...RateFragment
}
}
${RATE_FRAGMENT}
`
export const useRates = () => useQuery<GetExchangeRates>(EXCHANGE_RATES)
// Other fragments, hooks, queries will follow
// ExchangeRates.tsx
import { useRates } from "./graphql/Rate"
import { ExchangeRateItem } from "./ExchangeRateItem"
function ExchangeRates() {
const { loading, error, data } = useRates()
if (loading) return <p>Loading...</p>
if (error) return <p>Error :(</p>
return data.rates.map((rate) => (
<ExchangeRateItem rate={rate} key={rate.currency} />
))
}
// ExchangeRateItem.tsx
import { RateFragment } from "./graphql/Rate"
interface ExchangeRateItemProps {
rate: RateFragment
}
export function ExchangeRateItem({ rate }: ExchangeRateItemProps) {
const { currency, rate } = rate
return (
<div>
<p>
{currency}: {rate}
</p>
</div>
)
}
GraphQL 코드를ExchangeRateItem
로 이동한 후에 의존 관계는 선형으로 바뀌었다.Fragment
-> ./graphql/Rate
-> ExchangeRates
graphql/Rate
-> __generated__
-> ExchangeRates
-> ExchangeRateItem
graphql/Rate
데이터를 얻는 방법을 알고 있습니다.__generated__
인터페이스를 공개했다.graphql/Rate
와 graphql/Rate
는 데이터를 어떻게 얻는지 모른다.그것들은 실현에 의존하지 않고 데이터 원본과 유형의 인터페이스에 의존한다.단계 4.2 - 총 세그먼트 배치
또 다른 해결 방안은 '공통 포지셔닝 세션' 이라는 모델을 사용해서 중성자 구성 요소가 어떤 데이터를 필요로 하는지 설명하는 것이다.
// ExchangeRates.tsx
import { useQuery, gql } from "@apollo/client"
import { ExchangeRateItem, RATE_ITEM_FRAGMENT } from "./ExchangeRateItem"
const EXCHANGE_RATES = gql`
query GetExchangeRates {
rates(currency: "USD") {
...RateItemFragment
}
}
${RATE_ITEM_FRAGMENT}
`
function ExchangeRates() {
const { loading, error, data } = useQuery<GetExchangeRates>(EXCHANGE_RATES)
if (loading) return <p>Loading...</p>
if (error) return <p>Error :(</p>
return data.rates.map((rate) => (
<ExchangeRateItem rate={rate} key={rate.currency} />
))
}
// ExchangeRateItem.tsx
import { gql } from "@apollo/client"
import { RateItemFragment } from "./__generated__/RateItemFragment"
export const RATE_ITEM_FRAGMENT = gql`
fragment RateItemFragment on Rate {
currency
rate
# ...And other props in the future
}
`
interface ExchangeRateItemProps {
rate: RateItemFragment
}
export function ExchangeRateItem({ rate }: ExchangeRateItemProps) {
const { currency, rate } = rate
return (
<div>
<p>
{currency}: {rate}
</p>
</div>
)
}
이를 통해 다음과 같은 이점을 얻을 수 있습니다.아폴로 이외의 Codegen 도구
유형 문서 노드
추천
ExchangeRates
.나는 이 라이브러리를 시도해 본 적이 없지만, 그는 가장 똑똑한GraphQL 개발자 중의 하나이기 때문에 네가 가서 보아야 한다!https://the-guild.dev/blog/typed-document-node
@graphql-codegen/cli
이것은 길드의 수석 기술관이 제작한 것으로 광범위하게 사용된다.나는 아직 내 프로젝트에서 시도해 본 적이 없지만, 그것은 거의 모든 주요 도구를 포함한다.
https://github.com/dotansimha/graphql-code-generator
결론
ExchangeRateItem
또는 기타 도구로 GraphQL 결과 입력TypedDocumentNode
으로 유니버설 리셋 가능 유형 만들기Reference
이 문제에 관하여(GraphQL 실행 결과를 쉽게 입력하는 방법 단계별 가이드), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/acro5piano/step-by-step-guide-of-how-to-painlessly-type-graphql-execution-result-47kn텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)