dev.to clone using React-Node, Apollo-Cache, apollo-link-token-refresh, One-2-Many relation in Typeorm [Part-3]
Tags: react, typescript, apollo, graphql
Published: 2019-10-23 17:45:39

Hello Community, Today I am writing 3 part of this article series in which I am trying to clone dev.to with minimum feature.It will be a prototype, in which user can signUp/signIn, create post & other features.

> I am doing it for just learning purpose.
> If you have not visited the Part-1 & Part-2, please understand those first for better clearity of this one.

[Part- 1](https://dev.to/vinodchauhan7/dev-to-clone-using-react-node-via-typescript-typegraphql-typeorm-backend-part-1-kmn)
[Part -2](https://dev.to/vinodchauhan7/dev-to-clone-using-react-hooks-graphql-codegen-apollo-refresh-token-authentication-middleware-backend-frontend-part-2-28g8)


Code Repo : [GitHub Link](https://github.com/vinodchauhan7/dev.to-clone/tree/master)

Howdy! Friends, In this article I am able to complete many things such as **Login/Registration** functionality with token refresh feature. Also able to maintain cache using **Apollo state management** and at last loggedIn user can post its articles see other users articles and profiles.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/94n9zkltxbwiy9tdupxo.png)

###Login
When user login a refresh_token saved in user browser cookies.For user smooth usage of application we need to maintain its authentication even if user reload the page or if its token get expired. We have take care of both the features with **RefreshToken** and **using Apollo-link-token-Refresh** module in case of token got expired.

```javascript
//Getting access Token and passing it in request headers
const requestLink = new ApolloLink(
  (operation, forward) =>
    new Observable(observer => {
      let handle: any;
      Promise.resolve(operation)
        .then(operation => {
          const accessToken = getAccessToken();
          if (accessToken) {
            operation.setContext({
              headers: {
                authorization: `bearer ${accessToken}`
              }
            });
          } //accessToken is defined
        }) //then operation ends here
        .then(() => {
          handle = forward(operation).subscribe({
            next: observer.next.bind(observer),
            error: observer.error.bind(observer),
            complete: observer.complete.bind(observer)
          }); //handle ends here
        })
        .catch(observer.error.bind(observer));

      return () => {
        if (handle) handle.unsubscribe();
      };
    })
);

const client = new ApolloClient({
  link: ApolloLink.from([
    new TokenRefreshLink({
      accessTokenField: "accessToken",
      isTokenValidOrUndefined: () => {
        const token = getAccessToken();

        if (!token) {
          return true;
        }

        try {
          const { exp } = jwtDecode(token);
          if (Date.now() >= exp * 1000) {
            return false;
          } else {
            return true;
          }
        } catch (err) {
          console.log(err);
          return false;
        }
      },
      fetchAccessToken: () => {
        return fetch("http://localhost:4000/refresh_token", {
          method: "POST",
          credentials: "include"
        });
      },
      handleFetch: accessToken => {
        setAccessToken(accessToken);
      },
      handleError: err => {
        console.warn("Your refresh token is invalid. Try to relogin");
        console.error(err);
      }
    }),
    onError(() => {}),
    requestLink,
    new HttpLink({
      uri: "http://localhost:4000/graphql",
      credentials: "include"
    }) //new HttpLink ends here
  ]),
  cache
});

```

###Apollo-Cache
When user loggedIn, we are updating our cache for **MeQuery** so that it can be used throughout the application to know who is currently loggedIn without hitting the actual graphql query.
```javascript
 const LoginComponentUser = withFormik<MyFormProps, FormValues>({
    mapPropsToValues: props => ({
      email: props.initialEmail || "",
      password: props.initialPassword || ""
    }),
    validationSchema: Yup.object().shape({
      email: Yup.string()
        .email("Email is not valid")
        .required("Email is required"),
      password: Yup.string().required("Password is required")
    }),
    async handleSubmit({ email, password }: FormValues) {
      console.log(email, password);

      const response = await login({
        variables: {
          data: {
            email,
            password
          }
        },
        update: (store, { data }) => {
          //updating cache so that it will not hit again and again
          if (!data) {
            return null;
          }
          store.writeQuery<MeQuery>({
            query: MeDocument,
            data: {
              __typename: "Query",
              me: data.login.user
            }
          });
        }
      });

      console.log(response);
      if (response && response.data) {
        setAccessToken(response.data.login.accessToken);
      }

      console.log(getAccessToken());
      window.location.replace("http://localhost:3000/");
    }
  })(LoginForm);
```

###Styled-Components 
I am also adding little-bit styled-components usage for beginners to showcase how to use css in JS.
```javscript
 const WritePost = styled.a`
    width: 118px;
    display: block;
    margin-top: 10px;
    padding: 3px;
    text-align: center;
    font-weight: bold;
    border-radius: 3px;
    border: 2px solid #0a0a0a;
    color: #0a0a0a;
    background: #66e2d5;
    font-size: 11px;
    text-decoration: none !important;
    font-stretch: condensed;
    &:hover {
      color: #0b0b0b;
      background: #66e2e5;
    }
  `;

  const ShowSvg = styled.div`
    margin-top: 10px;
  `;
```

###One-to-Many Relations
I am also showing relations between schemas to show how we can implement this **TypeORM** feature using **Graphql** in our application by showing [user-post] relationship.
```javascript
 @Query(() => [Post])
  @UseMiddleware(isAuth)
  async getAllPostById(@Arg("userId") userId: number): Promise<Post[]> {
    const post = await Post.find({
      where: { user: { id: userId } },
      relations: ["user"]
    });
    console.log(JSON.stringify(post, null, 2));
    return post;
  }
```

##I have not made FrontEnd similar to dev.To fully because it will took time for matching all the things and also all feature.


![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/1mevy49s7e3b7lct1upo.png)

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/7cj7ogmxpiskw9jqea0g.png)

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/1maeu2cyruqxeorvsc32.png)

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/trzotjyqgl5h5pl5y0gd.png)

The purpose of this article series is to familiar beginners or intermediate react developers with Token refresh,apollo and typeorm features.

Will come back with new features and articles, Till then bye guys..