Journey to the real world by cloning DEV.to backend server(part 6)
Tags: node, apollo, express, prisma
Published: 2021-05-16 16:18:39

In our last post we have worked around providing interface to user from where user can register and login into their account. 

But how can our application knew who is sending request . Suppose we want to edit our profile how application will knew who we are hence today we will work on context section in graphql where we will extract jwt token provided by user browser in header and recognise user.

One more problem we generally face in apollo graphql is splitting of schema and resolvers in different file in this post we will also split our schema and resolvers easily .

## Organise project structure in more scalable way

Now create some file inside typeDefs

1. typeDefs/base.schema.js
2. typeDefs/auth.schema.js

> `base.schema.js` is a js file where we  will define our root Query, root Mutation and Root Subscription. For now we have no any Subscription we will introduce subscription in future.

> `auth.schema.js` here we will define our Query,  Mutation and Subscription related to authentication by extending root Query , Mutation and Subscription from `base.schema.js`


In the same way create some file inside resolvers directory

1. auth.resolver.js

we have already `index.js` inside resolvers which will act as a central point where all resolvers file will be imported and we will combine all inside their specific root and export from here to `server.js`

> `auth.resolvers.js` will contain all definition related to authentication


First we will write code for `typeDefs/base.schema.js`

```javascript

const { gql } = require("apollo-server-express");

module.exports = gql`

  
  type Query

  type Mutation
`;

```

The only work of this file to export root schema from here.
Here we have only provide root schema.


`typeDefs/index.js`

```javascript


const { gql } = require("apollo-server-express");

const baseTypes = require("./base.schema");
const authTypes = require("./auth.schema");


module.exports = [
  baseTypes,
  authTypes,

];

```
In this file we have imported our auth and base schema file and export from here so that it can use by `server.js`.
Apollo server typeDefs can be an array hence we have exported array of Schem from here.


`typeDefs/auth.schema.js`


```javascript

const { gql } = require("apollo-server-express");

module.exports = gql`
  type AuthResponse {
    token: String!
    user: User!
  }

  extend type Query {
    me: User!
  }

  extend type Mutation {
    login(email: String!, password: String): AuthResponse!
    register(name: String!, email: String!, password: String!): AuthResponse!
  }
`;



```

Here we have extend our root Query and add more schema inside root Query and Mutation.

`me` query is useful when we need to get authenticated user using provided jwt token we will look into `me` query later

We are returning AuthResponse after successful mutation on register and login and AuthResponse contain type defination for `User` which we have not defined yet.So lets first define User type for our Application

Create `user.schema.js` inside typeDefs

`user.schema.js`

```javascript
const { gql } = require("apollo-server-express");

module.exports = gql`
  type User {
    id: ID!
    email: String
    name: String
    username: String
    avatar: String
    role: String
    location: [Float]
    createdAt: String
    updatedAt: String
  }



`;


```

In this file we only define User type and in the previous way we will import this file in `index.js`

`typeDefs/index.js`

```javascript
...
const userTypes = require("./user.schema");

...

module.exports = [
...

userTypes,
]

```

Now we will move resolver defined for authentication in index.js into `resolvers/auth.resolver.js`

`resolvers/auth.resolver.js`

```javascript

const { UserInputError, AuthenticationError } = require("apollo-server-errors");
const {
  generateHash,
  generateUsername,
  matchPassword,
  generateJwtToken,
} = require("../../utils/auth.util");

module.exports = {
  Query: {
    // fetch current user
    async me(_, __, { prisma, userId }) {
      const user = await prisma.user.findUnique({
        where: {
          id: userId,
        },
      });

      if (!user) {
        throw new AuthenticationError("token is missing");
      }
      return user;
    },
  },
  Mutation: {
    // login user
    async login(_, { email, password }, { prisma }) {
      try {
        const user = await prisma.user.findUnique({
          where: {
            email,
          },
        });

        if (!user) {
          throw new UserInputError("USER_NOT_FOUND", {
            message: "Account with this email does not found create new one",
          });
        }

        const matchPass = await matchPassword(password, user.password);

        if (!matchPass) {
          throw new UserInputError("INCORRECT_PASSWORD", {
            message: "Password is incorrect",
          });
        }

        const token = generateJwtToken(user.id);

        return {
          user,
          token,
        };
      } catch (error) {
        return error;
      }
    },

    // create new account
    async register(_, { name, email, password }, { prisma }) {
      try {
        const checkEmail = await prisma.user.findUnique({
          where: {
            email,
          },
        });

        if (checkEmail) {
          throw new UserInputError("EMAIL_ALREADY_EXISTS", {
            message: "Account with this email is already exists ",
          });
        }

        username = generateUsername(email);
        password = await generateHash(password);

        const newUser = await prisma.user.create({
          data: {
            name,
            email,
            password,
            username,
          },
        });

        const token = generateJwtToken(newUser.id);

        return {
          token,
          user: newUser,
        };
      } catch (error) {
        return error;
      }
    },
  },
};


```


Inside `resolvers/indexjs` import `auth.resolver.js` and export from there


`resolvers/index.js`


```javascript

const auth = require("./auth.resolver");


module.exports = {
  Query: {
    ...auth.Query,
    
  },

  Mutation: {
    ...auth.Mutation,
   
  },
};


```

We have organise our code now we can scale it for any number of features by creating new `feature.schema.js` and resolvers related to that features inside resolvers folder for example in future we want post feature we can easily create `post.schema.js` and `post.resolver.js` which will contain feature related to post section such that like post , delete post , edit post etc..

If you notice `me` resolver carefully you will notice that  it has third argument `prisma` and `userId` prisma is ok we already see in previous post it come from context but we have not exported userId from context lets do that.

Now we work on middleware section which will verify user jwt token and extract userId from that because when we was creating login and register we created jwt token by wrapping payload object as userId.


`src/context.js`

```javascript


...
const { decodeJwtToken } = require("./utils/auth.util");

module.exports = async ({ req, res }) => {
  const token = req.headers.authorization || "";

  let userId;
  if (token) {
    userId = decodeJwtToken(token);
  }

  return {
    userId,
   ...
  };
};

```


Now we will test our application


### Register

```

 mutation {
  register(name:"Harsh Mangalam",email:"harsh@gmail.com",password:"12345"){
    token
    user {
      id
      name
      email
      role
      createdAt
    }
  }
}


```


```
{
  "data": {
    "register": {
      "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjExLCJpYXQiOjE2MjExODE1MDAsImV4cCI6MTYyMTIxNzUwMH0.qZUyyNMAdZzy_N-U5o3FYEq6UXfQrQUe9sG2tbK-V0A",
      "user": {
        "id": "11",
        "name": "Harsh Mangalam",
        "email": "harsh@gmail.com",
        "role": "USER",
        "createdAt": "1621181500667"
      }
    }
  }
}
```


### me 

put Authorization header 

```
{
  "Authorization":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjExLCJpYXQiOjE2MjExODE1MDAsImV4cCI6MTYyMTIxNzUwMH0.qZUyyNMAdZzy_N-U5o3FYEq6UXfQrQUe9sG2tbK-V0A"
}

```

```
{
  me{
    
      id
      name
      email
      role
      createdAt
    }
  }

```


```
{
  "data": {
    "me": {
      "id": "11",
      "name": "Harsh Mangalam",
      "email": "harsh@gmail.com",
      "role": "USER",
      "createdAt": "1621181500667"
    }
  }
}


```


Okay today we have discuss many things in our next post we will work more on user section.