Slack Clone with React | Semantic UI | GraphQL | PostgresSQL (PART 5)
Tags: react, webdev, tutorial, postgres
Published: 2020-09-24 17:57:04

Previously, we went over how GraphQL works. You can find that  [article here](https://dev.to/ajeasmith/slack-clone-with-react-semantic-ui-graphql-postgressql-part-4-4iop).

Today, we'll start to create our Graphql queries and mutations.

Open up the `typesDefs.js` file. The first thing we need to do is map out what our data is going to be. We know that we need to have a `User` object to represent a user in our project, so let's start there.

## Types 

Remove the previous code in our `typeDefs.js` file and replace it with this => 

```
const { gql } = require("apollo-server");
module.exports = gql`
  type User {
    username: String!
    email: String!
    password: String!
  }
`
```
Next, we need to create a `Team` object for when a user needs to create a team

```
const { gql } = require("apollo-server");
module.exports = gql`
  type Team {
    owner: User!
    members: [User!]!
    channels: [Channel!]!
  }
`
```
Were gonna need `Channels` to join =>

```
const { gql } = require("apollo-server");
module.exports = gql`
  type Channel {
    id: Int!
    name: String!
    public: Boolean!
    messages: [Message!]!
    users: [User!]!
  }
`
```
Lastly, we need to be able to send and receive `Messages` =>

 ```
const { gql } = require("apollo-server");
module.exports = gql`
  type Message {
    id: Int!
    text: String!
    user: User!
    channel: Channel!
  }
`
```
Let's look at these types closely. 

- A **Team** who created it? **(owner prop)**, who's in the team? **(members prop)**, and what channels are associated with this team? **(channels prop)**.

- A **User** we need to know, which user is creating the teams and channels **(email, username, password props)**.

- A **Channel** which channel it is **(id prop)**, what's the name of the channel? **(name prop)**, will it be public or private? **(public prop)**, what are the messages **(message prop)**, and list the users in this channel **(users prop)**.

- A **Message** which message it is? **(id prop)**, what does the message say? **(text prop)**, which user sent this message **(user prop)**, lastly which channel does this message belong to **(channel prop)**

In the end, your `typeDefs.js` should look like this => 

![Screen Shot 2020-09-16 at 2.12.35 AM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1600236782324/qmLh6FV3L.png)

Now, let's define our queries (GET endpoints) and mutations (POST, PUT, DELETE endpoints) 

Still, inside `typeDefs.js` file, let's add our queries

```
type Query {
    getUsers: [User!]!
    getMessages: [Message!]
    getUser(id: Int!): User!
  }
```
These are what I have so far. Mutations look like => 

```
type Mutation {
    createUser(username: String!, email: String!, password: String!): User
    createMessage(channel_id: Int!, text: String!): Boolean
    createTeam(name: String!): Boolean
    createChannel(teamId: Int!, name: String!, public: Boolean = false): Boolean
  }
```
FYI we only need to pass the params we need to use. As you can see all of our mutations involve creating something(POST) for now.

We're just defining it now, let's actually return some real data with our resolvers starting with creating a user using the `createUser` mutation. 

## Resolvers 

Head over to the `resolvers.js` file and create a `createUser` mutation *Remember, naming is important it needs to be the same name as the type query you defined*

```
const bcrypt = require("bcrypt");
const { User } = require("../models");
module.exports = {
  Mutation: {
      createUser: async (_, args) => {
        let { username, email, password } = args;
        try {
        // 1. Check if user exist in DB
        const getUser = await User.findOne({ where: { email: email } });
        if (!getUser) {
          // 2. Hash user password
          password = await bcrypt.hash(password, 12);
          // 3. store user in DB
          const user = await User.create({
            username,
            email,
            password
          });
          return user;
        } else {
          throw Error("User already exist");
        }
      } catch (err) {
        return err;
      }
    }
};
```
What we're doing is creating a user with the data passed to us through args (destructuring data). Were creating a user in the DB using the User model from Sequelize. I hope the rest of the comments help you get the gist of what's happening.

Let's test this endpoint in our playground. Have your server running and go to localhost:4000. 

calling the `createUser` mutation should look like this =>

![Screen Shot 2020-09-16 at 2.46.51 AM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1600238890887/7tz855mJB.png)

You specify the type, either query or mutation. Then you pick the endpoint. It should return a user and create a user in the DB if successful =>

![Screen Shot 2020-09-16 at 2.53.28 AM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1600239227014/dxWeoqWNd.png)

Now check the DB.

![Screen Shot 2020-09-16 at 2.58.19 AM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1600239510071/kdEzj7v25.png)
FYI ignore the first user, that was a test I did earlier. But as you can see JamesB was created with the password hashed, which is awesome. 

let's create the rest of the mutations. Creating a Team, Channel, and Message. 

```
const bcrypt = require("bcrypt");
const { Channel, Message, Team } = require("../models");
module.exports = {
  Mutation: {
    createChannel: async (_, args) => {
      try {
        await Channel.create(args);
        return true;
      } catch (err) {
        console.log(err);
        return false;
      }
    },
    createMessage: async (_, args) => {
      // const channel = Channel.findOne({where: {id: args.channel_ids}})
      try {
        await Message.create({
          ...args,
          userId: 1
        });
        return true;
      } catch (error) {
        console.log(error);
        return false;
      }
    },
    createTeam: async (_, args) => {
      try {
        await Team.create({
          ...args,
          owner: 1
        });
        return true;
      } catch (error) {
        console.log(error);
        return false;
      }
    }
  }
};
```
Now our queries => 

```
const bcrypt = require("bcrypt");
const { User } = require("../models");
module.exports = {
  Query: {
    getUsers: async () => {
      try {
        const users = await User.findAll();
        return users;
      } catch (err) {
        console.log(err);
      }
    },
    getUser: async (_, { id }) => {
      try {
        const user = await User.findOne({ where: { id } });
        return user;
      } catch (error) {
        console.log(error);
      }
    }
  },
}
```
Now that we have users to work with, let's get users using our `getUsers` query. 

![Screen Shot 2020-09-16 at 3.02.18 AM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1600239764254/9wuUTtlAI.png)

it returns exactly what we said it needed to, great. In a nutshell, these are the endpoints that we will be calling from our frontend. 

Overall, your `typeDefs.js` file should now look like this => 

![Screen Shot 2020-09-16 at 3.21.11 AM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1600241036006/PuYNvdEW6.png)


And `resolvers.js` file

![Screen Shot 2020-09-16 at 3.22.45 AM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1600241061462/nyD6plRf7.png)

![Screen Shot 2020-09-16 at 3.23.34 AM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1600241071260/yCH9jkkdq.png)

That's all for this one, hope that wasn't too mind-blowing. I have a few more articles to go before this series is caught up to where I'm currently at in this project. So until then, if you have any questions or if I missed anything let me know :)