DEV Community

Cover image for My own realtime chat with react, graphql and postgresql [part 3-Graphql schemas]
David Alejandro Quiñonez
David Alejandro Quiñonez

Posted on • Updated on

My own realtime chat with react, graphql and postgresql [part 3-Graphql schemas]

The funny part is about to begin.
Alt Text

In this section we are going to set our graphql queries, and schemas so them matches the sql models created on the first part, and the authentication setted on the second part.

Now we can create a folder graphql to wrap the users and messages schemas.

./graphql/schemas/messages.schema.js

const MESSAGE_TYPES = `
  type Message { id: String, text: String, date: String, usr: String }
`;

module.exports = { MESSAGE_TYPES };
Enter fullscreen mode Exit fullscreen mode

./graphql/schemas/users.schema.js

const USERS_TYPES = `
  type User { usr: String, name: String, type: String, password_digested:String, token: String }
`;

module.exports = { USERS_TYPES };

Enter fullscreen mode Exit fullscreen mode

This schemas are only objects that matches the types defined in the sql section for the messages and users.

Now we can use these schemas to implement mutations and queries with the graphql api apollo.

./graphql/index.js

const { USERS_TYPES } = require("./schemas/users.schema");
const { MESSAGE_TYPES } = require("./schemas/messages.schema");
const { getMessages, addMessage } = require("../data/sql/messages");
const { signin, signup, findUser } = require("../data/sql/users");

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

Enter fullscreen mode Exit fullscreen mode

First lets take a look to these weird graphqlrequires.

gql query parser, it allows us to write queries in string format.
PubSub is the magic package that will help us to get the real time functionality. It uses socket subscriptions under the hood to achive that.

Now let's create the mutations!

const pubsub = new PubSub();

const QUERY = gql`
  type Query {
    user(usr: String): User
    messages: [Message]
  }
`;

const MUTATION = gql`
  type Mutation {
    createMessage(text: String, date: String, usr: String): Message
    signInUser(usr: String, password: String): User
    signUpUser(usr: String, name: String, password: String, type: String): User
  }
`;

const SUBSCRIPTION = gql`
  type Subscription {
    messageAdded: Message
  }
`;

const typeDefs = [QUERY, MUTATION, SUBSCRIPTION, USERS_TYPES, MESSAGE_TYPES];
Enter fullscreen mode Exit fullscreen mode

Let's analize this code:

  1. We create a new instance of the PubSub object.

  2. The QUERY constant is a graphql query that defines how our server is going to search for users and messages.

  3. The MUTATION constant is a graphql mutation that defines 3 functions createMessage, signInUser, signUpUser, and the parameters these functions requires.

  4. The SUBSCRIPTION constant is a graphql subscription that will be our connection to the real time messages stream.

  5. The typeDefs is an object required by the graphql server in order to show documentation, and basically this is how the server knows what it can query and mutate.

Now we can actually add funcionality to those things defined before:

const resolvers = {
  Subscription: {
    messageAdded: {
      subscribe: () => {
        return pubsub.asyncIterator(["MESSAGE_ADDED"]);
      },
    },
  },
  Mutation: {
    signInUser: async (parent, args) => {
      return await signin({ ...args });
    },
    signUpUser: async (parent, args) => {
      return await signup({ ...args });
    },
    createMessage: async (parent, args) => {
      pubsub.publish("MESSAGE_ADDED", {
        messageAdded: { ...args },
      });
      return await addMessage({ ...args });
    },
  },
  Query: {
    messages: async () => {
      return await getMessages();
    },
    user: async (paretn, args) => {
      return await findUser(args.usr);
    },
  },
};

module.exports = { typeDefs, resolvers };

Enter fullscreen mode Exit fullscreen mode
  1. The resolvers object is, as the typeDefs object, used by the server. Basically are the functions executed by the server.

  2. The Subscription object is composed by a subscription to the 'MESSAGE_ADDED' topic. This means each time this topic is used for something (like adding a new message), the messageAdded subscription will notice.

  3. The Mutation object is composed by the 3 functions defined on the typeDefs. These functions in turn use the functions of signin, signup, and addMessage. The args parameter should match the defined on the typeDefs.
    3.1 The createMessage function is using the pubsub object to subscribe into a topic called 'MESSAGE_ADDED'.

  4. The Query object is returning whatever that is on the messages table and the user info given an username.

  5. Finally we can export the typeDefs and the resolvers so we can start our server.

In the next part we'll be setting up the final details to start our server and run some manual tests to check if everything is ok.

Top comments (0)