2018-08-28
Введение.
Этот проект был написан чтобы продемонстрировать возможности работы "Feathers" фреймворка. По своей сути Feathers представляет собой набор инструментов и шаблон архитектуры, который упрощает создание масштабируемых API REST приложений реального времени. Сравнение с другими фреймворками можно посмотреть здесь.
Этот проект на GitHub можно посмотреть здесь
Демонстрацию этого проекта можно посмотреть здесь
Обзор
Основная идея Feathers фреймворка уйти от концепции MVC и использовать концепцию работы с сервисами и “hooks”. Это дало возможность создать структуру, которая может расти вместе с вами по мере роста вашего продукта. Он достаточно гибкий, чтобы быстро адаптироваться к меняющимся потребностям бизнеса, достаточно мощный для создания современных приложений и достаточно простой, чтобы быстро создавать и работать.
Возможности
- Работа с сервисами на стороне сервера и на стороне клиента
- Использование “Hooks” при работе с сервисами
- Создание Real-time APIs
- Процесс аутентификации и авторизации создан на базе Express Password стратегий
- JWT Authentication используется JSON Web Token
- Local Authentication используется Email и Password
- OAuth 1.0a Authentication через Twitter
- OAuth 2.0 Authentication через Facebook, Google, GitHub, Instagram
- Работа с базами данных: NeDB, MongoDB, Elasticsearch, RethinkDB
- Работа с базами данных: MySQL, PostgreSQL, MariaDB, SQLite, MSSQL (с помощью ORM - Knex, Sequelize)
- Пользовательский интерфейс выполнен на базе клиенского фрейморка "Bulma"
- Gravatar
- Реализован пример Chat (обмена сообщениями между пользователями) в реальном времени
Ресурсы
- Node.js (Chrome's V8 JavaScript engine)
- Документация
- Express (Node.js framework)
- Документация
- API
- Passport.js
- Документация
- Feathers
- Документация
- Блог
- Ресурсы, плагины, примеры
- Блог
- Клиентский фреймворк "Bulma"
- Документация
- Схемы
- Шаблоны
- Расширения
- Схемы
- Font Awesome - the iconic font and CSS toolkit
- Icons
- MongoDB (noSQL DataBase)
- Документация
- Atlas (облачный хостинг)
- mLab (облачный хостинг 500MB FREE)
- Сompass (инструмент для визуализации данных)
- Mongoosejs (NPM компонент для работы с моделями базы данных)
- Atlas (облачный хостинг)
- NeDB (noSQL DataBase)
- Документация
- ElasticSearch (noSQL DataBase)
- Документация
- Bonsai - hosting for ElasticSearch
- RethinkDB (noSQL DataBase)
- Документация
- Knex (SQL DataBase ORM for Postgres, MSSQL, MySQL, MariaDB, SQLite3, Oracle)
- Документация
- Sequelize (SQL DataBase ORM for PostgreSQL, MySQL, SQLite and MSSQL)
- Документация
- Интересные статьи
- Why we built the best web framework you’ve probably never heard of (until now)
- Feathers.js — реактивный JavaScript-фреймворк поверх Express
Установка приложения
Предварительные требования
Убедитесь в том, что у вас установлен NodeJS 8.0+ и MongoDB, RethinkDB, Elasticsearch.
Клонируйте или загрузите feathers-exx проект с GitHub.
- Инсталируйте ваши зависимости
cd <project-name> npm install # Or yarn install
Переменные окружения
Файл .env
должен находиться в корне проекта, если он отсутствует, то его нужно создать на основе примера файла .env.example
, иначе приложение будет выдавать ошибку. Файл .env
устанавливает переменные окружения. В переменных окружения обычно указываются секретные данные пользователя например user_id, user_secret и т.д.
Запуск вашего проекта
Development
Вначале нужно создать пакет клиентского приложения для этого нужно выполнить команду:npm run build
илиnpm run watch
чтобы работать с MongoDB базой данных нужно выполнить командуnpm run start-mongod
чтобы работать с RethinkDB базой данных нужно выполнить командуnpm run start-rethinkdb
чтобы работать с ElasticSearch базой данных нужно вначале установить локально ElasticSearch, а затем запустить ее на выполнение... После этого нужно выполнить приложение в режиме разработки.npm run dev
Приложение будет запущено в режиме Разработки и будет выполнятся на http://localhost:3000
Production
npm start
Приложение будет запущено в Рабочем режиме и будет выполнятся на рабочем хостинге пример можно посмотреть здесь
Структура приложения
Файловая структура
пр.1Имя файла | Описание |
---|---|
client/public | Папка для публичных данных (css, js, images). |
client/scr/js/app.client.js | Основная точка входа клиентского приложения. |
client/scr/js/client.class.js | Client класс |
client/scr/js/polyfills.js | Модуль где собраны необходимые полифилы для клиента |
client/scr/js/controllers | Папка с контроллерами для клиента. |
client/scr/js/plugins | Папка с плагинами для клиента. |
client/scr/js/routes | Папка с роутерами для клиента. |
client/scr/js/tmpls | Папка с шаблонами для клиента. |
config/db/mongod.config.yml | Конфигурация базы данных MongoDB. |
config/db/rethinkdb.config | Конфигурация базы данных RethinkDB. |
config/default.json | Конфигурация приложения по умолчанию. |
config/production.json | Конфигурация приложения в режиме "Production". |
plugins/utils.class.js | Utils класс для общих функций сервера и клиента. |
server/app.server.js | Модуль инициализации серверного приложения. |
server/start.js | Основная точка входа серверного приложения. |
server/boot | Папка с модулями промежуточных обработчиков для инициализации сервера. |
server/controllers | Папка с контроллерами для сервера. |
server/data/db | Папка с базами данных: MongoDB, NeDB, RethinkDB, Sqlite3. |
server/data/log | Папка c логами для сервера. |
server/hooks | Папка с "Hooks" для сервера. |
server/middleware | Папка с "middleware" для сервера. |
server/plugins | Папка с плагинами для сервера. |
server/routes | Папка с роутерами для сервера. |
server/services | Папка с сервисами для сервера. |
server/views | Папка с шаблонами для сервера. |
validations | Папка со схемами валидации для сервера и клиента. |
.env | Ваши реальные API ключи, уникальные данные, пароли и URI базы данных. |
.env.example | Примеры API ключей, уникальных данных, паролей и URI базы данных. |
.gitignore | Папки и файлы, которые будут игнорироваться системой управления версиями Git. |
package.json | NPM зависимости. |
package-lock.json | Содержит точные версии зависимостей NPM в package.json. |
Procfile | Файл для конфигурации хостинга "Heroku". |
README.md | Информация о приложении. |
webpack.config.js | Конфигурация для WebPack. |
Замечание: Здесь представлен мой вариант организации структуры приложения. Вы можете изменять структуру приложения по своему усмотрению...
Список NPM пакетов
пр.2Пакет | Описание |
---|---|
Dependencies | |
@feathersjs/authentication | Feathers local, token, and OAuth authentication over REST and Websockets using JSON Web Tokens (JWT) with PassportJS. |
@feathersjs/authentication-jwt | JWT authentication strategy for feathers-authentication using Passport. |
@feathersjs/authentication-local | Local authentication strategy for feathers-authentication using Passport. |
@feathersjs/authentication-oauth1 | An OAuth1 authentication strategy for feathers-authentication using Passport. |
@feathersjs/authentication-oauth2 | An OAuth2 authentication strategy for feathers-authentication using Passport. |
@feathersjs/authentication-client | The authentication plugin for feathers-client. |
@feathersjs/configuration | A plugin for configuring a Feathers application. |
@feathersjs/errors | Feathers errors for server and client. |
@feathersjs/express | Feathers Express framework bindings and REST transport plugin. |
@feathersjs/feathers | A REST and realtime API layer for modern applications. |
@feathersjs/socketio | The Feathers Socket.io websocket transport plugin. |
ajv | The fastest JSON Schema validator for Node.js and browser. Supports draft-04/06/07. |
axios | Promise based HTTP client for the browser and node.js. |
babel-polyfill | Browser Polyfill for Babel. |
body-parser | Node.js body parsing middleware. |
browser-cookies | Tiny cookies library for the browser. |
compression | Node.js compression middleware. |
cookie-parser | Parse HTTP request cookies. |
cors | Node.js CORS middleware. |
cross-env | Cross platform setting of environment scripts. |
debug | A tiny JavaScript debugging utility modelled after Node.js core's debugging technique. Works in Node.js and web browsers. |
dotenv | Loads environment variables from .env for nodejs projects. |
dotenv-webpack | A secure webpack plugin that supports dotenv and other environment variables and only exposes what you choose and use. |
elasticsearch | Open Source, Distributed, RESTful Search Engine. |
express | Fast, unopinionated, minimalist web framework for node. |
express-session | Simple session middleware for Express. |
feathers-elasticsearch | Feathersjs adapter for Elasticsearch. |
feathers-hooks-common | Useful hooks for use with Feathersjs services. |
feathers-knex | Service adapters for KnexJS a query builder for PostgreSQL, MySQL, MariaDB, Oracle and SQLite3. |
feathers-localstorage | A client side service based on feathers-memory that persists to LocalStorage. |
feathers-memory | An in memory feathers service. |
feathers-mongodb | A mongodb service for feathers. |
feathers-mongoose | Easily create a Mongoose Service for Feathersjs. |
feathers-nedb | A service using NeDB, an embedded datastore for Node.js. |
feathers-rethinkdb | A Feathers service adapter for RethinkDB. |
feathers-sequelize | A Feathers service adapter for the Sequelize ORM. Supporting MySQL, MariaDB, Postgres, SQLite, and SQL Server. |
fetch-polyfill | A window.fetch JavaScript polyfill. |
helmet | Help secure Express apps with various HTTP headers. |
highlight.js | Javascript syntax highlighter. |
jstorage | jStorage is a simple key/value database to store data on browser side. |
knex | A query builder for PostgreSQL, MySQL and SQLite3, designed to be flexible, portable, and fun to use. |
lodash | A modern JavaScript utility library delivering modularity, performance, & extras. |
moment | Parse, validate, manipulate, and display dates in javascript. |
mongodb | MongoDB Abstraction Layer. |
mongoose | MongoDB object modeling designed to work in an asynchronous environment. |
morgan | HTTP request logger middleware for node.js. |
mysql | A pure node.js JavaScript Client implementing the MySql protocol. |
mysql2 | A modern, simple and very fast Mysql library for Ruby - binding to libmysql. |
nedb | The JavaScript Database, for Node.js, nw.js, electron and the browser. |
passport-facebook | Facebook authentication strategy for Passport and Node.js. |
passport-github | GitHub authentication strategy for Passport and Node.js. |
passport-google-oauth20 | Types for https://github.com/jaredhanson/passport-google-oauth2. |
passport-instagram | Instagram authentication strategy for Passport and Node.js. |
passport-twitter | Twitter authentication strategy for Passport and Node.js. |
rethinkdbdash | An advanced Node.js driver for RethinkDB with a connection pool, support for streams etc. |
sequelize | An easy-to-use multi SQL dialect ORM for Node.js. |
serve-favicon | favicon serving middleware. |
socket.io-client | Realtime application framework (client). |
sqlite3 | sqlite3 driver for go using database/sql. |
twig | Twig, the flexible, fast, and secure template language. |
devDependencies | |
babel-core | Babel is a compiler for writing next generation JavaScript. |
babel-loader | Webpack plugin for Babel. |
babel-preset-env | A Babel preset that compiles ES2015+ down to ES5 by automatically determining the Babel plugins and polyfills you need based on your targeted browser or runtime environments. |
bulma | Modern CSS framework based on Flexbox. |
bulmaswatch | Themes for Bulma. |
css-loader | CSS Loader for Webpack. |
node-sass | Node.js bindings to libsass. |
nodemon | Monitor for any changes in your node.js application and automatically restart the server - perfect for development. |
style-loader | Style Loader for Webpack. |
twig-loader | Webpack loader for compiling Twig.js templates. |
webpack | Webpack is a module bundler. |
Конфигурация
.env
Файл .env
должен находиться в корне проекта, если он отсутствует, то его нужно создать на основе примера файла .env.example
, иначе приложение будет выдавать ошибку. Файл .env
устанавливает переменные окружения. В переменных окружения обычно указываются секретные данные пользователя например user_id, user_secret и т.д.
### System ###
NODE_ENV=development
# default(Bulma as-is); cerulean(A calm blue sky); darkly(Flatly in night-mode)
COLOR_THEME=darkly
DEBUG=app:*
### HTTP ###
BASE_URL=http://localhost
### AUTH ###
SESSION_SECRET=expressFeathersExxSecretKey
AUTH_SECRET=13e504e1023381f2475b895183ca6fa0e3858d4302083695d708a159ea7979dbe780d2c0207e86f5c9e48cbea177caf2ba36f6821e648afcf14017ddbca3a20b8f2918608c8422f67dcd70fb9b2c7d60d92edf2aa95fd3ed26fd2aaff2a67319dd395a71aab1cab1578ab5757474904fca6f954835dce764dc17950952740db129bbbc3ce5e76b06fc36ef93d09699ccb3a68df2e5cd5a39412c1e8952d5feaaba779a3f638366176493cc7387e0c52e009a3f1b7383f3b5fcc528e4754419cfa3730550e72343b8b7adfbd2148323cfc34c411329245d9c979b98489025f074af28e72e54875e295933861e60dad850be57f0c2e68e4b16a163f2435c126988
FACEBOOK_ID=XXXXXXXXXXXXXXX
FACEBOOK_SECRET=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
INSTAGRAM_ID=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
INSTAGRAM_SECRET=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
GITHUB_ID=XXXXXXXXXXXXXXXXXXXX
GITHUB_SECRET=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
TWITTER_KEY=XXXXXXXXXXXXXXXXXXXXXXXXX
TWITTER_SECRET=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
GOOGLE_ID=XXXXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.apps.googleusercontent.com
GOOGLE_SECRET=XXXXXXXXXXXXXXXXXXXXXXXX
### Personal Data ###
PERSONAL_LOGO_IMAGE=/images/bsa-logo/4_bsa-logo_229x75.png
PERSONAL_COPYRIGHT=© 2018 BSA Lab.
PERSONAL_WEBSITE=http://bsa-git.github.io
### DataBase ###
# sqlite, mysql, postgres, mssql
DB_CURRENT=sqlite
DB_NEDB_FILENAME=/server/data/db/nedb/messages.db
DB_MONGOOSE_URI=mongodb://localhost:27017/dbFeathersExx
DB_MONGODB_URI=mongodb://localhost:27017/dbFeathersExx
DB_ELASTICSEARCH_URI=http://localhost:9200
DB_ELASTICSEARCH_INDEX=db_feathers_exx
DB_ELASTICSEARCH_TYPE=messages
DB_RETHINKDB_DATABASE=dbFeathersExx
DB_RETHINKDB_TABLE=messages
DB_KNEX_SQLITE_FILENAME=/server/data/db/sqlite3/messages.db
DB_KNEX_MYSQL_HOST=localhost
DB_KNEX_MYSQL_USER=root
DB_KNEX_MYSQL_PASSWORD=
DB_KNEX_MYSQL_DATABASE=dbFeathersExx
DB_KNEX_POSTGRES_HOST=localhost
DB_KNEX_POSTGRES_USER=your_database_user
DB_KNEX_POSTGRES_PASSWORD=your_database_password
DB_KNEX_POSTGRES_DATABASE=myapp_test
DB_SEQUELIZE_SQLITE_DATABASE=messages
DB_SEQUELIZE_SQLITE_USERNAME=
DB_SEQUELIZE_SQLITE_PASSWORD=
DB_SEQUELIZE_SQLITE_STORAGE=/server/data/db/sqlite3/messages.db
DB_SEQUELIZE_MYSQL_URI=mysql://root@localhost:3306/dbFeathersExx
DB_SEQUELIZE_MYSQL_DATABASE=dbFeathersExx
DB_SEQUELIZE_MYSQL_USERNAME=root
DB_SEQUELIZE_MYSQL_PASSWORD=
DB_SEQUELIZE_MYSQL_HOST=localhost
DB_SEQUELIZE_MYSQL_PORT=3306
DB_SEQUELIZE_POSTGRES_URI=postgres://user:pass@example.com:5432/dbname
DB_SEQUELIZE_POSTGRES_DATABASE=myapp_test
DB_SEQUELIZE_POSTGRES_USERNAME=user
DB_SEQUELIZE_POSTGRES_PASSWORD=pass
DB_SEQUELIZE_POSTGRES_HOST=localhost
Замечание: Чтобы иметь реальные ключи для доступа к API различных сервисов нужно зарегистрировать ваше приложение в этих сервисах. Примеры регистрации приложения и получения ключей API в разных сервисах можно посмотреть здесь.
Работа серверного приложения
- В приложении демонстрируется работа фреймворка Feathers в трех аспектах: работа с сервисами, работа с базами данных и аутентификация пользователей.
- В примерах показана работа с различными базами данных.
Например в приложении я использую базу данных MongoDB. Можно установить MongoDB локально на компьютер или использовать MongoDB на облачном хостинге Atlas или mLab.
Также используется база данных ElasticSearch Можно установить ElasticSearch локально на компьютер или использовать ElasticSearch на облачном хостинге Bonsai - hosting for ElasticSearch.
Используется база данных RethinkDB Можно установить RethinkDB локально на компьютер, а вот бесплатного хостинга для RethinkDB я пока не нашел...
Для Knex (SQL DataBase ORM for Postgres, MSSQL, MySQL, MariaDB, SQLite3, Oracle) и для Sequelize (SQL DataBase ORM for PostgreSQL, MySQL, SQLite and MSSQL) я использую бузу данных - SQLite3, которая находиться в папке
/server/data/db/sqlite3
в виде файлаmessages.db
База данных NeDB находится в папке
/server/data/db/nedb
в виде файловmessages.db, users.db, posts.db
. Файл messages.db используется для демонстрации работы с сервисами, а файлы users.db, posts.db используются для демонстрации аутентификации пользователей и демонстрации приложения Chat (обмен сообщениями между пользователями). - Чтобы тестировать в приложении возможность логирования с помощью таких сервисов как Facebook, Google, GitHub, Instagram и т.д. нужно быть там зарегистрированным и иметь свой аккаунт.
- Если вы разработчик и хотите создавать приложения с возможностью логирования и доступа других пользователей к API различных сервисов, нужно зарегистрировать ваше приложение в этих сервисах. Примеры регистрации приложения и получения ключей API в разных сервисах можно посмотреть здесь
- Для построения пользовательского интерфейса используется Bulma, это один из популярных HTML, CSS фреймворков и используется, для разработки интерактивных мобильных проектов в Интернете.
Инициализация серверного приложения
Инициализация приложения происходит в модуле server/app.server.js
см. пр.4
"use strict";
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const configuration = require('@feathersjs/configuration');
const dotenv = require('dotenv');// Loads environment variables from .env file.
const debug = require('debug')('app:app');
// Load environment variables
dotenv.load();
// Create APP
const app = express(feathers());
app.configure(configuration());
// Boot
require('./boot/index')(app);
// Routing
require('./routes/index')(app);
debug('Bootstrap application - OK');
module.exports = app;
Из структуры модуля app.server.js
видно, что происходят следующие действия:- Загрузка переменных окружения из файла .env.
- Создание самого приложения app и его конфигурация. Данные по конфигурации берутся из файлов
config/default.json, config/production.json
и сохраняются в приложении app. Их можно получить например так.app.get('authentication')
. - Установка промежуточных обработчиков в приложение в модуле
server/boot/index.js
. - Установка и настройка путей запросов в приложение в модуле
server/routes/index.js
.
Промежуточные обработчики серверного приложения
Установка промежуточных обработчиков в приложение происходит в модуле server/boot/index.js
. см. пр.5
'use strict';
const express = require("./express");
const transports = require("./transports");
const middleware = require("../middleware");
const authentication = require("./authentication");
const services = require("../services");
const channels = require("./channels");
const appHooks = require("./app.hooks");
const errorHandler = require("./error-handler");
module.exports = function (app) {
express(app);
transports(app);
middleware(app);
authentication(app);
services(app);
channels(app);
appHooks(app);
errorHandler(app);
};
Замечание: Здесь важна последовательность выполнения промежуточных обработчиков в приложении.
Express обработчики
К ним относятся такие модули: cors, helmet, compress, express.json, express.urlencoded, favicon, express.static. см. пр.6
пр.6
'use strict';
const express = require('@feathersjs/express');
const favicon = require('serve-favicon');
const compress = require('compression');
const helmet = require('helmet');
const cors = require('cors');
module.exports = function (app) {
// view engine setup
app.set('views', app.get('views'));
app.set('view engine', 'twig');
app.use(cors());
app.use(helmet());
app.use(compress());
// Turn on JSON body parsing for REST services
app.use(express.json());
// Turn on URL-encoded body parsing for REST services
app.use(express.urlencoded({extended: true}));
app.use(favicon(`${app.get('public')}/images/favicon.ico`));
app.use(express.static(app.get('public')));
};
Транспортные обработчики
К ним относятся такие модули: express.rest, socketio. Здесь мы устанавливаем REST транспорт используя Express, а также Socket.io транспорт. см. пр.7
пр.7
'use strict';
const express = require('@feathersjs/express');
const socketio = require('@feathersjs/socketio');
module.exports = function (app) {
// Set up REST transport using Express
app.configure(express.rest());
// Configure the Socket.io transport
app.configure(socketio());
};
Обработчики для аутентификации
К ним относятся такие модули: authentication, jwt, local, oauth1, oauth2. А также стратегии на основе Express Password такие как: TwitterStrategy, FacebookStrategy, GitHubStrategy, InstagramStrategy, GoogleStrategy. см. пр.8
пр.8
'use strict';
const authentication = require('@feathersjs/authentication');
const jwt = require('@feathersjs/authentication-jwt');
const local = require('@feathersjs/authentication-local');
const oauth1 = require('@feathersjs/authentication-oauth1');
const oauth2 = require('@feathersjs/authentication-oauth2');
const TwitterStrategy = require('passport-twitter').Strategy;
const FacebookStrategy = require('passport-facebook').Strategy;
const GitHubStrategy = require('passport-github').Strategy;
const InstagramStrategy = require('passport-instagram').Strategy;
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const debug = require('debug')('app:boot.authentication');
module.exports = function (app) {
// Get config for authentication
const config = app.get('authentication');
const twitterConfig = Object.assign(config['twitter'], {
Strategy: TwitterStrategy
});
const facebookConfig = Object.assign(config['facebook'], {
Strategy: FacebookStrategy
});
const githubConfig = Object.assign(config['github'], {
Strategy: GitHubStrategy
});
const instagramConfig = Object.assign(config['instagram'], {
Strategy: InstagramStrategy
});
const googleConfig = Object.assign(config['google'], {
Strategy: GoogleStrategy
});
// Set up authentication with the secret
app.configure(authentication(config));
app.configure(jwt());
app.configure(local());
app.configure(oauth1(twitterConfig));
app.configure(oauth2(facebookConfig));
app.configure(oauth2(githubConfig));
app.configure(oauth2(instagramConfig));
app.configure(oauth2(googleConfig));
app.service('authentication').hooks({
before: {
create: [
authentication.hooks.authenticate(config.strategies)
],
remove: [
authentication.hooks.authenticate('jwt')
]
}
});
};
Замечание: В этом модуле получаем параметры аутентификации для разных стратегий (см. config/default.json
), затем происходит конфигурирование и установка самих обработчиков в приложение. Для сервиса authentication устанавливаются соответствующие hooks при создании и удалении сервиса.
Обработчики событий реального времени
В этом модуле происходит установка и публикация событий для клиентов. Такими событиями могут быть: событие connection, событие login, событие authenticated и т.д. см. пр.9
пр.9
module.exports = function(app) {
if(typeof app.channel !== 'function') {
// If no real-time functionality has been configured just return
return;
}
app.on('connection', connection => {
// On a new real-time connection, add it to the anonymous channel
app.channel('anonymous').join(connection);
});
app.on('login', (authResult, { connection }) => {
// connection can be undefined if there is no
// real-time connection, e.g. when logging in via REST
if(connection) {
// Obtain the logged in user from the connection
// const user = connection.user;
// The connection is no longer anonymous, remove it
app.channel('anonymous').leave(connection);
// Add it to the authenticated user channel
app.channel('authenticated').join(connection);
}
});
app.publish((data, hook) => {
// e.g. to publish all service events to all authenticated users use
return app.channel('authenticated');
});
};
Сервисные обработчики
К ним относятся сервисы: users, posts см. пр.10.
пр.10
'use strict';
const users = require('./users/users.service');
const posts = require('./posts/posts.service');
module.exports = function (app) {
app.configure(users);
app.configure(posts);
};
Замечание: Сервисы users, posts используются для демонстрации аутентификации пользователей и демонстрации приложения Chat (обмен сообщениями между пользователями). Модули, которые определяют работу сервисов users, posts находяться в папках server/services/users
и server/services/posts
соответственно.
app.hooks обработчики
Здесь задается возможность логирования в самом приложении - когда идет обращение к любому сервису или возникает ошибка см. пр.11.
пр.11
// Application hooks that run for every service
const logger = require('../hooks/logger');
const hooks = {
before: {
all: [logger()],
find: [],
get: [],
create: [],
update: [],
patch: [],
remove: []
},
after: {
all: [logger()],
find: [],
get: [],
create: [],
update: [],
patch: [],
remove: []
},
error: {
all: [logger()],
find: [],
get: [],
create: [],
update: [],
patch: [],
remove: []
}
};
module.exports = function (app) {
app.hooks(hooks);
};
Middleware обработчики
Здесь можно подключить свои обработчики например server/middleware/init-app.js
. В этом обработчике устанавливаются общие данные для шаблонов. Проверяется наличие файла .env в режиме разработки и если этот файл отсутствует, то выдается ошибка. Проверяется режим технического обслуживания и если сайт находится в режиме технического обслуживания, то происходит переход на соответствующую страницу сайта см. пр.12.
"use strict";
const debug = require('debug')('app:middleware.init-app');
module.exports = function (req, res, next) {
const Base = require('../controllers/base.server.class');
// Get controller/action
Object.assign(req, Base.getControllerAction(req.path));
// Check maintenance mode
if ( req.app.get('maintenance') && req.action !== 'maintenance') {
return res.redirect('/maintenance')
}
// Set values for view
res.locals.port = req.app.get('port');
res.locals.req = req;
res.locals.controllers = req.app.get('controllers');
res.locals.actions = req.app.get('actions');
res.locals.color_theme = req.app.get('color_theme');
res.locals.logo_img = req.app.get('personal')['logo_image'];
res.locals.contact_website = req.app.get('personal')['website'];
res.locals.copyright = req.app.get('personal')['copyright'];
// Check .env
if(req.app.get('env') === 'development'){
Base.isEnvJs();
}
next()
};
Работа клиенского приложения
Клиенсткое приложение строится пакетным обработчиком WebPack и обработчиком каскадных стилей node-sass. Конфигурация WebPack задается файлом webpack.config.js см. пр 13.
пр.13
const path = require('path');
const Dotenv = require('dotenv-webpack');
module.exports = {
// context: path.resolve(__dirname, 'client/src'), // source directory
context: path.resolve(__dirname), // source directory
entry: { // file for assembly, if several - specify hash (entry name => filename)
'polyfills': './client/src/js/polyfills.js',
'app.client': './client/src/js/app.client.js'
},
output: {
path: path.resolve(__dirname, 'client/public/js'), // output directory
filename: '[name].bundle.js'
},
devtool: 'source-map',
module: {
rules: [
{test: /\.twig$/, use: "twig-loader"},
{test: /\.css$/, use: ['style-loader', 'css-loader']},
{
test: /\.js$/,
// exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['env']
}
}
}
]
},
plugins: [
new Dotenv({
path: './.env', // Path to .env file (this is the default)
systemvars: true // It makes it possible to work in production mode on Heroku hosting
})
],
resolve: {
alias: {
joi: 'joi-browser'
}
},
node: {
fs: "empty" // avoids error messages
}
};
Замечание: Модуль dotenv-webpack используется в конфигурации для того чтобы секретные данные с файла .env попали в параметры окружения на клиетне, при условии если эти параметры будут использоваться в коде клиентского приложения.
Инициализация клиентского приложения
Входной точкой клиентского приложения является модуль client/src/js/app.client.js
см. пр 14.
В модуле app.client.js
создается экземпляр класса Client, свойствами которого являются обьект хранилища jStorage, экземпляр класса Bulma, экземпляр класса HttpBox и данные полученные от сервера через интерфейсный элемент. Происходит инициализация пользовательского интерфейса с помощью функции client.bulma.init();
и выполняется вызов соответствующего действия контроллера через роутер const result = await indexRouter(client);
import indexRouter from './routes/index.router'
const debug = require('debug')('app:client');
const bootstrap = async () => {
// Create client
const client = new Client();
// Initializing the User Interface
client.bulma.init();
debug('Path controller/action: ', `${client.req.controller}/${client.req.action}`);
// Run router
const result = await indexRouter(client);
if (result === 'ok') {
return `Result: "OK"; Controller: "${client.req.controller}"; Action: "${client.req.action}";`;
} else {
return result;
}
};
// Run bootstrap
bootstrap().then(
result => {
debug(result)
},
error => {
new Bulma()
.init()
.showError(error)
}
);
Инициализация API REST и аутентификация клиента
Модуль client/src/js/controllers/base.client.class.js
является дочерним классом Base, для всех контроллеров. Из экземпляра этого класса вызывается функция const app = this.setRestTransport();
. Пример реализации этой функции можно посмотреть см. пр 15.
/**
* Set rest transport
* @return {*}
*/
setRestTransport() {
let restURL = `${this.req.protocol}//${this.req.hostname}`;
if (process.env.NODE_ENV === 'development') {
restURL += `:${this.data.port}`;
}
const feathers = require('@feathersjs/client/index');
const axios = require('axios');
//---------------------------------
// Create app
const app = feathers();
// Connect to URL
const restClient = feathers.rest(restURL);
// Configure an AJAX library (see below) with that client
app.configure(restClient.axios(axios));
const authentication = require('@feathersjs/client/authentication');
app.configure(authentication({
storage: window.localStorage
}));
return app
}
Замечание: В дальнейшем переменную app можно использовать для доступа к сервисам и работе с ними. Можно выполнять все операции с сервисами такие как: create, get, find, delete, а также производить аутентификацию к защищенным сервисам и работу с ними в защищенном режиме. Примеры реализации работы с сервисами можно посмотреть в котроллерах, находящихся в папке client/src/js/controllers
.