<p>рдЕрдкреЛрд▓реЛ-рд▓рд┐рдВрдХ-рддреНрд░реБрдЯрд┐ - рдХреИрд╕реЗ async рдЯреЛрдХрди рд░реАрдлреНрд░реЗрд╢ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП?</p>

рдХреЛ рдирд┐рд░реНрдорд┐рдд 15 рдЬреВрди 2018  ┬╖  31рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: apollographql/apollo-link

рдЕрдВрдХ рд▓реЗрдмрд▓

  • [] рд╣реИ-рдкреНрд░рдЬрдирди
  • [ ] рд╡рд┐рд╢реЗрд╖рддрд╛
  • [рдПрдХреНрд╕] рджрд╕реНрддрд╛рд╡реЗрдЬрд╝
  • [ ] рдмреНрд▓реЙрдХ рдХрд░рдирд╛ <----- рдорд╛рдл рдХрд░рдирд╛, рдмреНрд▓реЙрдХ рдирд╣реАрдВ рдХрд░рдирд╛
  • [] рдЕрдЪреНрдЫрд╛ рдкрд╣рд▓рд╛ рдЕрдВрдХ

рдкреНрд░рд╢реНрди

рдореИрдВ рдЬрд┐рд╕ рд╕рдЯреАрдХ рдкрд░рд┐рджреГрд╢реНрдп рдХреЛ рдкреВрд░рд╛ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдЙрд╕рдХрд╛ рдЙрд▓реНрд▓реЗрдЦ рдпрд╣рд╛рдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ:

https://github.com/apolographql/apollo-link/tree/master/packages/apollo-link-error#retrying -failed-requests

            operation.setContext({
              headers: {
                ...oldHeaders,
                authorization: getNewToken(),
              },
            });

рд╣рд╛рд▓рд╛рдВрдХрд┐, рдпрджрд┐ рдПрдХ рдЯреЛрдХрди рдХреА рд╕рдордп рд╕реАрдорд╛ рд╕рдорд╛рдкреНрдд рд╣реЛ рдЧрдИ рд╣реИ, рддреЛ рдПрдХ async resfreshToken рдХреЛ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдФрд░ "рдкреНрд░рддреАрдХреНрд╖рд┐рдд" рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ getNewToken рдПрдХ рд╡реИрдз рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдЯреЛрдХрди рд╡рд╛рдкрд╕ рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИред

рдореЗрд░рд╛ рд╕рд╡рд╛рд▓ рд╣реИ, рдХреИрд╕реЗ рдПрдХ async resfreshToken рдХреЙрд▓ рдХрд░рдирд╛ рд╣реИред рдореИрдВрдиреЗ await refreshToken() (рдЬреЛ рдкреВрд░рд╛ рд╣реЛрдиреЗ рдкрд░ рдПрдХ рд╡рд╛рджрд╛ рд╣рд▓ рдХрд░рддрд╛ рд╣реИ) рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рд╣реИ, рд▓реЗрдХрд┐рди рдореЗрд░реЗ рд▓реЙрдЧ рдХрд┐рдП рдЧрдП рд╕реНрдЯреИрдХ рдирд┐рд╢рд╛рди рд╕реЗ рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдЖрд░рдПрдХреНрд╕рдЬреЗрдПрд╕ рдХреЗ рд╕рд╛рде рдХрд╛рдлреА рдЧрдбрд╝рдмрдбрд╝ рд╣реИред рдореИрдВ рдПрдХ рдЖрд░рдПрдХреНрд╕рдЬреЗрдПрд╕ рдПрди 00 рдмреА рд╣реВрдВ, рдХрд┐рд╕реА рднреА рдорджрдж рдХреА рдмрд╣реБрдд рд╕рд░рд╛рд╣рдирд╛ рдХреА рдЬрд╛рддреА рд╣реИ!

рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА

рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ onError рдХреЙрд▓рдмреИрдХ aync рдлрд╝рдВрдХреНрд╢рди рдпрд╛ Promise рд░рд┐рдЯрд░реНрди рд╕реНрд╡реАрдХрд╛рд░ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рджреЗрдЦреЗрдВ рдХреЛрдб https://github.com/apollographql/apollo-link/blob/59abe7064004b600c848ee7c7e4a97acf5d230c2/packages/apollo-link-error/src/index.ts#L60 -L74

рдпрд╣ рд╕рдорд╕реНрдпрд╛ рдкрд╣рд▓реЗ рдмрддрд╛рдИ рдЧрдИ рдереА: #190

рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдмреЗрд╣рддрд░ рдХрд╛рдо рдХрд░реЗрдЧрд╛ рдпрджрд┐ apollo-link-error Promise рдирд┐рдкрдЯ рд╕рдХрддрд╛ рд╣реИ, рдЬреИрд╕рд╛ рдХрд┐ apollo-link-retry рдпрд╣рд╛рдВ рдХрд░рддреЗ рд╣реИрдВ: #436

рд╕рднреА 31 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

рдпрджрд┐ рдЖрдк рд╡рд╛рджреЛрдВ рд╕реЗ рдЕрдзрд┐рдХ рдкрд░рд┐рдЪрд┐рдд рд╣реИрдВ, рддреЛ рдЖрдк fromPromise рд╕рд╣рд╛рдпрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ

import { fromPromise } from 'apollo-link';

return fromPromise(refreshToken().then(token => {
  operation.setContext({
    headers: {
      ...oldHeaders,
      authorization: token,
    },
  });
  return forward(operation);
}))

@thymikee рдиреЗ рдЖрдкрдХреЗ рд╕рдорд╛рдзрд╛рди рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рдФрд░ рдпрд╣ рдирд┐рдореНрди рд╕рдВрджреЗрд╢ рдХреЗ рд╕рд╛рде рд╡рд┐рдлрд▓ рд╣реЛ рдЧрдпрд╛:

Uncaught (in promise) Error: Network error: Error writing result to store for query:
 query UserProfile($id: ID!) {
  UserProfile(id: $id) {
    id
    email
    first_name
    last_name
    activated
    created_at
    updated_at
    last_active
    roles {
      id
      name
      __typename
    }
    permissions {
      name
      value
      __typename
    }
    profile {
      address
      secondary_email
      phone {
        id
        number
        type {
          id
          name
          __typename
        }
        __typename
      }
      __typename
    }
    __typename
  }
}
Cannot read property 'UserProfile' of undefined
    at new ApolloError (ApolloError.js:43)
    at QueryManager.js:327
    at QueryManager.js:759
    at Array.forEach (<anonymous>)
    at QueryManager.js:758
    at Map.forEach (<anonymous>)
    at QueryManager.webpackJsonp../node_modules/apollo-client/core/QueryManager.js.QueryManager.broadcastQueries (QueryManager.js:751)
    at QueryManager.js:254

рдЖрдЧреЗ рдХреЗ рдирд┐рд░реАрдХреНрд╖рдг рд╕реЗ рдкрддрд╛ рдЪрд▓рддрд╛ рд╣реИ рдХрд┐ рдЙрдкрд░реЛрдХреНрдд рдХреЛрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп рдЕрдкреЛрд▓реЛ рд▓рд┐рдВрдХ рдХреЗ onError рдХреЛ рджреЛ рдмрд╛рд░ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ refresh token рдХреЛ рдПрдХ рдмрд╛рд░ рдЪрд▓рд╛рдиреЗ рдХреЗ рд╡рд╛рджреЗ рдХреЛ рд╕реАрдорд┐рдд рдХрд░рдиреЗ рд╕реЗ рднреА рддреНрд░реБрдЯрд┐ рдареАрдХ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИред

рдХреНрдпрд╛ рд╣реЛрддрд╛ рд╣реИ:

1) рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдХреНрд╡реЗрд░реА рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХреА рдЬрд╛рддреА рд╣реИ
2) рдпрд╣ рд╡рд┐рдлрд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдЕрдкреЛрд▓реЛ рдХрд╛ рд▓рд┐рдВрдХ onError рдЪрд▓рд╛рддрд╛ рд╣реИ
3) ?? рдпрд╣ рдЕрдкреЛрд▓реЛ рдХрд╛ рд▓рд┐рдВрдХ onError рдлрд┐рд░ рд╕реЗ рдЪрд▓рд╛рддрд╛ рд╣реИ
4) рдЯреЛрдХрди рдХреЛ рд░реАрдлреНрд░реЗрд╢ рдХрд░рдиреЗ рдХрд╛ рд╡рд╛рджрд╛, onError рдирд┐рд╖реНрдкрд╛рджрди рд╕рдорд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИ рдФрд░ рд╣рд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред
5) (рд╡рд╛рджрд╛ рд╕рдлрд▓ рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рджреВрд╕рд░реА рдмрд╛рд░ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдХреНрд╡реЗрд░реА рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдирд╣реАрдВ рдХреА рдЬрд╛рддреА рд╣реИ)
6) рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдХреНрд╡реЗрд░реА рд░рд┐рдЯрд░реНрди рдкрд░рд┐рдгрд╛рдо рдЬрд┐рд╕рдореЗрдВ data рдЕрдкрд░рд┐рднрд╛рд╖рд┐рдд рд╣реИ

рдпрд╣рд╛рдВ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдХрд┐рд╕реА рдХреЛ рдЗрд╕рдХрд╛ рд╕рдорд╛рдзрд╛рди рдорд┐рд▓ рдЬрд╛рдПрдЧрд╛, рдЕрдиреНрдпрдерд╛ рд╣рдореЗрдВ рд╕рдорд╛рдкреНрддрд┐ рдкрд░ рдЙрдиреНрд╣реЗрдВ рд░реАрдлреНрд░реЗрд╢ рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп рд▓рдВрдмреЗ рд╕рдордп рддрдХ рдЪрд▓рдиреЗ рд╡рд╛рд▓реЗ рдЯреЛрдХрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред

рдпрджрд┐ рдЖрдкрдХрд╛ рдЯреЛрдХрди рдкреБрдирд░реНрдкреНрд░рд╛рдкреНрддрд┐ рддрд░реНрдХ рд╕рд╣реА рд╣реИ, рддреЛ onError рдХреЛ рдХреЗрд╡рд▓ рдПрдХ рдмрд╛рд░ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЖрдкрдХреЛ рдЕрдкрдиреА рдЯреЛрдХрди рдХреНрд╡реЗрд░реА рдореЗрдВ рд╕рдорд╕реНрдпрд╛ рд╣реИ

@thymikee рдиреЗ рдПрдХ рдбрдореА рд╡рд╛рджреЗ рдХреЗ рд╕рд╛рде async рдЕрдиреБрд░реЛрдз рдХреЛ рдмрдВрдж рдХрд░ рджрд┐рдпрд╛ред рдЙрдкрд░реЛрдХреНрдд рд╕рдВрджреЗрд╢ рдХреЗ рд╕рд╛рде рдЕрднреА рднреА рд╡рд┐рдлрд▓ рд░рд╣рддрд╛ рд╣реИ рдФрд░ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдХреНрд╡реЗрд░реА рджреЛ рдмрд╛рд░ рдирд╣реАрдВ рдЪрд▓рддреА рд╣реИред рд╕рднреА рдЯреЛрдХрди рдкрд░реАрдХреНрд╖рдг рдХреЗ рд╕рдордп рдорд╛рдиреНрдп рд╣реИрдВред

рдХреЛрдб:

return fromPromise(
    new Promise((resolve) => {
        let headers = {
            //readd old headers
            ...operation.getContext().headers,
            //switch out old access token for new one
            authorization: `Bearer  mynewaccesstoken`,
        };
        operation.setContext({
            headers
        });
        return resolve(forward(operation));
    })
)

рд╕рдВрдкрд╛рджрд┐рдд рдХрд░реЗрдВ: fromPromise рд╣рдЯрд╛ рджрд┐рдпрд╛ рдФрд░ рдпрд╣ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдХрд┐рд╕реА рддрд░рд╣, рд▓рд┐рдВрдХ рд╕реНрдЯреИрдХ рдХреА рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдкрд░рд┐рдгрд╛рдо рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рд╕рдорд╛рдкреНрдд рд╣реЛ рдЬрд╛рддреА рд╣реИ рдЗрд╕рд▓рд┐рдП forward(operation) рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред

fromPromise рдХреЛрдб рдФрд░ рдкреНрд░рддрд┐рдмрджреНрдз #172 рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, fromPromise рдЙрдкрдпреЛрдЧ рдХреЗрд╡рд▓ рдЕрдкреЛрд▓реЛ рд▓рд┐рдВрдХ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рд╕рд╛рде рдЕрдиреБрдорд╛рди рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рдПрдХ рд╕рдорд╛рдзрд╛рди рдкрд░ рд╢реЛрдз рдХрд░рдиреЗ рдкрд░, рдореИрдВ рдЕрдВрдд рдореЗрдВ рдЗрд╕ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдкрд░ рдареЛрдХрд░ рдЦрд╛рдИ: рдЕрдкреЛрд▓реЛ-рд▓рд┐рдВрдХ-рдЯреЛрдХрди-рд░реАрдлреНрд░реЗрд╢

рдореЗрд░рд╛ рдЕрдкреЛрд▓реЛ рд▓рд┐рдВрдХ рд╕реНрдЯреИрдХ рдЕрдм рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╣реИ:

[
   refreshTokenLink,
   requestLink,
   batchHttpLink
]

refreshTokenLink рдХреЛ рд╣рдореЗрд╢рд╛ рдЧреНрд░рд╛рдлрд╝рд┐рдХрд▓ рдПрдВрдбрдкреЙрдЗрдВрдЯ рдкрд░ рдХрд┐рд╕реА рднреА рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдПрдХреНрд╕реЗрд╕ рдЯреЛрдХрди рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдПрдХ рдЖрдХрд░реНрд╖рдг рдХреА рддрд░рд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред

рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, рдпрд╣ рдорд╛рдирддрд╛ рд╣реИ рдХрд┐ рдЧреНрд░рд╛рдлрд╝рд┐рдХрд▓ рдПрдВрдбрдкреЙрдЗрдВрдЯ рдкрд░ рдХреЙрд▓ рд╣рдореЗрд╢рд╛ рдкреНрд░рдорд╛рдгрд┐рдд рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП (рдЬреЛ рдХрд┐ рдореЗрд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ рд╣реИ)ред

рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ onError рдХреЙрд▓рдмреИрдХ aync рдлрд╝рдВрдХреНрд╢рди рдпрд╛ Promise рд░рд┐рдЯрд░реНрди рд╕реНрд╡реАрдХрд╛рд░ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рджреЗрдЦреЗрдВ рдХреЛрдб https://github.com/apollographql/apollo-link/blob/59abe7064004b600c848ee7c7e4a97acf5d230c2/packages/apollo-link-error/src/index.ts#L60 -L74

рдпрд╣ рд╕рдорд╕реНрдпрд╛ рдкрд╣рд▓реЗ рдмрддрд╛рдИ рдЧрдИ рдереА: #190

рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдмреЗрд╣рддрд░ рдХрд╛рдо рдХрд░реЗрдЧрд╛ рдпрджрд┐ apollo-link-error Promise рдирд┐рдкрдЯ рд╕рдХрддрд╛ рд╣реИ, рдЬреИрд╕рд╛ рдХрд┐ apollo-link-retry рдпрд╣рд╛рдВ рдХрд░рддреЗ рд╣реИрдВ: #436

рдПрдХ рд╣реА рд╕рдорд╕реНрдпрд╛ рд╣реЛрдиреЗ рдкрд░, рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдореВрд▓ рдХреЗ рд╕рд╛рде рдЕрдкреЛрд▓реЛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдореБрдЭреЗ AsyncStorage onError рд╕реЗ рдХреБрдЫ рдЯреЛрдХрди рдирд┐рдХрд╛рд▓рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЗрд╕реЗ рдПрдХ async рдлрд╝рдВрдХреНрд╢рди рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП

рдЗрд╕ рд╕рдорд╛рдзрд╛рди рдиреЗ рдореЗрд░реЗ рд▓рд┐рдП рдХрд╛рдо рдХрд┐рдпрд╛: https://stackoverflow.com/a/51321068/60223

рдореИрдВрдиреЗ рдЗрд╕реЗ рдПрдХ рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдмрдирд╛рдХрд░ рд╣рд▓ рдХрд┐рдпрд╛ promiseToObservable.js :

import { Observable } from 'apollo-link';

export default promise =>
  new Observable((subscriber) => {
    promise.then(
      (value) => {
        if (subscriber.closed) return;
        subscriber.next(value);
        subscriber.complete();
      },
      err => subscriber.error(err)
    );
    return subscriber; // this line can removed, as per next comment
  });

рдФрд░ рдлрд┐рд░

import { onError } from 'apollo-link-error';
import promiseToObservable from './promiseToObservable';

export default (refreshToken: Function) =>
  onError(({
    forward,
    graphQLErrors,
    networkError = {},
    operation,
    // response,
  }) => {
    if (networkError.message === 'UNAUTHORIZED') { // or whatever you want to check
      // note: await refreshToken, then call its link middleware again!
      return promiseToObservable(refreshToken()).flatMap(() => forward(operation));
    }
  });

@crazy4groovy рдЖрдкрдХреЗ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж, рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдорджрдж рдХрд░рддрд╛ рд╣реИред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдЗрд╕рдХреЗ рд╕рд╛рде рдПрдХ рдЫреЛрдЯреА рд╕реА рд╕рдорд╕реНрдпрд╛ рд╣реИ: subscriber Observable рдЯрд╛рдЗрдкрд┐рдВрдЧ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдЕрдорд╛рдиреНрдп рд╡рд╛рдкрд╕реА рдореВрд▓реНрдп рд╣реИ: рдпрд╣ ZenObservable.SubscriptionObserver рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП:

export declare type Subscriber<T> = ZenObservable.Subscriber<T>;

export declare const Observable: {
    new <T>(subscriber: Subscriber<T>): Observable<T>;
};

export declare namespace ZenObservable {
    interface SubscriptionObserver<T> {
        closed: boolean;
        next(value: T): void;
        error(errorValue: any): void;
        complete(): void;
    }

    type Subscriber<T> = (observer: SubscriptionObserver<T>) => void | (() => void) | Subscription;
}

рдпрд╛рдиреА рдЗрд╕рдХреЗ рдмрдЬрд╛рдп рдЕрдкрд░рд┐рднрд╛рд╖рд┐рдд рд▓реМрдЯрдирд╛ рд╕реБрд░рдХреНрд╖рд┐рдд рд╣реИред рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХреА рд░реАрдбрдореЗ рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдЗрд╕рдХрд╛ рдЙрд▓реНрд▓реЗрдЦ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред

рдпреВрдкреАрдбреА: рдореИрдВрдиреЗ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдПрдХ рдкреАрдЖрд░ рдЬреЛрдбрд╝рд╛: https://github.com/apollographql/apolo-link/pull/825

рдпрд╣ рд╕рдорд╕реНрдпрд╛ Google рдкрд░ рдЙрдЪреНрдЪ рд░реИрдВрдХ рдкрд░ рд╣реИ рдЗрд╕рд▓рд┐рдП рдореИрдВ рдХреБрдЫ рд▓реЛрдЧреЛрдВ рдХреА рд╕рд╣рд╛рдпрддрд╛ рдХреЗ рд▓рд┐рдП рдЕрдкрдирд╛ рд╕рдорд╛рдзрд╛рди рдпрд╣рд╛рдВ рд╕рд╛рдЭрд╛ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ: https://gist.github.com/alfonmga/9602085094651c03cd2e270da9b2e3f7

рдореИрдВрдиреЗ рдЖрдкрдХреЗ рд╕рдорд╛рдзрд╛рди рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рд╣реИ рд▓реЗрдХрд┐рди рдореБрдЭреЗ рдирдИ рд╕рдорд╕реНрдпрд╛ рдХрд╛ рд╕рд╛рдордирд╛ рдХрд░рдирд╛ рдкрдбрд╝ рд░рд╣рд╛ рд╣реИ:

Argument of type '(this: Observable<{}>, observer: Subscriber<{}>) => Observable<{}> | Promise<{}>' is not assignable to parameter of type '(this: Observable<{}>, subscriber: Subscriber<{}>) => TeardownLogic'.
  Type 'Observable<{}> | Promise<{}>' is not assignable to type 'TeardownLogic'.
    Type 'Observable<{}>' is not assignable to type 'TeardownLogic'.
      Property 'unsubscribe' is missing in type 'Observable<{}>' but required in type 'Unsubscribable'

рддрд╛рдЬрд╝рд╛ рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рдЖрдк рд▓реЛрдЧ рдирдП рдкреНрд░рдорд╛рдгреАрдХрд░рдг рдЯреЛрдХрди рдХреЛ рдХреИрд╕реЗ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░ рд░рд╣реЗ рд╣реИрдВ?

рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рдореИрдВ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдЕрдиреБрд░реЛрдз рдореЗрдВ рдирдП рд╢реАрд░реНрд╖рд▓реЗрдЦ рд╕реЗрдЯ рдХрд░ рд╕рдХрддрд╛ рд╣реВрдВ, рд╣рд╛рд▓рд╛рдВрдХрд┐ рдореВрд▓ рдкрд╣реБрдВрдЪ рдЯреЛрдХрди (рдЬрд┐рд╕реЗ рдореИрдВ рдХреБрдХреАрдЬрд╝ рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВ) рдЕрдкрдбреЗрдЯ рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИ рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рд╕рд░реНрд╡рд░ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдЕрдиреБрд░реЛрдз рдкреБрд░рд╛рдиреЗ рдПрдХреНрд╕реЗрд╕ рдЯреЛрдХрди (рдФрд░ рдмрд╛рдж рдореЗрдВ) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдЧрд╛ рдлрд┐рд░ рд╕реЗ рддрд╛рдЬрд╝рд╛ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА)ред

рдЬрдм рднреА рдореИрдВ рд░реАрдлреНрд░реЗрд╢ рдХреЗ рджреМрд░рд╛рди рдХреБрдХреАрдЬрд╝ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддрд╛ рд╣реВрдВ рддреЛ рдХрд┐рд╕реА рдХрд╛рд░рдг рд╕реЗ рдореБрдЭреЗ рдирд┐рдореНрди рддреНрд░реБрдЯрд┐ рд╕рдВрджреЗрд╢ рдорд┐рд▓ рд░рд╣рд╛ рд╣реИ (рдореИрдВрдиреЗ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдпрд╣рд╛рдВ рдПрдХ рдирдпрд╛ рдореБрджреНрджрд╛ рдмрдирд╛рдпрд╛ рд╣реИ):

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ServerResponse.setHeader (_http_outgoing.js:470:11)
    at setCookie (/root/SimplyTidyAdmin/node_modules/nookies/dist/index.js:98:17)
    at /root/SimplyTidyAdmin/.next/server/static/CAhshxrRWHVF6Gzbce~pU/pages/_app.js:1273:63
    at process._tickCallback (internal/process/next_tick.js:68:7)

@StupidSexyJake рд╢рд╛рдпрдж рдпрд╣ рдЖрдк рдореЗрдВ рдорджрдж рдорд┐рд▓реЗрдЧреА https://stackoverflow.com/questions/55356736/change-apollo-client-options-for-jwt-token рдореИрдВ рдХреИрд╕реЗ рдЯреЛрдХрди рдЕрджреНрдпрддрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░ рдПрдХ рд╕рдорд╛рди рдореБрджреНрджреЗ рдореЗрдВ рдЪрд▓рд╛рдиреЗ

рдирдорд╕реНрддреЗ, рдзрдиреНрдпрд╡рд╛рдж @crazy4groovyред рдореИрдВрдиреЗ рдЖрдкрдХреЗ рд╕рдорд╛рдзрд╛рди рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рд╣реИ рд▓реЗрдХрд┐рди рдореБрдЭреЗ рдЕрднреА рднреА рд╕рдорд╕реНрдпрд╛ рд╣реЛ рд░рд╣реА рд╣реИ, рдХрд┐ рдорд┐рдбрд▓рд╡реЗрдпрд░ рдЬрд╣рд╛рдВ рдореИрдВ рдЧреНрд░рд╛рдлрд╝рд┐рдХрд▓ рдЕрдиреБрд░реЛрдз рдореЗрдВ рдЯреЛрдХрди рдЬреЛрдбрд╝рддрд╛ рд╣реВрдВ, рдЕрдиреБрд░реЛрдз рдкрд░ рдирдпрд╛ рдЯреЛрдХрди рд╕реЗрдЯ рд╣реЛрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рд╣реЗрдбрд░ рдореЗрдВ рдЕрднреА рднреА рдЕрдорд╛рдиреНрдп рдЯреЛрдХрди рд╣реИред

рдереЛрдбрд╝реА рдкреГрд╖реНрдарднреВрдорд┐ рдХреА рдЬрд╛рдирдХрд╛рд░реА: рдЬрдм рдЯреЛрдХрди рдЕрдорд╛рдиреНрдп рд╣реЛрддрд╛ рд╣реИ, рддреЛ рд╣рдореЗрдВ рдПрдХ рдиреЗрдЯрд╡рд░реНрдХ рддреНрд░реБрдЯрд┐ рдорд┐рд▓рддреА рд╣реИ, рдФрд░ рдПрдХ рддрд╛рдЬрд╝рд╛ рдЯреЛрдХрди рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ, рд╣рдо рдПрдХ рдирдпрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рдЪреВрдВрдХрд┐ рд░реАрдлреНрд░реЗрд╢ рдЯреЛрдХрди рдЗрдХрдЯреНрдард╛ рд╣реЛрдиреЗ рдФрд░ рд╕реНрдерд╛рдиреАрдп рд╕реНрдЯреЛрд░реЗрдЬ рдкрд░ рд╕реЗрдЯ рд╣реЛрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдорд┐рдбрд▓рд╡реЗрдпрд░ рдХреЛ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдлрд┐рд░ рднреА рдЗрд╕рдореЗрдВ рдЕрдорд╛рдиреНрдп рд╣реИред рд░реАрдлреНрд░реЗрд╢ рдЯреЛрдХрди рд▓реЙрдЬрд┐рдХ рдареАрдХ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рд╣рдореЗрдВ рдЕрдВрдд рдореЗрдВ рдирдпрд╛ рдЯреЛрдХрди рд╕реЗрдЯ рдорд┐рд▓рддрд╛ рд╣реИред рдореИрдВрдиреЗ рдЗрд╕ рдореБрджреНрджреЗ рдХреЛ рдереЛрдбрд╝рд╛ рд╕рд╛ рдбрд┐рдмрдЧ рдХрд┐рдпрд╛ рд╣реИ рдФрд░ рд╕рдордп рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╣реИ:

  • рдорд┐рдбрд▓рд╡реЗрдпрд░: рдЕрдорд╛рдиреНрдп рдЯреЛрдХрди рд╕рдВрд▓рдЧреНрди
  • рдПрдХ рдкреНрд░рд╢реНрди рдХреЗ рд▓рд┐рдП рдЕрдиреБрд░реЛрдз рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ
  • рдиреЗрдЯрд╡рд░реНрдХ рддреНрд░реБрдЯрд┐: 401, рдХреНрдпреЛрдВрдХрд┐ рдЯреЛрдХрди рдЕрдорд╛рдиреНрдп рд╣реИ, рдкрдХрдбрд╝рд╛ рдЧрдпрд╛ рд╣реИ рдФрд░ onError рдЗрд╕реЗ promiseToObservable рддрд░реНрдХ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
  • рдЬрдм рддрдХ рд╣рдо onRefreshToken рд╡рд╛рджреЗ рдореЗрдВ рдЯреЛрдХрди рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рд╕рдорд╛рдкреНрдд рдирд╣реАрдВ рдХрд░ рд▓реЗрддреЗ, рддрдм рддрдХ рдорд┐рдбрд▓рд╡реЗрдпрд░ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдкреБрд░рд╛рдиреЗ рдЯреЛрдХрди рдХреЗ рд╕рд╛рде рджреВрд╕рд░реЗ рд░рди рдореЗрдВ рд╣реИред
  • рдЯреЛрдХрди рд╕реНрдерд╛рдиреАрдп рднрдВрдбрд╛рд░рдг рдореЗрдВ рдЕрджреНрдпрддрди рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ...

рдпрд╣рд╛рдВ рдЗрди рднрд╛рдЧреЛрдВ рдХрд╛ рдПрдХ рд╕реНрдирд┐рдкреЗрдЯ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ (рд░реАрдлреНрд░реЗрд╢рдЯреЛрдХрди рдкрд░ рдЫреЛрдбрд╝рдирд╛ред рдпрд╣ рдПрдХ рдПрд╕рд┐рдВрдХ рдлрд╝рдВрдХреНрд╢рди рд╣реИ, рдПрдХ рд╡рд╛рджрд╛ рд▓реМрдЯрд╛ рд░рд╣рд╛ рд╣реИ):

  const promiseToObservable = (promise: Promise<any>) =>
    new Observable((subscriber: any) => {
      promise.then(
        value => {
          console.log(subscriber);
          if (subscriber.closed) return;
          subscriber.next(value);
          subscriber.complete();
        },
        err => subscriber.error(err)
      );
    });
  const authMiddleware = setContext((operation: GraphQLRequest) => {
    const token = localStorage.getItem('ca_token');
    return {
      headers: {
        ...(token && !isSkipHeader(operation)
          ? { authorization: `Bearer ${token}` }
          : {})
      }
    };
  });
const errorLink = onError(
    ({
      networkError,
      graphQLErrors,
      operation,
      forward
    }: ErrorResponse): any => {
      if (networkError) {
        switch (networkError.statusCode) {
          case 401:
            console.warn('Refreshing token and trying again');
            // await refreshToken, then call its link middleware again
            return promiseToObservable(onRefreshToken(client.mutate)).flatMap(() => forward(operation));
          default:
            // Handle all other errors here. Irrelevant here.
        }
      }
      if (graphQLErrors) {
         // Handle gql errors, irrelevant here.
      }
    }
  );

рдХреНрдпрд╛ рдЖрдк рдХреГрдкрдпрд╛ рдореБрдЭреЗ рдмрддрд╛ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдореИрдВ рдпрд╣рд╛рдБ рдХреНрдпрд╛ рдЦреЛ рд░рд╣рд╛ рд╣реВрдБ? рдЕрдЧреНрд░рд┐рдо рдореЗрдВ рдмрд╣реБрдд рдмрд╣реБрдд рдзрдиреНрдпрд╡рд╛рдж...

рдареАрдХ рд╣реИ, рднреНрд░рдо рдХреЗ рд▓рд┐рдП рдЦреЗрдж рд╣реИ, рдпрджрд┐ рдХреЛрдИ рд╣реЛ ...

рдореБрдЭреЗ рдЙрддреНрддрд░ рдорд┐рд▓ рдЧрдпрд╛ рд╣реИ рдФрд░ рдпрд╣ рдШрдВрдЯреЛрдВ рддрдХ рдЦреЛрдЬрдиреЗ рдФрд░ рдЦреЛрдЬрдиреЗ рдХреЗ рдмрд╛рдж рдпрд╣ рдПрдХ рдмреЗрд╡рдХреВрдлреА рд╣реИ - рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ - рдпрд╣рд╛рдВ рдкреЛрд╕реНрдЯ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж: рдЕрдкреЛрд▓реЛ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЗ рдЖрд░рдВрднреАрдХрд░рдг рдХреЗ рджреМрд░рд╛рди, рдореИрдВрдиреЗ рдорд┐рдбрд▓рд╡реЗрдпрд░ рдФрд░ рддреНрд░реБрдЯрд┐ рд▓рд┐рдВрдХ рдХреЛ рдмрджрд▓ рджрд┐рдпрд╛ рд╣реИред рдЕрдм рдпрд╣ рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реИред рддреНрд░реБрдЯрд┐ рд▓рд┐рдВрдХ рдкрд╣рд▓реЗ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП, рдЬрд╛рд╣рд┐рд░ рд╣реИ ..
рдкреБрд░рд╛рдирд╛: link: from([authMiddleware, errorLink, /* others */])
рдирдпрд╛: link: from([errorLink, authMiddleware, /* others */])

рджреЛрдмрд╛рд░рд╛ рдорд╛рдлреА рдЪрд╛рд╣реВрдВрдЧрд╛..

рд╣реИрд▓реЛ рджреЛрд╕реНрддреЛрдВ,

рдЯреЛрдХрди рд░реАрдлреНрд░реЗрд╢ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореБрдЭреЗ рдСрдирд░рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдореЗрдВ рдирд┐рдореНрди рд╕рдорд╕реНрдпрд╛ рд╣реИред рдиреЗрдХреНрд╕реНрдЯрдЬ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП рдПрд╕рдПрд╕рдЖрд░ рдХреЗ рдЙрджреНрджреЗрд╢реНрдп рдХреЗ рд▓рд┐рдП рдореИрдВ рд╕рднреА рдЧреНрд░рд╛рдлрд╝рд┐рдХрд▓ рдкреНрд░рд╢реНрдиреЛрдВ рд╕реЗ рдбреЗрдЯрд╛ рдПрдХрддреНрд░ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рд▓реЗрдХрд┐рди рдХреНрдпрд╛ рд╣реЛрддрд╛ рд╣реИ рдЬрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП 2 рдкреНрд░рд╢реНрди рд╣реЛрддреЗ рд╣реИрдВ рдФрд░ рдЙрдирдореЗрдВ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдПрдХ рддреНрд░реБрдЯрд┐ рдХреЗ рд╕рд╛рде рд╕рдорд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ jwt рдЯреЛрдХрди рд╕рдорд╛рдкреНрдд рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред рдлрд┐рд░ рдпрд╣ рдСрдирд░рд░ рд╕реЗ рджреЛ рдмрд╛рд░ рдлрд╛рдпрд░ рдХрд░рддрд╛ рд╣реИ рдФрд░ рд╣рдо рд░реАрдлреНрд░реЗрд╢ рдЯреЛрдХрди рдХреЗ рд▓рд┐рдП рджреЛ рдмрд╛рд░ рдХреЙрд▓ рдХрд░ рд░рд╣реЗ рд╣реИрдВ рдЬреЛ рдорд╣рдВрдЧрд╛ рд╣реИред рдореИрдВ рдпрд╣ рдирд╣реАрдВ рд╕рдордЭ рд╕рдХрддрд╛ рдХрд┐ рд╕рдорд╕реНрдпрд╛ рдХрд╣рд╛рдБ рд╕реЗ рдЖ рд╕рдХрддреА рд╣реИред рдпрд╣рд╛рдВ рд╡рд╣ рдХреЛрдб рд╣реИ рдЬрд┐рд╕рдХрд╛ рдореИрдВ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВред рдХреНрдпрд╛ рдЖрдк рдХреГрдкрдпрд╛ рдЗрд╕рдореЗрдВ рдорджрдж рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

https://gist.github.com/shaxaaa/15817f1bcc7b479f3c541383d2e83650

