Apollo-link-rest: 였λ₯˜ 응닡 처리

에 λ§Œλ“  2018λ…„ 10μ›” 02일  Β·  16μ½”λ©˜νŠΈ  Β·  좜처: apollographql/apollo-link-rest

μ•ˆλ…•ν•˜μ„Έμš”, μš”μ²­ 본문을 λ‹€μŒκ³Ό 같이 μ‚¬μš©ν•˜λŠ” 둜그인 APIκ°€ μžˆμŠ΅λ‹ˆλ‹€.

{
    "authentications": {
        "emailAddress": "[email protected]",
        "password": "11111111"
    }
}

μ„±κ³΅ν•˜λ©΄ μ„œλ²„ λ°˜ν™˜ 토큰 :

{
    "authentications": {
        "token": "eyJhbGoiU3RvcmUifV0sImNyZWF0ZWRBdCI6IjIwMTgtMDktMTZUMTg6NTA6NTYuNT"
    }
}

이메일 λ˜λŠ” λΉ„λ°€λ²ˆν˜Έ μž…λ ₯이 잘λͺ»λœ 경우 λ‹€μŒμ„ λ°˜ν™˜ν•©λ‹ˆλ‹€.

{
    "message": "Cannot find document for class 'User'. searched with parameters: '{\"emailAddress\":\"[email protected]\"}'",
    "errorCode": 1103,
    "status": 404
}

λ‹€μŒκ³Ό 같이 GraphQL μŠ€ν‚€λ§ˆλ‘œ μ„±κ³΅μ μœΌλ‘œ 둜그인 ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

gql`
  fragment Authentications on any {
    emailAddress: String
    password: String
  }

  fragment AuthInput on REST {
    authentications {
      Authentications
    }
  }

  mutation signIn($input: AuthInput!) {
    authPayload(input: $input) 
      @rest(type: "AuthPayload", path: "/api/v1/authentications", endpoint:"UsersService", method:"POST") {
      authentications @type(name:"Auth"){
        token
      }
    }
  }
`;

제 μ§ˆλ¬Έμ€ 였λ₯˜ (잘λͺ»λœ 이메일 / λΉ„λ°€λ²ˆν˜Έ)의 경우 μ–΄λ–»κ²Œ 응닡을받을 수 μžˆμŠ΅λ‹ˆκΉŒ? μ§€κΈˆ μ„œλ²„κ°€ 였λ₯˜λ₯Ό λ°˜ν™˜ν•˜λ©΄ 응닡은 항상 null이기 λ•Œλ¬Έμž…λ‹ˆλ‹€.

Object {
    "data": Object {
        "authPayload": null,
    },
    "errors": undefined,
}
help wanted πŸ›  question❔

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

λ‚˜λŠ” λ˜ν•œμ΄ λ¬Έμ œμ— λΆ™μ–΄ μžˆμŠ΅λ‹ˆλ‹€. null λŒ€μ‹  전체 404 응닡을 λ°˜ν™˜ν•˜μ§€ μ•ŠλŠ” μ΄μœ κ°€ μžˆμŠ΅λ‹ˆκΉŒ?

λͺ¨λ“  16 λŒ“κΈ€

400+ 였λ₯˜λ₯Ό μž‘μ„ 수 없닀면이 λ¬Έμ œκ°€ 유용 ν•  것이라고 μƒκ°ν•©λ‹ˆλ‹€.
https://github.com/apollographql/apollo-link-rest/issues/151

μ°Έκ³  : 잘λͺ»λœ 자격 증λͺ…μ˜ 경우 401을 λ°˜ν™˜ν•΄μ•Όν•©λ‹ˆλ‹€.
https://stackoverflow.com/questions/1959947/whats-an-appropriate-http-status-code-to-return-by-a-rest-api-service-for-a-val

μ•ˆλ…•ν•˜μ„Έμš”,

방금이 문제λ₯Ό λ§Œλ‚¬κ³  404λ₯Ό μ²˜λ¦¬ν•˜λŠ” 데 ꢌμž₯λ˜λŠ” 방법이 무엇인지 κΆκΈˆν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄ apollo-link-error λ₯Ό νŠΈλ¦¬κ±°ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

μ§€κΈˆκΉŒμ§€ μ‚¬μš©μž 지정 였λ₯˜ 처리기 링크λ₯Ό μž‘μ„±ν•˜κ±°λ‚˜ 각 <Query /> ꡬ성 μš”μ†Œμ˜ μ‘λ‹΅μ—μ„œ 데이터 μ½˜ν…μΈ λ₯Ό ν™•μΈν•˜λ €κ³ ν•©λ‹ˆλ‹€.

FWIW 예λ₯Ό λ“€μ–΄ μ„œλ²„κ°€ 401 λŒ€μ‹  404λ₯Ό λ°˜ν™˜ν•˜λŠ” λ™μΌν•œ κ²½μš°κ°€ μžˆμ§€λ§Œ λΆˆν–‰νžˆλ„ μ„œλ²„λ₯Ό λ³€κ²½ν•˜λŠ” 것은 ν˜„μž¬ μ˜΅μ…˜μ΄ μ•„λ‹™λ‹ˆλ‹€.

REST의 μƒνƒœ μ½”λ“œλŠ” GraphQL의 μƒνƒœ μ½”λ“œμ™€ 맀우 λ‹€λ₯΄κ³  더 λ‹€μ–‘ν•˜κ³  μ€‘μš”ν•˜κΈ° λ•Œλ¬Έμ—μ΄ μ‚¬μš© 사둀λ₯Ό 처리 ν•  κ°€μΉ˜κ°€ μžˆλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€.

λ‚˜λŠ” λ˜ν•œμ΄ λ¬Έμ œμ— λΆ™μ–΄ μžˆμŠ΅λ‹ˆλ‹€. null λŒ€μ‹  전체 404 응닡을 λ°˜ν™˜ν•˜μ§€ μ•ŠλŠ” μ΄μœ κ°€ μžˆμŠ΅λ‹ˆκΉŒ?

λ‚˜λŠ” 아직 404λ₯Ό 였λ₯˜λ‘œ μ·¨κΈ‰ν•˜μ§€ μ•ŠλŠ” κ²½μš°κ°€ λ‚˜μ—κ²Œ λ„μ›€μ΄λ˜μ§€ μ•Šμ€ 경우λ₯Ό κ²ͺ지 μ•Šμ•˜μœΌλ©° κ·Έ 사싀을 ν•΄κ²°ν•  쒋은 방법을 계속 찾으렀고 λ…Έλ ₯ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

404 Not found κ°€ μ„±κ³΅μ μœΌλ‘œ 빈 μ„ΈνŠΈλ₯Ό μƒμ„±ν•˜λŠ” 데이터 쿼리λ₯Ό μ„€λͺ… ν•  수 μžˆλ‹€λŠ” μƒκ°μž…λ‹ˆκΉŒ?

λ˜ν•œ μ„œλΉ„μŠ€ μ†Œμœ μžκ°€ 이전에 μ‚¬μš© κ°€λŠ₯ν•œ μ—”λ“œ ν¬μΈνŠΈκ°€ 사라 μ‘Œλ‹€λŠ” μ€‘μš”ν•œ 변경을 μˆ˜ν–‰ν–ˆμŒμ„ μ•Œλ¦΄ 수 μžˆμŠ΅λ‹ˆλ‹€.

첫 번째 κ²½μš°λŠ” λΉ„μ–΄ μžˆκ±°λ‚˜ null μ‘μš© ν”„λ‘œκ·Έλž¨ 엔터티와 ν•¨κ»˜ 200 OK둜 더 잘 처리 ν•  수 β€‹β€‹μžˆλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€. 적어도이 두 κ²½μš°λŠ” 맀우 λ‹€λ₯΄κΈ° λ•Œλ¬Έμ— ν΄λΌμ΄μ–ΈνŠΈκ°€ μ‰½κ²Œ 식별 ν•  수 μžˆμ–΄μ•Όν•©λ‹ˆλ‹€.

