Skip to content

Instantly share code, notes, and snippets.

@bzhr
Created May 11, 2020 12:01
Show Gist options
  • Save bzhr/531e1c25a4960fcd06ec06d8b21f143b to your computer and use it in GitHub Desktop.
Save bzhr/531e1c25a4960fcd06ec06d8b21f143b to your computer and use it in GitHub Desktop.

Revisions

  1. bzhr created this gist May 11, 2020.
    142 changes: 142 additions & 0 deletions index.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,142 @@
    import React from "react";
    import ReactDOM from "react-dom";
    import ApolloClient from "apollo-client";
    import { ApolloProvider } from "@apollo/react-hooks";
    import { ApolloLink, fromPromise, Observable } from "apollo-link";
    import { onError } from "apollo-link-error";
    // import "./index.css";
    import App from "./App";
    import * as serviceWorker from "./serviceWorker";
    import { createUploadLink } from "apollo-upload-client";
    import { setContext } from "apollo-link-context";
    import { InMemoryCache } from "apollo-cache-inmemory";
    import "./assets/main.css";
    // import { signOut } from "./components/Auth";
    import { getToken, getRefreshToken, getNewToken } from "./constants/token";

    const API_URL = process.env.REACT_APP_API_URL;

    const httpLink = createUploadLink({
    uri: API_URL ? API_URL : "/graphql",
    credentials: "omit",
    });

    const authLink = setContext((_, { headers }) => {
    // get the authentication token from local storage if it exists
    const token = localStorage.getItem("token");
    console.log("Token in auth link: ", token);
    return {
    headers: {
    ...headers,
    authorization: token ? `JWT ${token}` : "",
    },
    };
    });

    let isRefreshing = false;
    let pendingRequests = [];

    const resolvePendingRequests = () => {
    pendingRequests.map((callback) => callback());
    pendingRequests = [];
    };

    // const getAndStoreToken = () => new Promise

    const errorLink = onError(
    ({ graphQLErrors, networkError, operation, forward, location, ...other }) => {
    console.log("On error");
    console.log(graphQLErrors, networkError, other);
    // TODO --- On error message invalid token clear local storage
    if (graphQLErrors && graphQLErrors.filter((e) => e).length > 0) {
    console.log("Errors: ", graphQLErrors);
    graphQLErrors.map(({ message, status }) => {
    console.log("Message: ", message);
    console.log("Status: ", status);
    console.log("Location: ", location);
    if (message.includes("You do not have permission")) {
    const token = getToken();
    const refreshToken = getRefreshToken();
    console.log("Token, refresh", token, refreshToken);
    if (token && refreshToken) {
    console.log("In if condition");
    // error code is set to UNAUTHENTICATED
    // when AuthenticationError thrown in resolver
    let forward$;
    if (!isRefreshing) {
    isRefreshing = true;
    forward$ = fromPromise(
    getNewToken(client)
    .then(({ data: { refreshToken } }) => {
    console.log("Promise data: ", refreshToken);
    // localStorage.setItem("token", refreshToken.token);
    // localStorage.setItem(
    // "refreshToken",
    // refreshToken.refreshToken
    // );
    resolvePendingRequests();
    return refreshToken.token;
    })
    .catch((error) => {
    // Handle token refresh errors e.g clear stored tokens, redirect to login, ...
    console.log("Error after setting token: ", error);
    pendingRequests = [];
    return;
    })
    .finally(() => {
    console.log("Finally");
    isRefreshing = false;
    })
    ).filter((value) => {
    console.log("In Filter: ", value);
    return Boolean(value);
    });
    } else {
    // Will only emit once the Promise is resolved
    forward$ = fromPromise(
    new Promise((resolve) => {
    pendingRequests.push(() => resolve());
    })
    );
    }
    return forward$.flatMap(() => {
    console.log("Forwarding!");
    return forward(operation);
    });
    }
    // else {
    // // If there's no token, then sign out user
    // console.log("There's no token, sign out the user", signOut);
    // signOut();
    // }
    }
    });
    }
    if (networkError) {
    console.log("Network error: ", networkError);
    }
    }
    );

    const links = [errorLink, authLink, httpLink];
    const link = ApolloLink.from(links);

    export const client = new ApolloClient({
    link,
    cache: new InMemoryCache(),
    fetchOptions: {
    mode: "no-cors",
    },
    });

    ReactDOM.render(
    <ApolloProvider client={client}>
    <App />
    </ApolloProvider>,
    document.getElementById("root")
    );

    // If you want your app to work offline and load faster, you can change
    // unregister() to register() below. Note this comes with some pitfalls.
    // Learn more about service workers: https://bit.ly/CRA-PWA
    serviceWorker.unregister();