ããã«ã¡ã¯ã Web ããã³ãã¨ã³ãã¨ã³ã¸ãã¢ã® @progfay ã§ãã
ãã®è¨äºã¯ Recruit Engineers Advent Calendar 2022 ã® 12 æ¥ç®ã®è¨äºã§ãã
ä»åã¯ããã¸ã§ã¯ãå
ã§ä½¿ã£ã¦ãã @graphql-codegen/typescript-react-apollo
package ã¨ã®æãåºãæ¸ã綴ã£ã¦ããã¾ãã
åºä¼ã
ç§ã®æå±ããã¹ã¿ãã£ãµããªä¸å¦è¬åº§ã®éçºããã¸ã§ã¯ã (é称: tara) ã§ã¯éä¿¡ã« GraphQL ãæ¡ç¨ãã¦ãã¾ãã ã¾ãã GraphQL Code Generator ã使ã£ã¦ GraphQL ã«ã¾ã¤ããåãé¢æ°ã®çæãè¡ãªã£ã¦ãã¾ãã
Web Frontend ã§ã¯ API Client ã¨ã㦠Apollo Client ã使ç¨ãã¦ããã TypeScript 㨠React 㨠Apollo Client ãåããã¦ä¾¿å©ã«æ±ãããã« @graphql-codegen/typescript-react-apollo
plugin ãç¨æããã¦ãã¾ãã
Apollo Client ã使ã£ã Request ã¯ä»¥ä¸ã®ããã«æ¸ããã¾ãã
import { gql, useQuery } from '@apollo/client' const SAMPLE_QUERY = gql` query SampleQuery($cardId: String!) { card(cardId: $cardId) { title ownerName createdAt } } ` const Sample = () => { const { loading, data, // anyå } = useQuery( SAMPLE_QUERY, { variables: { cardId: "0123" } } // åæ¨è«ã¯å¹ããªã ) // : }
ããã GraphQL Code Generator 㨠@graphql-codegen/typescript-react-apollo
ã使ãã¨ä»¥ä¸ã®ããã«ãªãã¾ãã
// GraphQL Code Generator ã«ããçæããããã¡ã¤ã«ãã import import { useSampleQuery } from './__generated__/graphql' const SAMPLE_QUERY = gql` query SampleQuery($cardId: String!) { card(cardId: $cardId) { title ownerName createdAt } } ` const Sample = () => { const { loading, data, // èªåçæãããåãä»ä¸ããã¦ãã } = useSampleQuery( { variables: { cardId: "0123" } } // åæ¨è«ãå¹ãï¼ ) // : }
Query ã®å¼æ°ãè¿ãå¤ã«åãä»ä¸ããããã Query ãã¨ã« custom hooks ãçæããããã¨ãéçºãããå¿«é©ã«è¡ããããã«ãªãã¾ãã ãã®æ©æµã¨ãã¦ç¡é§ãªè¨è¿°ãæ¶ãããããã£ããåã®æå®ãééãããã¨ããªããªã£ããã¨ãéçºã«ãããé¢åèããç·©åã§ãã¾ãã
ä¸æº: æ¯ååãã³ã¼ããæ¸ããããªã
ã©ããªã«ä¾¿å©ãªãã®ã§ãã使ã£ã¦ããä¸ã§ããã£ã¨ããããããã¨ããä¸æºã¯åºã¦ãã¾ãã æã ã®ããã¸ã§ã¯ãã§ã¯ããããGraphQL Request ã«å¤±æãããèªå㧠Error ã throw ãã¦ã»ãããã§ããã ã¨ããã®ããæã ã®ããã¸ã§ã¯ãã§ã¯ GraphQL Request ã«å¤±æãããåºãç»é¢ãç¨æããã¦ããã Error Boundary ã«ç¹å®ã® Error ã catch ãããã¨ããã表示ãããããã«ãªã£ã¦ãã¾ããã
ããã Apollo Client ã®æä¾ãã useQuery
㯠Error ã throw ãããè¿ãå¤ã« error: ApolloError | undefined
ãæã¡ã¾ãã
ãã®ãããé½åº¦ä»¥ä¸ã®ãããªå®è£
ãå¿
è¦ã«ãªã£ã¦ãã¾ããã
const Sample = () => { const { loading, data, error } = useSampleQuery() if (error !== undefined) throw error // : }
ããããæ¯åãã®è¨è¿°ãããã®ã¯é¢åã ãæ¸ãå¿ãããã¨ããã°ãã°ããã¾ããã ãã®çµæãéçºã®ä¸ã§ GraphQL Request ã«å¤±æããã¨ãã¼ãã£ã³ã°ç»é¢ããæãåºããªãäºè±¡ãªã©ãããã¤ãçºçãã¦ãã¾ããã ããã®åé¡ç¹ã¯ã¨ã©ã¼ãã³ããªã³ã°ã®å¦çãéçºè ãè¨è¿°ãããããªãããã° Opt-in ã®ãããªä»çµã¿ã§ãããã¨ã ã¨åæãã¾ããã ã§ããã°ãããã©ã«ãã§ã¨ã©ã¼ãã³ããªã³ã°ãè¡ããããªå¦çã«æ¸ãæããããªãã®ãï¼ãã¨ããæ¹åæ§ã«è©±ãé²ã¿ã¾ããã
Error Handling by default
ä¿®æ£ã«ãã¾ãã³ã¹ãããããªãããã«ã @graphql-codegen/typescript-react-apollo
ã«ç¨æããã¦ããæ©è½ã使ã£ã¦å®ç¾ã§ããªãããèãã¦ã¿ã¾ããã
å
¬å¼ããã¥ã¡ã³ããã½ã¼ã¹ã³ã¼ããèªãã§ã¿ã㨠@graphql-codegen/typescript-react-apollo
ã«ã¯è¤æ°ã® config ãç¨æããã¦ãã¾ããã
- typescript-react-apollo â GraphQL Code Generator
- graphql-code-generator-community/config.ts at 924bd6cdd220168d1ede23a1b40f853609d69620 · dotansimha/graphql-code-generator-community · GitHub
ãã®ä¸ã« useQuery
ã import ããå
ãæå®ã§ãã apolloReactHooksImportFrom
config ãããããããå©ç¨ã㦠Apollo Client ã® useQuery
ã wrap ãããã®ã使ãããæ¹åã§å®è£
ããã¦ã¿ã¾ããã
// src/lib/apollo/client.ts import { useEffect } from 'react' import { useQuery as useQueryOriginal } from '@apollo/client' import type * as Apollo from '@apollo/client' export interface QueryHookOptions<TData = any, TVariables = Apollo.OperationVariables> extends Apollo.QueryHookOptions<TData, TVariables> { readonly skipErrorHandling?: boolean } export function useQuery<TData = any, TVariables = Apollo.OperationVariables>( query: Apollo.DocumentNode | Apollo.TypedDocumentNode<TData, TVariables>, options?: QueryHookOptions<TData, TVariables> ) { const result = useQueryOriginal(query, options) if (!options?.skipErrorHandling && result.error !== undefined) throw result.error return result }
// codegen.yaml generates: src/__generated__/graphql.tsx: plugins: - typescript - typescript-operations - typescript-react-apollo config: apolloReactHooksImportFrom: ../apiClient/apollo/client
ããã«ãã useSampleQuery
ãªã©ã® GraphQL Code Generator ã«ãã£ã¦çæããã Custom Hooks ã¯å
é¨çã« src/lib/apollo/client.ts
ã§å®ç¾©ãããããã©ã«ã㧠Error Handling ãè¡ã useQuery
ã使ãããã«ãªãã¾ããã
ã¾ã useSampleQuery({ skipErrorHandling: true })
ã®ããã«è¨è¿°ãããã¨ã§ Error Handling ã Opt-Out ãããã¨ãå¯è½ã§ãã
ãã®ä»çµã¿ã«ãã£ã¦ã¨ã©ã¼ãã³ããªã³ã°å¦çãè¨è¿°ããç ©ããããæ¸ãå¿ãã¯ã»ã¼ 0 ã«ãªãã¾ããã
Apollo CLI ããã®ä¹ãæã
æ㯠2022 å¹´ 10 æã Node.js ã® Active LTS ã v16 ãã v18 ã«ç§»ã£ããããæã ãããã«è¿½å¾ãããã¨ã¨ãã¾ããã Node.js v18 移è¡ã®ããã« npm package ã® version ãä¸ãã¦ããã¨ã Apollo CLI ãå½æã®ææ°çã§ã Node.js v18 ã«å¯¾å¿ãã¦ãã¾ããã§ããã Node.js v18 ã«å¯¾å¿ãã¦æ¬²ããã¨ãã issue ãç«ã¦ãããèªå㧠Apollo CLI æ¬ä½ã Node.js v18 ã«å¯¾å¿ãããããªããã¨æ ¼éãããã¨é å¼µã£ã¦ã¿ã¾ãããããããã Apollo CLI 㯠deprecated ã¨ããæ±ãã«ãªã£ã¦ãã¾ããã
(Apollo CLI ã Node.js v18 ã«å¯¾å¿ãã¦ããªãåé¡ã®æ ¹æ¬åå ã§ãã£ã @apollo/federation
package 㯠v0.38.1 ã«ã¦ Node.js v18 ã«è¿½å¾ãã¾ããã Special Thanks @glasser!)
ãã®ããããããæ©ã« Apollo CLI ããå¥ã®æ段ã¸ã®ä¹ãæããèãã¯ããã¾ããã
v.s. Persisted Query
æã ã®ããã¸ã§ã¯ãã§ã¯ GraphQL ã® Persisted Query ãå©ç¨ãã¦ããããã®ããã« Apollo CLI ã使ã£ã¦ãã¾ããã éã«ãã以å¤ã®ç¨éã§ã¯ä½¿ããã¦ãã¾ããã§ããã ã¤ã¾ãã Persisted Query ãå¥ã®æ¹æ³ã§çæã§ããã° Apollo CLI ããã®ä¹ãæããéæã§ããã¨ãããã¨ã§ã GraphQL Code Generator ã§ãããã§ããªãããèãã¦ã¿ã¾ããã
GraphQL Code Generator ã® plugin ã¨ã㦠graphql-codegen-persisted-query-ids
ãããã¾ãã
ããã @graphql-codegen/typescript-react-apollo
ã¨ä¸æãä½µç¨ããããã«ã¯å°ã工夫ããã¦ãããå¿
è¦ãããããã§ããã
Persisted Query ã¯ä»¥ä¸ã®ãããªæé ã§å¦çãè¡ãã¾ãã
- Client å´ã§ GraphQL ã® Query ãæ£è¦åã hash ãåã
- hash ã HTTP Request ã«è¼ã㦠API ãå©ã
- Server å´ã§ hash ãæ¢ç¥ããæ¤è¨¼ãã (ä¿¡é ¼ã§ãã Client ãããªã¯ã¨ã¹ããããã§ããã Query ã® hash ãåãã£ã¦ãªã¹ãã¢ãããã¦ããå¿ è¦ããã)
- æ¢ç¥ã® hash ã ã£ãå ´åã¯å¯¾å¿ãã Response ãçæãè¿ã
ãããå®ç¾ããããã«ã¯ä»¥ä¸ã® 2 ã¤ãå®è£ ããå¿ è¦ãããã¾ãã
- Client å´ã§ GraphQL ã® Query ãæ£è¦åã hash ãåã
- ä¿¡é ¼ã§ãã Client ãããªã¯ã¨ã¹ããããã§ããã Query ã® hash ãåãã£ã¦ãªã¹ãã¢ãããã¦ãã
Apollo CLI ã§ã¯ Runtime 㧠Query ã®æ£è¦å㨠hash çæãè¡ãªã£ã¦ãã¾ãã ãã graphql-codegen-persisted-query-ids
ã§ã¯ GraphQL Code Generator ã«ããã³ã¼ãçææã«æ£è¦å㨠hash çæãè¡ãããã Runtime ã§ã®å¦çãæ£è¦åã» hash çæã®ããã®ã©ã¤ãã©ãªãä¸è¦ã«ãªãã¾ãããæé«ã
ããããã³ã¼ãçææã«ã¯ @graphql-codegen/typescript-react-apollo
ã«ããåæ
å ±ã Custom Hooks ã®ã³ã¼ã㨠graphql-codegen-persisted-query-ids
ã«ãã Persisted Query ã® hash æ
å ±ã¯å¥ã
ã®ãã¡ã¤ã«ã«åãåºãããããããããã対å¿ã¥ããå¦çãèªåã§æ¸ãå¿
è¦ãããã¾ãã
æ¹æ³ã¯æ§ã
ããã¾ãããä»å㯠@graphql-codegen/typescript-react-apollo
ã«ãã£ã¦èªåçæããããã¡ã¤ã«ã®æ«å°¾ã«ä»¥ä¸ã®ãããªè¡ã Query ã®æ°ã ã追å ããã¹ã¯ãªãããå®è¡ãããã¨ã§è§£æ±ºãã¾ããã
SampleQueryDocument.__hash = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
SampleQueryDocument
㯠query SampleQuery
ã gql
ã«ãã£ã¦ parse ããçµæã® AST ã§ãã
ãã® Object ã« __hash
property ãæ¡å¼µãã persistedQueryLink
ã®ä¸ã§ãã® hash ãåãåºãã¦ãããå®è£
ãæ¡ç¨ãã¾ããã
import { createPersistedQueryLink } from '@apollo/client/link/persisted-queries' const persistedQueryLink = createPersistedQueryLink({ useGETForHashedQueries: true, generateHash: (document) => { if (document.__hash === undefined) { throw new Error('document hash is not found') } return document.__hash }, }) const client = new CustomizedApolloClient({ link: [persistedQueryLink, /* and more... */] })
ãã㧠graphql-codegen-persisted-query-ids
ãç¨ãã Persisted Query ã«ä¹ãæãããã¨ã«æåãã Apollo CLI ããã®ä¹ãæããæããã¾ããï¼
@graphql-codegen/typescript-react-apollo
ããã®ä¹ãæãã®æã¯è¿ã...
ããã¾ã§æ¹é ãéãã¦ä½¿ãç¶ãã¦ãã @graphql-codegen/typescript-react-apollo
ã§ãããä»ã«ãæ¹åå¸æã¯åºã¦ãã¦ãã¾ãã
- Error Handling ã®å®è£ ã wrap ããé¢æ°ãçµç±ããã®ã§ã¯ãªãã custom hooks ã«ç´ã«å±éããã
gql
ã§ã® parse ã Runtime ã§è¡ããªãããã«ããã- GraphQL Query ã bundle ããåãé¤ããã (Persisted Query ã® hash ã®ã¿ã bundle ã«å«ããã)
ããããå®ç¾ããããã«ã¯ @graphql-codegen/typescript-react-apollo
ããèªåã§å®è£
ãã plugin ã«ä¹ãæããã®ãä¸çªç¾å®çããªã¨èãã¦ãã¾ãã
ãã£ã¦ããããæ°æã¡ã¯ããããããããå®ç¾ãããã¾ãããã°ã«ãããããªã¨æãã¾ãã
ãããã«
æ¬è¨äºã§ã¯ã @graphql-codegen/typescript-react-apollo
ã®æ¹é ã®è¨é²ããç´¹ä»ãã¾ããã
ã¹ã¿ãã£ãµããªã§ã¯ãä¸ç·ã« Web Frontend ã®éçºä½é¨ãããè¯ããã¦ãã仲éãåéãã¦ãã¾ãã
https://brand.studysapuri.jp/career/
ã¾ãã Recruit Engineers Advent Calendar 2022 ã§ã¯ãªã¯ã«ã¼ãã®ã¨ã³ã¸ãã¢é£ãè¨äºãæ稿ãã¦ããäºå®ã§ãã ãããªã¯ã«ã¼ãã«ãããã¨ã³ã¸ãã¢ãªã³ã°ã«èå³ãããã°ããã²ä»ã®è¨äºããããã¦ãåç §ãã ããã