예, μ˜λ„μ μœΌλ‘œ 빈 데이터 μ„ΈνŠΈκ°€ 생각보닀 μ’€ 더 μΌλ°˜μ μž…λ‹ˆκΉŒ? (적어도 λ†€λžμŠ΅λ‹ˆλ‹€!) μ‚¬μš©μžκ°€ μ—¬λŸ¬ λ„€νŠΈμ›Œν¬ 및 기타 ν˜ΈμΆœμ„ 단일 메타 호좜둜 μˆ˜μ§‘ν•˜λŠ” κ²½μš°κ°€ 많기 λ•Œλ¬Έμ— 기본적으둜 404μ—μ„œ 였λ₯˜λ₯Ό λ°œμƒμ‹œν‚€λŠ” 것은 큰 영ν–₯을 λ―ΈμΉ©λ‹ˆλ‹€. 404 ν•˜λ‚˜κ°€ λ³‘λ ¬λ‘œ λ°œμƒν•˜λŠ” λ‹€λ₯Έ λͺ¨λ“  데이터 κ°€μ Έ 였기λ₯Ό μ’…λ£Œν•˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€. μ‹€ν–‰ 된 GraphQL 쿼리 λ‹Ή REST 호좜이 ν•˜λ‚˜λ§Œ 있으면 λ™μ˜ν•©λ‹ˆλ‹€. 곡식 REST 의미 체계가 주어지면 였λ₯˜κ°€ λ°œμƒν•΄μ•Όν•˜λŠ” 것 κ°™μŠ΅λ‹ˆλ‹€.

μ‹€μ œλ‘œλŠ” 기본적으둜 였λ₯˜λ₯Ό λ˜μ§€μ§€ μ•ŠλŠ” 것이 더 λ‚˜μ€ 것 κ°™μ•˜μŠ΅λ‹ˆλ‹€! μ‚¬μš©μž 지정 κ°€μ Έ 였기λ₯Ό μΆ”κ°€ν•˜μ—¬μ΄ 문제λ₯Ό ν•΄κ²°ν•  수 있으며 "μˆ˜λ½ν•˜λŠ” 것에 λŒ€ν•΄ 자유 λ‘œμ›Œ μ§€μ‹­μ‹œμ˜€"λΌλŠ” λŠλ‚Œμ΄ λ“€κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€. 이 선택은 Apollo-link-rest의 μ£Όμš” λͺ©μ  쀑 ν•˜λ‚˜μ™€ μΌμΉ˜ν•˜λŠ” κ²ƒμ²˜λŸΌ λŠκ»΄μ‘ŒμŠ΅λ‹ˆλ‹€. λ°±μ—”λ“œλ₯Ό λ°˜λ“œμ‹œ μ œμ–΄ ν•  ν•„μš”λŠ”μ—†λŠ” μ‚¬μš©μžλ₯Ό μ§€μ›ν•˜κ³  "λŒ€λΆ€λΆ„ νœ΄μ‹"μ„œλ²„ 만 μ‘΄μž¬ν•˜λ―€λ‘œ 의미 μœ„λ°˜μ΄ μΌλ°˜μ μž…λ‹ˆλ‹€. .

@williamboman customFetch 맀개 λ³€μˆ˜λ₯Ό μ‚¬μš©ν•˜λŠ” 경우 Apollo-link-restλ₯Ό 404s에 λ˜μ§€λ„λ‘ κ΅¬μ„±ν•˜λŠ” 것은 비ꡐ적 κ°„λ‹¨ν•©λ‹ˆλ‹€. μ €λŠ” 제 컴퓨터에 μ—†μŠ΅λ‹ˆλ‹€. 도움이 ν•„μš”ν•˜λ©΄ μ•Œλ €μ£Όμ„Έμš”!

μ•ˆλ…•ν•˜μ„Έμš” @fbartho 404 였λ₯˜λ₯Ό μ²˜λ¦¬ν•˜κΈ° μœ„ν•΄ customFetchλ₯Ό μž‘μ„±ν•˜λŠ” 데 도움이 될 수 μžˆμŠ΅λ‹ˆκΉŒ? 그것에 λŒ€ν•œ λͺ‡ 가지 μ˜ˆκ°€ μžˆμŠ΅λ‹ˆκΉŒ?

@anasnain :

μžλ°” μŠ€ν¬λ¦½νŠΈμ—μ„œλŠ” λ‹€μŒκ³Ό 같이 보일 κ²ƒμž…λ‹ˆλ‹€.

export async function customFetch(requestInfo, init) {
  const response = await fetch(requestInfo, init);
  if (response.status === 404) {
    throw new Error("404 File Not Found"); // Customize this however you like!
  }
  return response;
}

(TypeScriptμ—μ„œλŠ” μ’€ 더 μž₯ν™©ν•©λ‹ˆλ‹€)

@fbartho λΉ λ₯Έ 응닡에 κ°μ‚¬λ“œλ¦½λ‹ˆλ‹€. 이제 404λ₯Ό μž‘μ„ 수 μžˆμŠ΅λ‹ˆλ‹€.
κ·ΈλŸ¬λ‚˜ apollo-link-error의 networkErrorκ°€ μ‚¬μš©μž 지정 κ°€μ Έ 였기 내에 μž‘μ„±λœ 였λ₯˜ (μƒˆ 였λ₯˜ ( "404 νŒŒμΌμ„ 찾을 수 μ—†μŒ") λ°œμƒ)λ₯Ό ν¬μ°©ν•˜λ„λ‘ν•˜λ €λ©΄ μ–΄λ–»κ²Œν•΄μ•Όν•©λ‹ˆκΉŒ?

μ•„, μ•ˆνƒ€κΉκ²Œλ„ ApolloClient λ‚΄λΆ€ κ·œμΉ™ (링크 μž‘λ™ 방식에 λŒ€ν•œ)으둜 인해 graphQLErrors λ°°μ—΄ ( networkError 속성이 μ•„λ‹˜)에 첨뢀 된 κ²ƒμ²˜λŸΌ 보일 κ²ƒμž…λ‹ˆλ‹€.

이것이 κ³ μΉ  μˆ˜λŠ” μžˆμ§€λ§Œ 방법을 λͺ¨λ₯΄κ² μŠ΅λ‹ˆλ‹€. -HTTPLinkλŠ”μ΄λ₯Ό μˆ˜ν–‰ν•˜λŠ” 방법을 μ•Œμ•„μ•Όν•˜λ©° 쑰사 ν•  κΈ°νšŒκ°€ μ—†μ—ˆμŠ΅λ‹ˆλ‹€. (μž‘μ—…) μ½”λ“œλ² μ΄μŠ€μ—λŠ” 쀑첩 된 였λ₯˜μ˜ 압좕을 ν‘ΈλŠ” λ„μš°λ―Έ λ©”μ„œλ“œκ°€ μžˆμŠ΅λ‹ˆλ‹€. (이것은 μš°λ¦¬μ—κ²Œ apollo-link-state μ—μ„œ λ°œμƒν•œ 였λ₯˜μ—λ„ ν•„μš”ν•˜λ―€λ‘œ μ‹€μ œλ‘œ μš°μ„  μˆœμœ„κ°€ μ•„λ‹ˆ μ—ˆμŠ΅λ‹ˆλ‹€)

@fbartho 이 κ²½μš°μ—λŠ” 였λ₯˜κ°€ μ „ν˜€ λ°œμƒν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 데이터가 null을 λ°˜ν™˜ν•©λ‹ˆλ‹€. 였λ₯˜κ°€ λ°œμƒν•˜λ©΄ 데이터 λŒ€μ‹  였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. 이것을 κ΅¬ν˜„ν•˜λŠ” 방법을 λͺ¨λ₯΄κ² μŠ΅λ‹ˆλ‹€.

@anasnain μ„€μ • ν•œ 지 λ„ˆλ¬΄ 였래

λ˜ν•œ apollo-link-error μΈμŠ€ν„΄μŠ€λ₯Ό κ΅¬μ„±ν•΄μ•Όν•©λ‹ˆλ‹€. 이것이 λ‚΄ κ΅¬μ„±μž…λ‹ˆλ‹€.

const attachGQLErrorsToNetworkError = (
    graphQLErrors: readonly GraphQLError[],
    networkError: Error,
): void => {
    (networkError as any).tr_graphQLErrors = graphQLErrors;
    return;
};

