- Имитация GET/POST/DELETE поверх сокета: запрос-ответ, получение, сохранение, удаление
- Подписка/отписка на изменения данных
- Передача ошибок, связанных с запросом или подпиской
- Типизация: возможность описать union объектов событий в ts/openapi
- Использование одних и тех же типов для получения и обновления сущности
- Прозрачное, простое в реализации на сервере (де)мультиплексирование запросов на другое устройство и ответов/событий от него
- Отсутствие специального апи для подписок/отписок с генераций request-id или subscription-id
- Сервер может не реализовывать подписки, а всегда слать в сокет любые изменения
- Сервер может не реализовывать апдейты, а просто отправить обратно пришедший запрос, уведомляя клиент, что запрос обработан
- Совместимость с часто используемым в ws форматом сообщений, объект с type
type Value = string | number | boolean | null
export type Message = {
// entity or list type
type: string
// entity id or list search params
id?: string | number | Record<string, Value | readonly Value[]> | null
// optional target server paths
path?: Record<string, string | null> | null
// to server: undefined - get and subscribe, null - delete, object - replace
// from server: null - deleted, object - new data
data?: unknown
// Error enum
error?: number | string | null
// Optional error message
message?: string | null
}
request - to server, response - from server
POST /device/123/firmware
body { firmware: 'base64data' }
WS request: { path: { device: '123' }, type: 'firmware', data: { firmware: 'base64data' }}
WS response: { path: { device: '123' }, type: 'firmware' }
GET /device/123/info
response { status: 'OK', version: '1.0.0' }
WS request + subscribe to device 123 info changes: { path: { device: '123' }, type: 'info' }
WS response + updates: { path: { device: '123' }, type: 'info', data: { status: 'OK', version: '1.0.0' }
WS response error: { path: { device: '123' }, type: 'info', error: 'SOME_ERROR', message: 'optional error text' }
WS unsubscribe request: { path: { device: '123' }, type: 'info', error: null }
GET /device/123/rules?allow=1
response ['1', '2', '3']
WS request + subscribe: { path: { device: '123' }, type: 'rules', id: { allow: 1 }
WS response + updates: { path: { device: '123' }, type: 'rules', id: { allow: 1 } , data: ['1', '2', '3'] }
DELETE /device/123/rules?allow=1
response {}
WS request: { path: { device: '123' }, type: 'rules', id: { allow: 1 }, data: null }
WS response: { path: { device: '123' }, type: 'rules', id: { allow: 1 }, data: null }
DELETE /device/123/rule/32112
response {}
WS request: { path: { device: '123' }, type: 'rule', id: '32112', data: null }
WS response: { path: { device: '123' }, type: 'rule', id: '32112', data: null }
GET /device/123/task/32112
response { status: 'OK', progress: 100 }
WS request + subscribe: { path: { device: '123' }, type: 'task', id: '32112' }
WS response + updates: { path: { device: '123' }, type: 'task', id: '32112', data: { status: 'OK', progress: 100 } }
GET /device/123/subdev/321/task/32112
response { status: 'OK', progress: 100 }
WS request + subscribe: { path: { device: '123', subdev: '321' }, type: 'task', id: '32112' }
WS response + updates: { path: { device: '123', subdev: '321' }, type: 'task', id: '32112', data: { status: 'OK', progress: 100 } }