Некоторое время назад я работал над мобильным приложением, функционал которого включал в себя удобный онлайн-чат. И теперь я решил написать статью с краткой инструкцией, как создать чат, используя apollo server и node.js на бэкенде, а так же react native и apollo client на клиентской части.
Статья разбита на две части для удобства прочтения. В первой части содержится гайд по созданию бэкенд приложения, а во второй — гайд по созданию фронтенд приложения.
Если вам лень читать, можно сразу посмотреть код в Github’e здесь и здесь.
В качестве основных технологий для реализации я выбрал node.js фреймворк koa, базу данных postgresql, а так же GraphQL сервер — apollo-server-koa.
Первым делом, был сгенерирован пустой koa2 проект, для этого я использовал простой koa-generator, выполнив в терминале команду:
Далее были установлены необходимые зависимости, я делаю это с помощью yarn, но вы можете воспользоваться npm.
Для подключения к БД нужно описать два файла, первый из них — db.js, который будет экспортировать инстанс клиента knex и позволит нашим моделям работать с даннными из базы, второй — knexfile.js, который содержит в себе настройки подключения к БД для создания и накатывания миграций.
Код db.js описан ниже, обратите внимание, что все настройки берутся из переменных окружения:
Код knexfile.js доступен по ссылке.
Сами таблицы будут максимально просты и содержать лишь минимальный необходимый набор полей. Команда для их создания ниже:
Посмотреть файлы миграций можно по ссылке.
Осталось самое интересное — подключение и настройка apollo-server-koa, описание graphql схемы и резолверов.
app.js:
www:
Помимо подключения apollo-server-koa, мы включили возможность работы с подписками для оповещения клиентов о том, что в чате пришло новое сообщение.
Пример резолвера для отправки нового сообщения:
Интересный момент — помимо сохранения сообщения в БД, здесь вызывается функция publish() которая оповещает всех подписчиков о событии MESSAGE_CREATED, отправляя им объект нового сообщения (внимательный читатель заметит, что отправитель тоже будет оповещен о своем же новом сообщении, и мы обработаем это далее на клиенте, в реальном же проекте имеет смысл обработать это на стороне бекенда, чтобы не дублировать логику среди различных клиентов).
С кодом оставшихся резволеров можно ознакомиться по ссылке.
Откройте хост в своем браузере и в нем вы увидите graphql playground.
В следующей части мы займемся созданием мобильного приложения.
Статья разбита на две части для удобства прочтения. В первой части содержится гайд по созданию бэкенд приложения, а во второй — гайд по созданию фронтенд приложения.
Если вам лень читать, можно сразу посмотреть код в Github’e здесь и здесь.
В качестве основных технологий для реализации я выбрал node.js фреймворк koa, базу данных postgresql, а так же GraphQL сервер — apollo-server-koa.
Первым делом, был сгенерирован пустой koa2 проект, для этого я использовал простой koa-generator, выполнив в терминале команду:
$ koa <project name>
Далее были установлены необходимые зависимости, я делаю это с помощью yarn, но вы можете воспользоваться npm.
$ yarn add apollo-server-koa knex objection pg
Все необходимые библиотеки установлены, теперь можно писать код
Для подключения к БД нужно описать два файла, первый из них — db.js, который будет экспортировать инстанс клиента knex и позволит нашим моделям работать с даннными из базы, второй — knexfile.js, который содержит в себе настройки подключения к БД для создания и накатывания миграций.
Код db.js описан ниже, обратите внимание, что все настройки берутся из переменных окружения:
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;
Код knexfile.js доступен по ссылке.
Теперь можно описать миграции для создания двух необходимых нам таблиц
Сами таблицы будут максимально просты и содержать лишь минимальный необходимый набор полей. Команда для их создания ниже:
$ knex migrate:make migration_name
Посмотреть файлы миграций можно по ссылке.
Теперь создадим модели сущностей Message и 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'
}
}
};
}
}
Осталось самое интересное — подключение и настройка apollo-server-koa, описание graphql схемы и резолверов.
Для подключения apollo-server-koa достаточно добавить следующие строки кода
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);
Помимо подключения apollo-server-koa, мы включили возможность работы с подписками для оповещения клиентов о том, что в чате пришло новое сообщение.
Apollo-server-koa подключен, следующий шаг — описание graphql-схемы с необходимыми для чата типами
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
}
Схема готова, опишем резолверы
Пример резолвера для отправки нового сообщения:
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;
},
};
Интересный момент — помимо сохранения сообщения в БД, здесь вызывается функция publish() которая оповещает всех подписчиков о событии MESSAGE_CREATED, отправляя им объект нового сообщения (внимательный читатель заметит, что отправитель тоже будет оповещен о своем же новом сообщении, и мы обработаем это далее на клиенте, в реальном же проекте имеет смысл обработать это на стороне бекенда, чтобы не дублировать логику среди различных клиентов).
С кодом оставшихся резволеров можно ознакомиться по ссылке.
Серверная часть чата готова, как проверить, что все работает?
Откройте хост в своем браузере и в нем вы увидите graphql playground.
В следующей части мы займемся созданием мобильного приложения.