/** Set behavior when errors occur and handle our own TR errors */
export const apolloErrorLink = onError((errorResponse: ErrorResponse) => {
    const {
        graphQLErrors = [],
        networkError,
    }: {
        graphQLErrors?: readonly GraphQLError[];
        networkError?: Error;
    } = errorResponse;

    /**
     * Our error parsing (function recursiveGQLErrorsFromNetworkError) rely
     * on attaching the following graphql errors.
     * Let's make sure to not attach anything `wrong` (ie: null, empty, ...)
     */
    const hasGraphQLErrors: boolean =
        graphQLErrors != null &&
        Array.isArray(graphQLErrors) &&
        graphQLErrors.length > 0;

    if (networkError && hasGraphQLErrors) {
        /*
         * graphQLErrors are not being passed through the chain of links,
         * but network errors are attaching the graphQLErrors to networkError
         * to be able to access them in a component
         */
        attachGQLErrorsToNetworkError(graphQLErrors, networkError);
    }
});

μΆ”κ°€ κ²€ν†  ν›„ : κ·€ν•˜κ°€ μ„€λͺ…ν•˜λŠ” 상황을 μ™„μ „νžˆ μ΄ν•΄ν•˜κ³  μžˆλŠ”μ§€ 잘 λͺ¨λ₯΄κ² μŠ΅λ‹ˆλ‹€.

μ»΄ν¬λ„ŒνŠΈ / λ°˜μ‘ μ½”λ“œμ—μ„œ "404 였λ₯˜"λ₯Ό 읽을 μˆ˜μ—†λŠ” λ¬Έμ œμž…λ‹ˆκΉŒ?

λΏ‘λΏ‘
μ‹œλ‚˜λ¦¬μ˜€ : λ‚˜λ¨Έμ§€ APIquery μ•„λž˜μ—μ„œ μ‹€ν–‰ 쀑이며 λ‹€λ₯Έ 4xx 였λ₯˜ 및 5xx 였λ₯˜μ™€ λ§ˆμ°¬κ°€μ§€λ‘œ 404 였λ₯˜ μ½”λ“œλ₯Ό λ°˜ν™˜ν•˜λŠ” 경우 였λ₯˜ 개체λ₯Ό κ°€μ Έμ™€μ•Όν•©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜μ΄ 경우 였λ₯˜λŠ” μ •μ˜λ˜μ§€ μ•Šκ³  λ°μ΄ν„°λŠ” nullμž…λ‹ˆλ‹€.
const {loading, error, data} = useQuery (CLIENT_API_QUERY);

이것은 Apollo ν΄λΌμ΄μ–ΈνŠΈ μΈμŠ€ν„΄μŠ€μž…λ‹ˆλ‹€.

async function customFetch(requestInfo, init) {
    const response = await fetch(requestInfo, init);
    if (response.status === 404) {
        response.json().then((errorResponse) => {
          throw new Error(errorResponse);
        });
    }
    return response;
  }

const errorLink = onError(({ operation, response, graphQLErrors, networkError }) => {
    if (graphQLErrors) {
      graphQLErrors.forEach(({ message, path }) =>
           console.log(`[GraphQL error]: Message: ${message}, Path: ${path}`),
      );
    }
    if (networkError) {
        console.log(`[Network error ${operation.operationName}]: ${networkError.message}`);
    }
  });

const restLink = new RestLink({
    uri: 'https://run.mocky.io/v3/df72bacd-39cb-476d-bfda-06d7f5e9d77d',
    customFetch: (requestInfo, init) => customFetch(requestInfo, init)
});

const apolloClient = new ApolloClient({
    link: ApolloLink.from([errorLink, restLink]),
    new InMemoryCache(),
  });
export default apolloClient;

@anasnain- μ œκ°€ μ•„λŠ” ν•œ κ°€μ§€λŠ” new Error ν•  λ•Œ μž„μ˜μ˜ 객체λ₯Ό 전달할 수 μ—†λ‹€κ³  μƒκ°ν•œλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€.

λ˜ν•œ awaitκ°€ λˆ„λ½λ˜μ—ˆλ‹€κ³  μƒκ°ν•˜λ―€λ‘œ throw 문이 restLink customFetch 호좜 μ™ΈλΆ€μ—μ„œ λ°œμƒν•©λ‹ˆλ‹€!

const err = new Error("404 Error");
try {
  err.responseJson = await response.json(); // This await crucial to get the error in the right spot!
} catch (parsingError) {
  // figure out what you want to do with parsingError?
}
throw err;
이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