Creating a backend application for Apollo online chat, Node.js

Some time ago I was working on a mobile application, the functionality of which included a convenient online chat. And now I decided to write an article with a brief instruction on how to create a chat using apollo server and node.js on the backend, as well as react native and apollo client on the client side.



The article is divided into two parts for easy reading. The first part contains a guide for creating an application backend, and the second part contains a guide for creating an application frontend.



If you are too lazy to read, you can immediately see the code in Github'e here and here .



As the main technologies for implementation, I chose the node.js koa framework, the postgresql database, and also the GraphQL server - apollo-server-koa .



First of all, an empty koa2 project was generated, for this I used a simple koa-generator by running the command in the terminal:



$ koa <project name>
      
      





Next, the necessary dependencies were installed, I do this with yarn, but you can use npm.



 $ yarn add apollo-server-koa knex objection pg
      
      





All necessary libraries are installed, now you can write code



To connect to the database, you need to describe two files, the first one is db.js, which will export the knex client instance and allow our models to work with data from the database, the second is knexfile.js, which contains the database connection settings for creating and rolling migrations.



The db.js code is described below, note that all settings are taken from environment variables:



 const db = require('knex')({ client: 'pg', connection: {   host : process.env.POSTGRES_HOST,   port: process.env.POSTGRES_PORT,   user : process.env.POSTGRES_USER,   password : process.env.POSTGRES_PASSWORD,   database : process.env.POSTGRES_DATABASE } }); module.exports = db;
      
      





The code knexfile.js is available here .



Now you can describe the migrations to create the two tables we need.



The tables themselves will be as simple as possible and contain only the minimum required set of fields. The command to create them is below:



 $ knex migrate:make migration_name
      
      





You can view the migration files here .



Now create the entity models Message and User



 class Message extends Model { static get tableName() {   return 'messages'; } $beforeInsert() {   this.created_at = new Date().toISOString(); } static get relationMappings() {   return {     user: {       relation: Model.BelongsToOneRelation,       modelClass: User,       join: {         from: 'messages.user_id',         to: 'users.id'       }     }   }; } }
      
      





The most interesting thing remained - connecting and configuring apollo-server-koa, description of graphql schemes and resolvers.



To connect apollo-server-koa, just add the following lines of code



app.js:



 const { ApolloServer } = require('apollo-server-koa'); const graphqlSchema = require('./graphqlSchema'); … const apolloServer = new ApolloServer(graphqlSchema); apolloServer.applyMiddleware({ app });
      
      





www:



 var { app, apolloServer } = require('../app'); ... apolloServer.installSubscriptionHandlers(server);
      
      





In addition to connecting apollo-server-koa, we have included the ability to work with subscriptions to notify customers that a new message has arrived in the chat.



Apollo-server-koa is connected, the next step is a description of the graphql-scheme with the types necessary for chat



 input UserInput { username: String! } input MessageInput { text: String! user_id: ID! } type User { id: ID username: String } type Message { id: ID text: String created_at: String user: User } type Query { getLast100Messages: [Message] } type Mutation { findOrCreateUser(user: UserInput!): User createMessage(message: MessageInput!): Message } type Subscription { messageCreated: Message }
      
      





The circuit is ready, we describe the resolvers



An example of a resolver for sending a new message:



 const Message = require('../../models/message'); const { pubsub, MESSAGE_CREATED } = require('../../utils'); module.exports = { createMessage: async (obj, { message }, context, info) => {   const createdMessage = await Message     .query()     .insert(message);   const resultMessage = await Message     .query()     .eager('user')     .findById(createdMessage.id);   pubsub.publish(MESSAGE_CREATED, { messageCreated: resultMessage });   return resultMessage; }, };
      
      





An interesting point is that in addition to saving the message in the database, the publish () function is called here, which notifies all subscribers about the MESSAGE_CREATED event, sending them the object of a new message (the attentive reader will notice that the sender will also be notified of his new message, and we will process this further on to the client, in a real project, it makes sense to process this on the backend side, so as not to duplicate the logic among different clients).



The code of the remaining resolvers can be found here .



The server side of the chat is ready, how can I verify that everything is working?



Open the host in your browser and you will see graphql playground in it.



image



In the next part, we will create a mobile application.



All Articles