μλ νμΈμ, μμ² λ³Έλ¬Έμ λ€μκ³Ό κ°μ΄ μ¬μ©νλ λ‘κ·ΈμΈ 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,
}
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;
κ°μ₯ μ μ©ν λκΈ
λλ λνμ΄ λ¬Έμ μ λΆμ΄ μμ΅λλ€. null λμ μ 체 404 μλ΅μ λ°ννμ§ μλ μ΄μ κ° μμ΅λκΉ?