рдореИрдВ рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рд╕реЗ рдереЛрдбрд╝реА рджреЗрд░ рдХреЗ рд▓рд┐рдП рдХреБрд╢реНрддреА рд▓рдбрд╝реА, рд▓реЗрдХрд┐рди рдЖрдЦрд┐рд░рдХрд╛рд░ рдореБрдЭреЗ рдпрд╣ рдХрд╛рдо рдорд┐рд▓ рдЧрдпрд╛ред рдореИрдВрдиреЗ рдПрдХ рд╕рд╛рде рдПрдХ рдкреИрдХреЗрдЬ рдлреЗрдВрдХрд╛ред

https://github.com/baleeds/apolo-link-refresh-token

рдЗрд╕ рдкреИрдХреЗрдЬ рдФрд░ рдЕрдкреЛрд▓реЛ-рд▓рд┐рдВрдХ-рдЯреЛрдХрди-рд░реАрдлреНрд░реЗрд╢ рдирд╛рдордХ рдкреИрдХреЗрдЬ рдХреЗ рдмреАрдЪ рдкреНрд░рд╛рдердорд┐рдХ рдЕрдВрддрд░ рдпрд╣ рд╣реИ рдХрд┐ рдпрд╣ рдкреИрдХреЗрдЬ рд░реАрдлреНрд░реЗрд╢ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдиреЗрдЯрд╡рд░реНрдХ рддреНрд░реБрдЯрд┐ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░реЗрдЧрд╛ред

рдореБрдЭреЗ рдмрддрд╛рдПрдВ рдХрд┐ рдХреНрдпрд╛ рдЖрдк рд▓реЛрдЧреЛрдВ рдХреЗ рдкрд╛рд╕ рдмрджрд▓рд╛рд╡ рдХреЗ рд▓рд┐рдП рд╡рд┐рдЪрд╛рд░ рд╣реИрдВред

рдпрд╣рд╛рдБ рдореВрд▓ рдЙрдкрдпреЛрдЧ рд╣реИ:

const refreshTokenLink = getRefreshTokenLink({
  authorizationHeaderKey: 'Authorization',
  fetchNewAccessToken,
  getAccessToken: () => localStorage.getItem('access_token'),
  getRefreshToken: () => localStorage.getItem('refresh_token'),
  isAccessTokenValid: accessToken => isTokenValid(accessToken),
  isUnauthenticatedError: graphQLError => {
    const { extensions } = graphQLError;
    if (
      extensions &&
      extensions.code &&
      extensions.code === 'UNAUTHENTICATED'
    ) {
      return true;
    }
    return false;
  },
});

рдореИрдВрдиреЗ рдЗрд╕реЗ рдПрдХ рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдмрдирд╛рдХрд░ рд╣рд▓ рдХрд┐рдпрд╛ promiseToObservable.js :

import { Observable } from 'apollo-link';

export default promise =>
  new Observable((subscriber) => {
    promise.then(
      (value) => {
        if (subscriber.closed) return;
        subscriber.next(value);
        subscriber.complete();
      },
      err => subscriber.error(err)
    );
    return subscriber; // this line can removed, as per next comment
  });

рдФрд░ рдлрд┐рд░

import { onError } from 'apollo-link-error';
import promiseToObservable from './promiseToObservable';

export default (refreshToken: Function) =>
  onError(({
    forward,
    graphQLErrors,
    networkError = {},
    operation,
    // response,
  }) => {
    if (networkError.message === 'UNAUTHORIZED') { // or whatever you want to check
      // note: await refreshToken, then call its link middleware again!
      return promiseToObservable(refreshToken()).flatMap(() => forward(operation));
    }
  });

рдореИрдВ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВ рдФрд░ рдкрд╛рдпрд╛ рдХрд┐ рдЯреЛрдХрди рдЕрдиреБрд░реЛрдз рд░реАрдлреНрд░реЗрд╢ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рднреА рдпрд╣ рдкреБрд░рд╛рдиреЗ рдЯреЛрдХрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдореИрдВ рдЕрдиреБрд╕рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ рдкреНрд░рдпрд╛рд╕ рдХрд░рддрд╛ рд╣реВрдВ:

return promiseToObservable(refreshToken()).flatMap((value) => {
  operation.setContext(({ headers = {} }) => ({
    headers: {
      // re-add old headers
      // ...headers,
      Authorization: `JWT ${value.token}`
    }
  }));
  return forward(operation)
});

рдФрд░ рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред
рд╣рд╛рд▓рд╛рдВрдХрд┐, рдЗрд╕рдореЗрдВ рдЕрднреА рднреА рдПрдХ рд╕рдорд╕реНрдпрд╛ рд╣реИ рдХрд┐ рдЕрдЧрд░ рдореИрдВ ...headers (рдорддрд▓рдм рдкреБрд░рд╛рдиреЗ рд╣реЗрдбрд░ рдХреЛ рдлрд┐рд░ рд╕реЗ рдЬреЛрдбрд╝рдирд╛) рдЬреЛрдбрд╝рддрд╛ рд╣реВрдВ, рддреЛ рдлреЙрд░рд╡рд░реНрдб рдЕрдиреБрд░реЛрдз рднреЗрдЬреЗ рдЬрд╛рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдХреБрдЫ рдЧрдбрд╝рдмрдбрд╝ рд╣реИ:
ERROR Error: Network error: Cannot read property 'length' of null
рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ ... рд╢реАрд░реНрд╖рд▓реЗрдЦреЛрдВ рдореЗрдВ рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдирдП рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдХреЗ рд╕рд╛рде рд╕рдВрдШрд░реНрд╖ рдХрд░ рд╕рдХрддрд╛ рд╣реИред

рдЙрдкрд░реЛрдХреНрдд рд╕рдорд╕реНрдпрд╛ рдЕрдкреЛрд▓реЛ-рдХреЛрдгреАрдп "apollo-angular-link-http": "^1.6.0", рдФрд░ рдЕрдкреЛрд▓реЛ-рдХреНрд▓рд╛рдЗрдВрдЯ рдореЗрдВ рдирд╣реАрдВ "apollo-link-http": "^1.5.16", рдЬрдмрдХрд┐ рд▓рд┐рдВрдХ-рддреНрд░реБрдЯрд┐ рд╕рдорд╛рди рд╣реИ "apollo-link-error": "^1.1.12",

рдПрдХ рдФрд░ рд╡рд╛рдХреНрдпрд╡рд┐рдиреНрдпрд╛рд╕: рдЖрдВрдЦреЗрдВ:

import Vue from 'vue'
import { Observable } from 'apollo-link'
import { onError } from 'apollo-link-error'

const onGraphqlError = async ({ graphQLErrors = [], observer, operation, forward }) => {
  // here you could call the refresh query in case you receive an expired error
  for (let error of graphQLErrors)
    observer.next(forward(operation)) // this line would retry the operation
}

const onNetworkError = async ({ observer, networkError, operation, forward }) => { }

export const errorHandler = opt => new Observable(async observer => {
  try {
    const payload = { ...opt, observer }
    await Promise.all([onGraphqlError(payload), onNetworkError(payload)])
    if (observer.closed) return
    observer.complete()
  } catch (error) {
    observer.error(error)
  }
})

рдирдорд╕реНрддреЗ! рдореИрдВ рдкреВрд░реНрдг рд╡реЗрдмрд╕реЛрдХреЗрдЯ рдкрд░рд┐рд╡рд╣рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рдЯреЛрдХрди рдХреНрд╡реЗрд░реА рдХрд╛ рдЕрдиреБрд░реЛрдз рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдпрд╣ рдХреИрд╕реЗ рдХрд░рдирд╛ рд╣реИ рдкрддрд╛ рдирд╣реАрдВред
рдореИрдВ рдПрдХ рдЕрдиреБрд░реЛрдз рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдЬрдм рд╕рд░реНрд╡рд░ рдЬрд╡рд╛рдм рджреЗрддрд╛ рд╣реИ рдХрд┐ accessToken рд╕рдорд╛рдкреНрдд рд╣реЛ рдЧрдпрд╛ рд╣реИред

import { onError } from "apollo-link-error";

import gql from 'graphql-tag'

// Client: VUE APOLLO
const q = {
    query: gql`query token { token { accessToken } }`,
    manual: true,
    result({ data, loading }) {
        if (!loading) {
            console.log(data)
        }
    },
}

const link = onError(({ graphQLErrors, networkError, operation, response, forward }) => {

    if (networkError) {


        switch (networkError.message) {
            case 'accessTokenExpired':
                console.log('accessTokenExpired')
                return forward(q) // NOT WORKS, NEED HELP
            case 'unauthorized':
                return console.log('unauthorized')
            default:
                return forward(operation)
        }
    }

    return forward(operation)
})

export default link

@nikitamarcius рд╣рдордиреЗ рдКрдкрд░ рд╡рд░реНрдХрдЕрд░рд╛рдЙрдВрдб рдкреЛрд╕реНрдЯ рдХрд┐рдП рд╣реИрдВ,

рдореИрдВ рдЯреЛрдХрди рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рдиреЗ рдореЗрдВ рдЕрд╕рдорд░реНрде рд╣реВрдВ, рдХреНрдпрд╛ рдХреЛрдИ рдХрд╛рдордХрд╛рдЬреА рдЙрджрд╛рд╣рд░рдг рдкреНрд░рджрд╛рди рдХрд░ рд╕рдХрддрд╛ рд╣реИ

@ Ramyapriya24 рдпрд╣рд╛рдБ рд╡рд╣ рдХреЛрдб рд╣реИ рдЬрд┐рд╕рдХрд╛ рдореИрдВ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдБред

import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client';
import { setContext } from '@apollo/link-context';
import AuthService from 'services/auth-service' // this is my implementation

const asyncAuthLink = setContext(async () => {
    // this is an async call, it will be done before each request
    const { token } = await AuthService.getCredentials();
    return {
      headers: {
        authorization: token
      },
    };
  },
);

const httpLink = new HttpLink({
  uri: 'http://localhost:4000/graphql',
});

export const apolloClient = new ApolloClient({
  cache: new InMemoryCache(),
  link: asyncAuthLink.concat(httpLink),
});

@adrianolsk рдХреНрдпрд╛ рдЖрдк

'рд╕реЗрд╡рд╛рдУрдВ/рдкреНрд░рд╛рдзрд┐рдХрд░рдг-рд╕реЗрд╡рд╛' рд╕реЗ AuthService рдЖрдпрд╛рдд рдХрд░реЗрдВ//рдпрд╣ рдореЗрд░рд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣реИ
рдХреЙрдиреНрд╕реНрдЯ {рдЯреЛрдХрди} = AuthService.getCredentials (); рдХрд╛ рдЗрдВрддрдЬрд╛рд░ рдХрд░реЗрдВ;

рдЬрдм рдореИрдВ рд╕реЗрд╡рд╛ рдЖрдпрд╛рдд рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рддреЛ рдореБрдЭреЗ рддреНрд░реБрдЯрд┐рдпрд╛рдВ рдорд┐рд▓ рд░рд╣реА рд╣реИрдВ

рдпрд╣ рдореЗрд░реА рд╕реЗрд╡рд╛ рд╣реИ, рдпрд╣ рд╕рд┐рд░реНрдл рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛-рдореВрд▓ рд╕реЗ AsyncStorage рдкрдврд╝рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд▓реЙрдЧрд┐рди рдХреЗ рдмрд╛рдж рдореИрдВрдиреЗ рд╡рд╣рд╛рдВ рдореВрд▓реНрдп рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рд╣реИ рдФрд░ рдкреНрд░рддреНрдпреЗрдХ рдЕрдиреБрд░реЛрдз рд╕реЗ рдкрд╣рд▓реЗ рдХреЛрдб рдХреЗрд╡рд▓ рдЬрд╛рдирдХрд╛рд░реА рдХреЛ рдкрдХрдбрд╝рддрд╛ рд╣реИ рдФрд░ рд╣реЗрдбрд░ рдореЗрдВ рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИ, рдЖрдк рдРрд╕рд╛ рд╣реА рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдпрд╛ рд╕реНрдерд╛рдиреАрдп рд╕реНрдЯреЛрд░реЗрдЬ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдпрджрд┐ рдЖрдк рд╡реЗрдм рдкрд░ рд╣реИрдВред

рдЖрдк рд╡рд╣ рдЬрд╛рдирдХрд╛рд░реА рдХрд╣рд╛рдБ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░ рд░рд╣реЗ рд╣реИрдВ рдЬрд┐рд╕рдХрд╛ рдЖрдк рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ?

рдЖрдк рдмрд╕ рдЗрд╕рдХрд╛ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ

//save the token after login or when it refreshes
localStorage.setItem('token', yourToken);

рдФрд░ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ

const asyncAuthLink = setContext(() => {
    // grab token from localStorage
    const token = localStorage.getItem('token');
    return {
      headers: {
        authorization: token
      },
    };
  },
);

@adrianolsk рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж, рд▓реЗрдХрд┐рди рдореИрдВ рдХреЛрдгреАрдп рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдореИрдВ grapqh.module.ts рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд╕реЗрд╡рд╛ рдЖрдпрд╛рдд рдХрд░рдиреЗ рдореЗрдВ рдЕрд╕рдорд░реНрде рд╣реВрдВ рдЬрдм рдореИрдВ рд╕реЗрд╡рд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рддреЛ рдореБрдЭреЗ рддреНрд░реБрдЯрд┐рдпрд╛рдВ рдорд┐рд▓ рд░рд╣реА рд╣реИрдВ

рдХреНрдпрд╛ рдХреЛрдИ рдХреНрд▓рд╛рд╕ рдФрд░ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдмрд┐рдирд╛ рдореЙрдбреНрдпреВрд▓.рдЯреАрдПрд╕ рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд╕реЗрд╡рд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЬрд╛рди рд╕рдХрддрд╛ рд╣реИ

рдзрдиреНрдпрд╡рд╛рдж

рдореИрдВ рдЯреЛрдХрди рд░реАрдлреНрд░реЗрд╢ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП fromPromise рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░ рд░рд╣рд╛ рд╣реВрдВред
рдореВрд▓ рд░реВрдк рд╕реЗ рдЗрд╕ рдкреЛрд╕реНрдЯ рдХреЗ рддреАрд╕рд░реЗ рдмреЙрдХреНрд╕ рдХрд╛ рдЕрдиреБрд╕рд░рдг рдХрд░ рд░рд╣реЗ рд╣реИрдВ

рдореИрдВ рд╕рдлрд▓рддрд╛рдкреВрд░реНрд╡рдХ рдЯреЛрдХрди рдкреНрд░рд╛рдкреНрдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдФрд░ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рд▓реЗрдХрд┐рди catch рдпрд╛ filter рдпрд╛ flatMap рдХреЛ рднреА рдХреЙрд▓ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдореБрдЭреЗ рдпрдХреАрди рдирд╣реАрдВ рд╣реИ рдХрд┐ рдЗрд╕реЗ рдХреИрд╕реЗ рдбрд┐рдмрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдП, рдЗрд╕рд▓рд┐рдП рдХреБрдЫ рд╕реБрдЭрд╛рд╡ рдорджрджрдЧрд╛рд░ рд╣реЛрдВрдЧреЗред

if (token && refreshToken) {
  return fromPromise(
    getNewToken(client)
      .then(({ data: { refreshToken } }) => {
        console.log("Promise data: ", refreshToken);
        localStorage.setItem("token", refreshToken.token);
        localStorage.setItem("refreshToken", refreshToken.refreshToken);
        return refreshToken.token;
      })
      .catch((error) => {
        // Handle token refresh errors e.g clear stored tokens, redirect to login, ...
        console.log("Error after setting token: ", error);
        return;
      })
  )
    .filter((value) => {
      console.log("In filter: ", value);
      return Boolean(value);
    })
    .flatMap(() => {
      console.log("In flat map");
      // retry the request, returning the new observable
      return forward(operation);
    });
}

@adrianolsk : рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╣рдореЗрд╢рд╛ рд╕рдорд╛рдкреНрдд рд╣реЛрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рд╣реА рдЯреЛрдХрди рдХреЛ рддрд╛рдЬрд╝рд╛ рдХрд░рдиреЗ рд▓рдЧрддрд╛ рд╣реИ, рдЬреЛ рдХреБрдЫ рдкреНрд░рдорд╛рдгреАрдХрд░рдг рд╕реЗрд╡рд╛рдУрдВ (рдЬреИрд╕реЗ Auth0 рдХрд╛

рдореИрдВ рдЯреЛрдХрди рд░реАрдлреНрд░реЗрд╢ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП fromPromise рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░ рд░рд╣рд╛ рд╣реВрдВред
рдореВрд▓ рд░реВрдк рд╕реЗ рдЗрд╕ рдкреЛрд╕реНрдЯ рдХреЗ рддреАрд╕рд░реЗ рдмреЙрдХреНрд╕ рдХрд╛ рдЕрдиреБрд╕рд░рдг рдХрд░ рд░рд╣реЗ рд╣реИрдВ

рдореИрдВ рд╕рдлрд▓рддрд╛рдкреВрд░реНрд╡рдХ рдЯреЛрдХрди рдкреНрд░рд╛рдкреНрдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдФрд░ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рд▓реЗрдХрд┐рди catch рдпрд╛ filter рдпрд╛ flatMap рдХреЛ рднреА рдХреЙрд▓ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдореБрдЭреЗ рдпрдХреАрди рдирд╣реАрдВ рд╣реИ рдХрд┐ рдЗрд╕реЗ рдХреИрд╕реЗ рдбрд┐рдмрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдП, рдЗрд╕рд▓рд┐рдП рдХреБрдЫ рд╕реБрдЭрд╛рд╡ рдорджрджрдЧрд╛рд░ рд╣реЛрдВрдЧреЗред

if (token && refreshToken) {
  return fromPromise(
    getNewToken(client)
      .then(({ data: { refreshToken } }) => {
        console.log("Promise data: ", refreshToken);
        localStorage.setItem("token", refreshToken.token);
        localStorage.setItem("refreshToken", refreshToken.refreshToken);
        return refreshToken.token;
      })
      .catch((error) => {
        // Handle token refresh errors e.g clear stored tokens, redirect to login, ...
        console.log("Error after setting token: ", error);
        return;
      })
  )
    .filter((value) => {
      console.log("In filter: ", value);
      return Boolean(value);
    })
    .flatMap(() => {
      console.log("In flat map");
      // retry the request, returning the new observable
      return forward(operation);
    });
}

рдореИрдВрдиреЗ рдкрд╛рдпрд╛ рд╣реИ рдХрд┐ рддреНрд░реБрдЯрд┐ рдХрд╛ рдХрд╛рд░рдг рдХреНрдпрд╛ рдерд╛ред рдЙрдкрд░реЛрдХреНрдд рдХреЛрдб рдореЗрдВ рдирд╣реАрдВ рджреЗрдЦрд╛ рдЧрдпрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореИрдВрдиреЗ рдкреНрд░рддреНрдпреЗрдХ рдкрд░рд┐рдгрд╛рдореА рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдореИрдк рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП map рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рд╣реИред рдЗрд╕рдХреЗ рдХрд╛рд░рдг onError рдХреБрдЫ рднреА рдирд╣реАрдВ рд▓реМрдЯрд╛ рдФрд░ рдСрдмреНрдЬрд░реНрд╡реЗрдмрд▓ рдХреЛ рдЯреЛрдХрди рдирд╡реАрдиреАрдХрд░рдг рдХреЗ рд▓рд┐рдП рдСрдкрд░реЗрд╢рди рдХреА рд╕рджрд╕реНрдпрддрд╛ рдирд╣реАрдВ рдорд┐рд▓реАред

рдмрд╣реБрдд рднреНрд░рдорд┐рдд рдХрд░рдиреЗ рд╡рд╛рд▓рд╛ рдФрд░ рдореБрдЭреЗ рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдореЗрдВ рдЗрддрдирд╛ рд╕рдордп рд▓рдЧрд╛ред рдореЗрд░реА рдорджрдж рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмреНрд▓реЙрдЧ рдкреЛрд╕реНрдЯ рдХреЗ рд▓реЗрдЦрдХ рдХреЛ рдзрдиреНрдпрд╡рд╛рджред

ERROR Error: Network error: Cannot read property 'length' of null

@ рд╡рд┐рд▓реНрд╕рдирд▓рд╛рдЙ0755 , рдореБрдЭреЗ рднреА рдпрд╣реА рд╕рдорд╕реНрдпрд╛ рдереАред рд╕рднреА null рд╢реАрд░реНрд╖рд▓реЗрдЦреЛрдВ рдХреЛ рдПрдХ рдЦрд╛рд▓реА рд╕реНрдЯреНрд░рд┐рдВрдЧ '' рд╕реЗрдЯ рдХрд░рдХреЗ рдЗрд╕реЗ рд╣рд▓ рдХрд┐рдпрд╛ред

onError рдХреЗрд╡рд▓ async рдкреНрд░рддреАрдХреНрд╖рд╛ рдХреЗ рд╕рд╛рде рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрд▓рдмреНрдз рдХреНрдпреЛрдВ рдирд╣реАрдВ рд╣реИ?

рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕

рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ

NicholasLYang picture NicholasLYang  ┬╖  4рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

sandersn picture sandersn  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

j3ddesign picture j3ddesign  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

steffenmllr picture steffenmllr  ┬╖  4рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

lobosan picture lobosan  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