My own realtime chat with react, graphql and postgresql [part 7 - React Login]

dalejan

David Alejandro Quiñonez

Posted on October 28, 2020

My own realtime chat with react, graphql and postgresql [part 7 - React Login]

In this part we'll be seeing how to start the apollo client in react, use mutations and signin our first user from the web.

Previously we saw the first steps in the project structure and the routing system, but we didn't create the containers that renders those url paths, so let's do it!

But first we have to configure our apollo-client in order to use apollo in react. For this let's install some packages: npm i @apollo/client apollo-utilities graphql apollo-link-ws subscriptions-transport-ws graphql-tag.

./graphql/client.js

import { ApolloClient, HttpLink, InMemoryCache, split } from "@apollo/client";
import { WebSocketLink } from "apollo-link-ws";
import { getMainDefinition } from "apollo-utilities";

const server_url = process.env.SERVER_URL;

const httpLink = new HttpLink({
  uri: "http://server_url",
});

// Create a WebSocket link:
const wsLink = new WebSocketLink({
  uri: `ws://server_url`,
  options: {
    reconnect: true,
  },
});

const link = split(
  // split based on operation type
  ({ query }) => {
    const definition = getMainDefinition(query);
    return (
      definition.kind === "OperationDefinition" &&
      definition.operation === "subscription"
    );
  },
  wsLink,
  httpLink
);

export const client = new ApolloClient({
  cache: new InMemoryCache(),
  link: link,
});

Enter fullscreen mode Exit fullscreen mode

There is a few important things happening here.

  1. ApolloClient will allow us to compose a client object to use it as a provider so our app can access this api from any component under the main component node we define.
  2. The server_url constant is the path that we got from deploy our server, if we are running this locally it would be something like localhost:8080/graphql.
  3. The HttpLink and the WebSocketLink are link creators, we'll use those links to comunicate with the sockets and http api we defined in our backend. 4.The split operator let us redirect the queries, mutations and subscriptions to the specific endpoints they correspond to.

Now we can provide this client to all our app so we can excecute the graphql operations wherever we like.

./App.jsx

import { ApolloProvider } from "@apollo/client";
import React from "react";
import { HashRouter } from "react-router-dom";
import AppRouter from "./AppRouter";
import { client } from "./graphql/client";
import appRoutes from "./routes/app.routes";

const App = () => {
  return (
    <div className="App">
      <ApolloProvider client={client}>
        <HashRouter basename="/">
          <AppRouter routes={appRoutes} />
        </HashRouter>
      </ApolloProvider>
    </div>
  );
};

export default App;

Enter fullscreen mode Exit fullscreen mode

Now we actually can connect to the backend, but first we have to define what we want to say to it, or what we want it to answer us.

To do this let's define our first operation, the signin mutation.

./graphql/mutations/signIn.js

import gql from "graphql-tag";

export default gql`
  mutation signInMutation($usr: String, $password: String) {
    signInUser(usr: $usr, password: $password) {
      usr
      name
      type
      token
    }
  }
`;

Enter fullscreen mode Exit fullscreen mode

gql is basically a graphql interpreter that reads a string and translate it into graphql language. You may have notice that this string is exactlly the same we tested in the playground, shout-out to the playground!

Now we can consume this specific endpoint.

Let's login.

Alt Text

./containers/Login/Login.jsx

import { useMutation } from "@apollo/client";
import React, { useEffect } from "react";
import Signin from "../../components/Signin/Signin";
import SIGNIN_USER from "../../graphql/mutations/signIn";

const Login = () => {
  const [signInUser, { data, error, loading }] = useMutation(SIGNIN_USER);

  const onSubmitSignin = (fields) => {
    signInUser({
      variables: { usr: fields.username, password: fields.password },
    });
  };

  useEffect(() => {
    if (!loading) {
      console.log(data);
      if (data?.signInUser.usr) {
        console.log("Should let me in");
      } else {
        console.log("You shall not pass");
      }
    }
  }, [data, loading]);

  return (
    <div>
      <Signin onSubmit={onSubmitSignin}></Signin>
    </div>
  );
};

export default Login;
Enter fullscreen mode Exit fullscreen mode

As always, let's check this piece of code.

  1. The useMutation hook allow us to execute the SIGNIN_USER mutation as a function signInUser, also it let us check the data, if an error occur and whereas our petition is loading.
  2. The Signin component is just a form that resolve the username and the password, so it's submit function fires the signInUser mutation with those params.
  3. Using the useEffect hook we can check for data and loading states to change.

To check if everything is ok you could create a new user in the playground, and come back to the app to try those credentials. The console should print Should let me in.

In the next part we'll use the routing system we created so we can navigate to the chatroom container. As an exercise you should try to build the signup flow (hint: it's pretty similar).

💖 💪 🙅 🚩
dalejan
David Alejandro Quiñonez

Posted on October 28, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related