GraphQL MAGIC

Now that we finish with the set up of the different files that we need to continue, we are going to start with all the magic of GraphQL.

Types:

This is where we define what we want to respond to the user that is making the request, we can add some validations there and also we can define what type of data we are going to return.\

There are different type of types, we should import those from graphql and set what kind of data is the one that we are returning.

and set what kind of data is the one that we are returning. Each type must be a GraphQLObjectType which will have multiple properties, like name and fields (the values that the user will get when it is returned).

which will have multiple properties, like name and fields (the values that the user will get when it is returned). Each field must have a type (where we set the type that we imported earlier) and also it can have a resolve.

Resolve: it is a function that receives 3 arguments, the actual object, the arguments and the context, inside the resolve we can handle different logics, like the auth middleware that checks if the token is valid; also when we return a value, we can return a promise without resolve it, GraphQL will handle it.

schema/types/me.js:

const {

GraphQLID,

GraphQLObjectType,

GraphQLString,

GraphQLNonNull

} = require('graphql') const MeType = new GraphQLObjectType({

name: 'Me',

fields: () => {

return {

id: { type: GraphQLNonNull(GraphQLID) },

email: { type: GraphQLNonNull(GraphQLString) },

username: { type: GraphQLNonNull(GraphQLString) },

apiKey: { type: GraphQLNonNull(GraphQLString) }

}

}

}) module.exports = MeType

When we are going to use the meType; we can ask the query to return:

email: it is a string that can’t be null.

username: it is a string that can’t be null.

apiKey: it is a string that can’t be null.

schema/types/places.js:

const {

GraphQLObjectType,

GraphQLString,

GraphQLNonNull,

} = require('graphql') const PlacesType = new GraphQLObjectType({

name: 'Place',

fields: () => {

return {

place: { type: GraphQLNonNull(GraphQLString) },

}

}

}) module.exports = PlacesType

When we are going to use the PlacesType; we can ask the query to return:

place: it is a string that can’t be null.

schema/types/users.js:

const {

GraphQLObjectType,

GraphQLString,

GraphQLNonNull,

GraphQLList

} = require('graphql') const { verifyJwt } = require('../../utils')

const pgdb = require('../../models/pgdb') const UsersType = new GraphQLObjectType({

name: 'Users',

fields: () => {

const PlacesType = require('./places')

return {

email: { type: GraphQLNonNull(GraphQLString) },

username: { type: GraphQLNonNull(GraphQLString) },

visitedPlaces: {

type: new GraphQLList(PlacesType),

resolve: async (obj, args, { pgPool, req }) => {

try {

await verifyJwt(req)

return pgdb(pgPool).getVisitedPlaces(obj.id)

} catch (err) {

return []

}

}

}

}

}

}) module.exports = UsersType

This type is a little different from the others ones.

We require verifyJwt ; it will be used to verify if the token that we pass is valid or not, in case that it is not valid, we are going to return an empty array in visited places.

The other new thing that you might notice is that we are using GraphQLList and resolve .

GraphQLList will let know GraphQL that we want to return a list (array) of placesType.

Resolve is going to be async/await because we want to check first if the token is valid or not, so we are passing (obj, args, { pgPool, req }) `as arguments, where the obj is the whole response that we got from users, pgPool is the pool to the database that we set on App.js and req is the request from express. Then we verify if the token is valid, and in case that it is, we search on the database all the visited places that the user have and return them.

Queries:

The queries are where we want to set the /GET that we want to let GraphQL do to our database, we set in the query the type of response that we want to give, so we can be sure which data we want to share.

schema/queries/getUser.js:

const { GraphQLID, GraphQLNonNull } = require('graphql') const UserType = require('../types/users')

const pgdb = require('../../models/pgdb') module.exports = {

type: UserType,

description: 'This query will search for a user with userId',

args: {

userId: { type: new GraphQLNonNull(GraphQLID) }

},

resolve (obj, { userId }, { pgPool, req }) {

return pgdb(pgPool).getUserById(userId)

}

}

The query is going to have a type that we already defined on types; the description that is optional; args is optional and it is an object with the arguments that the query will receive, also, it must have a type; and resolve where we do all the logic to response, in this case, the query is waiting to get the userId and it will make a query to the database with it.

Mutations:

The mutations are the queries that let us save info to the database. We set in the mutation the type of response that we want to give, so we can be sure which data we want to share.

schema/mutations/addUser.js:

const {

GraphQLInputObjectType,

GraphQLString,

GraphQLNonNull

} = require('graphql') const pgdb = require('../../models/pgdb')

const MeType = require('../types/me') const UserInputType = new GraphQLInputObjectType({

name: 'UserInput',

fields: {

email: { type: GraphQLNonNull(GraphQLString) },

username: { type: GraphQLNonNull(GraphQLString) }

}

}) module.exports = {

type: MeType,

description: 'This mutation will create a new user and it will

return a apiKey',

args: {

input: { type: new GraphQLNonNull(UserInputType) }

},

resolve: async (obj, { input }, { pgPool }) => {

return pgdb(pgPool).addNewUser(input)

}

}

We need to define the GraphQLInputObjectType that is the type that we are going to receive on the args.

schema/mutations/addVisitedPlaces.js:

const {

GraphQLInputObjectType,

GraphQLID,

GraphQLString,

GraphQLNonNull

} = require('graphql') const { verifyJwt } = require('../../utils')

const pgdb = require('../../models/pgdb')

const UsersType = require('../types/users') const VisitedInputType = new GraphQLInputObjectType({

name: 'VisitedInput',

fields: {

userId: { type: GraphQLNonNull(GraphQLID) },

place: { type: GraphQLNonNull(GraphQLString) }

}

}) module.exports = {

type: UsersType,

description: 'This mutation will add a new visited place',

args: {

input: { type: new GraphQLNonNull(VisitedInputType) }

},

resolve: async (obj, { input }, { pgPool, req }) => {

await verifyJwt(req)

await pgdb(pgPool).addNewVisitedPlace(input)

return pgdb(pgPool).getUserById(input.userId)

}

}

First, we want to verify if the token is valid before saving a new visited place in the database after we validate it we save the info and then we respond with the data of the user and the visited places. In case that the token is not valid it will return an error with 401: User is not authenticated .

schema/index.js:

const { GraphQLSchema, GraphQLObjectType } = require('graphql')

const GetUser = require('./queries/getUser') const AddNewUserMutation = require('./mutations/addUser')

const AddVisitedPlaceMutation = require('./mutations/addVisitedPlace') const RootQueryType = new GraphQLObjectType({

name: 'RootQuery',

fields: () => ({

user: GetUser

})

}) const RootMutationType = new GraphQLObjectType({

name: 'RootMutation',

fields: () => ({

AddUser: AddNewUserMutation,

AddVisitedPlace: AddVisitedPlaceMutation

})

}) const ncSchema = new GraphQLSchema({

query: RootQueryType,

mutation: RootMutationType

}) module.exports = ncSchema

Now we want to define how we want our GraphQLSchema , so, we create a GraphQLObjectType for queries and other for mutations than will be used in: