ApiBlaze – это инструмент для изучения спецификаций API: поиск по ключевому слову, фильтрация объектов, свойств или конечных точек, а также просмотр описаний и примеров кода. ApiBlaze поможет вам молниеносно ответить на конкретный вопрос об API. Вы можете попробовать это здесь: apblaze.admantium.com.
В моих предыдущих статьях я рассказал, почему веб-сокеты являются важным методом для ApiBlaze: они обеспечивают длительные полнодуплексные соединения между двумя серверами для непрерывной потоковой передачи данных. Поскольку спецификация открытого API довольно велика (полная спецификация Kubernetes занимает 4 МБ текста), поиск этих данных, их преобразование и отправка обратно в браузер требует довольно больших вычислительных ресурсов. В ApiBlaze эти действия выполняются на стороне сервера, а затем отправляются обратно в браузер для немедленного рендеринга.
Это соответствует следующему основному требованию:
- TECH03 — Используйте веб-сокеты для подключения внешнего и внутреннего интерфейса
В этой статье подробно рассказывается, как создать сборку внутреннего сервера с помощью экспресс-фреймворка и библиотеки socket.io, а также как подключить ее к клиентскому интерфейсу, работающему в браузере. Хотя шаги объясняются в контексте ApiBlaze, они являются общими, и вы можете применить их для любой внешней библиотеки, такой как приложения React, Vue или PlainJS.
Эта статья первоначально появилась в разделе мой блог.
Бэкенд-сервер
Бэкэнд основан на express
и socket.io
(v2.3)1. Давайте установим пакеты.
npm i -S express [email protected]
После завершения установки мы создадим 4 файла, чтобы разделить внутренний код на разные области ответственности.
index.js
: реализует экземпляр экспресс-сервера, открывая порт, через который можно получить доступ к соединению через веб-сокет.connect.js
: создает экземпляр веб-сокета, получая экземпляр узлаHttpServer
, объект, который, например. создано с экспрессhandler.js
: обработчик определяет все события веб-сокета, к которым и определяет, как они обрабатываются.actions.js
: Содержит конкретные функции, которые будут вызываться при получении зарегистрированного события, и они возвращают свои результаты обработчику, который, в свою очередь, возвращает их вызывающей стороне.
Этот простой макет помогает четко отделить код серверного приложения. Давайте теперь подробно рассмотрим содержимое этих файлов.
Веб-сервер с конечной точкой WebSocket
Веб-сервер express
определен в index.js
.
//* index.js *// const express = require('express') const websocketConnection = require('./connect.js')
app = express()
const httpServer = app.listen(3000, () => { console.log(`BOOTING | api-blaze-backend v0.0.1`) })
websocketConnection(httpServer)
В этих нескольких строках кода 2 мы создаем экземпляр экспресс-сервера для прослушивания порта 3000 (строка 7), а затем передаем этот экземпляр функции websocketConnection
(строка 11).
Соединитель
Соединитель определяет, как настроен веб-сокет. Мы создаем экземпляр с именем io
(строка 6), который получает экземпляр экспресс-сервера и необязательный объект конфигурации. Вариантов множество, см. официальную документацию. Затем для экземпляра веб-сокета мы определяем прослушиватель событий для события connection
(строка 9). Когда это событие произойдет, обработчик возьмет на себя управление.
//* connect.js *// const websocket = require('socket.io') const handleConnection = require('./handler.js')
function websocketConnection (httpServer) { const io = websocket(httpServer, { serveClient: false }) io.on('connection', socket => handleConnection(socket)) }
module.exports = websocketConnection
Обработчик и действия
В файле handler.js
мы определяем, какие сообщения обрабатывает веб-сокет и как на них реагировать. События определяются с помощью метода io.on
, который получает имя события, его аргументы и функцию обратного вызова, которая будет выполнена. В строке 6 мы определяем, как обрабатывать сообщение system:healthcheck
: мы будем регистрировать полученное сообщение, а затем emit
ответ с сообщением healthy
. Точно так же в строке 10 мы определяем обработку сообщения app:api-search-action
, которое выполнит функцию действия apiSearchAction
.
//* handler.js *// const { apiSearchAction } = require('./actions')
const clients = {}
function handleConnection (socket) { console.log(`+ client ${socket.id} has connected`) clients[socket.id] = { connected: true }
socket.on('system:healthcheck', msg => { console.log(msg) socket.emit('system:healthcheck', 'healthy') })
socket.on('app:api-search-action', keyword => { console.log('app:api-search-action', keyword) socket.emit('app:api-search-action', apiSearchAction(keyword)) }) }
module.exports = handleConnection
Действия — это простые функции JavaScript. apiSearchAction загрузит инвентаризацию API, статический файл, содержащий имя, описание и ссылку на файл на стороне сервера для файла спецификации API. Он будет искать ключевое слово в этом представлении, преобразовывая ключевое слово в регулярное выражение, а затем ранжируя все API по количеству совпадений этого ключевого слова.
Пример действия:
//* action.js *// const apiInventory = require('./spec/inventory.json')
function apiSearchAction (keyword) { const regex = new RegExp(keyword, 'ig') var res = [] for (let [name, definition] of Object.entries(apiInventory)) { const occurences = JSON.stringify(definition).match(regex) const score = (occurences && occurences.length) || 0 res.push({ name, score, definition }) } return res.sort((a, b) => b.score - a.score) }
Теперь мы объяснили внутреннюю обработку поиска. Давайте посмотрим, как это соединение устанавливается и обрабатывается во внешнем интерфейсе.
Подключение внешнего интерфейса
Интерфейс предлагает два разных варианта установки socket.io. Вы можете добавить тег <script>
вручную, ссылаясь на статически предоставленный файл JavaScript socket.io, или вы можете использовать сборщик, такой как сборщик Snowpack, который автоматически установит библиотеку.
Чтобы настроить snowpack
и клиентскую библиотеку socket.io
, выполните следующую команду:
npm i -s snowpack [email protected]
После завершения определите файл connect.js
, который создаст экземпляр веб-сокета, который подключается к внутреннему серверу.
//* connect.js (Frontend) *//
import io from 'socket.io-client'
export default io('ws://127.0.0.1:8081', { cookie: false })
Затем вы можете импортировать экземпляр websocket
в другие файлы, например, в index.js
, и начать с отправки сообщения проверки работоспособности. Будьте осторожны: при импорте socket.io-client
будет определен ряд объектов в области global
, таких как Server
, Socket
, Client
— не используйте объекты с похожими именами в своем приложении.
import websocket from './globals/connect.js'
function init () { websocket.emit('system:healthcheck', 'ok?') websocket.on('system:healthcheck', msg => { console.log(msg) }) }
init()
Этот экземпляр веб-сокета работает аналогично тому, что мы уже видели в бэкэнде. С помощью websocket.emit
сообщения отправляются, а с помощью websocket.on
определяются обработчики входящих сообщений.
Экземпляр, экспортированный в connect.js
, можно использовать и в других классах. Вот пример для SearchApiAction
— он выдаст сообщение app:api-search-action
и, получив ответ, передаст результаты функции обратного вызова.
import websocket from '../globals/connect.js'
export default class SearchApiAction extends Action { action (cb) { websocket.emit('app:api-search-action', 'dummy') websocket.on('app:api-search-action', json => { cb(json) }) } }
Обзор: требования проекта ApiBlaze
После завершения рефакторинга мы имеем следующий статус с требованиями ApiBlaze:
Поиск APIS
- ✅ SEA01 — Поиск API по ключевому слову
- ✅ SEA02 — Показать результаты поиска во всплывающем окне
- ✅ SEA03 — Выберите результаты поиска с помощью клавиш со стрелками, введите и щелкните мышью
Рамки
- ✅ FRAME01 — Контроллер и маршрутизация
- ✅ FRAME02 — Страницы и компоненты с отслеживанием состояния
- ✅ FRAME03 — Действия
- ✅ FRAME04 — Оптимизированная комплектация
Технологии
- ✅ TECH01 — Используйте PlainJS и пользовательский фреймворк
- ✅ TECH02 — Используйте SAAS для CSS
- ✅ TECH03 — Используйте веб-сокеты для подключения внешнего и внутреннего интерфейса
Вывод
Использование WebSockets для подключения серверной части к интерфейсной позволяет формировать долговременные полнодуплексные соединения для непрерывной потоковой передачи данных. Для серверной части основными шагами являются: Импортируйте библиотеку socket.io, создайте экземпляр узла HttpServer
и используйте этот экземпляр для создания экземпляра Socket.IO. Затем вы определяете прослушиватели событий с помощью методов io.on
и io.emit
. Клиенту необходимо импортировать клиентскую библиотеку socket.io, создать экземпляр, который подключается к серверной части, а также использовать io.on
и io.emit
для определения и обработки сообщений, которыми будет осуществляться обмен. Попробуйте использовать WebSockets в одном из ваших проектов — они мощные и простые в настройке.
Сноски
- На момент написания был выпущен websocket.io v 3.0, но я не смог заставить его работать и вместо него выбрал более старую версию v2.3. ↩
- В этом примере экспресс-конфигурация довольно проста, но вы можете добавить любой другой экспресс-модуль, например. для обработки статических файлов или для установки значений CORS. ↩