Обработка собственных объектов в REST API
У меня есть веб-сервер API, реализованный с использованием ExpressJS, который предоставляет в REST API для записи веб-камер, подключенных к машине веб-сервера.
Веб-камеры и кодирование обрабатываются с использованием DLL, написанной на C++, а взаимодействие осуществляется с помощью библиотеки node-ffi.
Проблема, с которой я столкнулся, заключается в том, что я смешиваю нативные дескрипторы ffi со строковым форматированием JSON в своих ответах.
например, у меня есть Stream
класс с прототипом:
Stream.prototype.id = '';
Stream.prototype.url = '':
Stream.prototype.parent = null;
Stream.prototype.filePtr = null;
куда Stream.filePtr
будет содержать дескриптор ffi, например ref.refType(ref.types.void)
Тогда в моем экспресс-посте start
позвоните мне сделать что-то вроде:
impl.start = function(req, res){
var camera = cameras.find(function(camera) {
return camera.id === req.params.camera;
});
res.send(camera.startStream()); // startStream returns a new 'Stream' object.
};
Как видите, я просто отправляю Stream
объект как есть в ответе. Вот как я обычно реализую REST API. Проблема в том, что родной filePtr
Ручка не должна быть действительно включена, и я не уверен, что лучший метод для этого или я делаю что-то в корне неправильно?
ПРИМЕЧАНИЕ: я новичок, когда дело доходит до web, nodejs, expressjs и javascript в целом. Поэтому, если что-то, что я делаю, не имеет смысла или может быть сделано лучше, пожалуйста, укажите это.
Более полный пример:
// dll bindings
var fileType = ref.types.void;
var filePtrType = ref.refType(fileType);
var cameraType = ref.types.void;
var cameraPtrType = ref.refType(cameraType);
var myLib = ffi.Library(/* Stuff */):
// expressjs api definitions
app.post('api/cameras/:camera/streams', impl.start);
app.delete('api/cameras/:camera/streams/:stream', impl.stop);
app.get('api/cameras', impl.cameras);
app.get('api/cameras/:camera', impl.camera);
app.get('api/cameras/:camera/streams', impl.streams);
app.get('api/cameras/:camera/streams/:stream', impl.stream);
// objects definitions
function Stream() {
this.id = Date.now();
this.url = this.id + '.mp4';
};
Stream.prototype.id = '';
Stream.prototype.url = '':
Stream.prototype.parent = null;
Stream.prototype.filePtr = null;
function Camera(id, device){
this.id = id;
this.device = device;
this.cameraPtr = myLib.openCamera(device);
};
Camera.prototype.id = '';
Camera.prototype.device = 0;
Camera.prototype.cameraPtr = null;
Camera.prototype.startStream = function() {
var stream = new Stream(this);
stream.filePtr = myLib.openFile(this.cameraPtr, stream.url);
return stream;
};
Camera.prototype.stopStream = function(stream) {
myLib.closeFile(stream.filePtr);
this.streams.slice(this.streams.indexOf(stream), 1);
};
// object declaration
var cameras = [];
var numCameras = myLib.num_cameras();
for (var n = 0; n < numCameras; ++n) {
cameras.push(new Camera(n, n));
}
// express api implementation
var impl = {};
impl.streams = function(req, res) {
var camera = cameras.find(function(camera) {
return camera.id === req.params.camera;
});
res.send(camera.streams);
};
impl.start = function(req, res){
var camera = cameras.find(function(camera) {
return camera.id === req.params.camera;
});
res.send(camera.startStream());
};
impl.stop = function(req. res) {
var camera = cameras.find(function(camera){
return camera.id === req.params.camera;
});
var stream = camera.streams.find(function(stream) {
return stream.id === req.params.stream:
});
camera.stopStream(stream);
};
/* Stuff */
1 ответ
Я полагаю, что вы хотите передать данные потока в ответ, а не возвращать поток напрямую. Попробуй это. Вот документы о трубе.
var readableStream = camera.startStream();
readableStream.pipe(res);
редактировать
Ну, на самом деле, вы, вероятно, не хотите завершать writeableStream (ответ - writableStream), как только у вас заканчиваются данные (так как вы выполняете потоковую передачу), поэтому попробуйте это, если вышеприведенное не работает:
var readableStream = camera.startStream();
readableStream.on('data', function(chunk) {
res.write(chunk);
})
Другие мысли
Если вы хотите вернуть несколько потоков одновременно, вам может потребоваться сделать отдельные http-запросы для каждого. Возврат нескольких потоков одновременно (если вы не сделали что-то очень умное), скорее всего, просто отослал бы перепутанные данные.
Чтобы попытаться ответить на актуальный вопрос
Когда клиент запрашивает поток, очевидно, что вы не можете вернуть необработанные данные в виде JSON, поскольку JSON этого не позволяет. Я бы порекомендовал, когда клиент запрашивает ресурс потока, чтобы вернуть местоположение ресурса (URL), которое клиент должен запросить. Я считаю, что это правильный способ REST, но я не эксперт в этом. Вот как будет происходить взаимодействие:
Клиент: (через GET) Пожалуйста, дайте мне поток
Сервер: ответ (json) вот куда вам нужно пойти, чтобы получить это (плюс метаданные [необязательно])
Клиент: Пожалуйста, дайте мне jsonResponse.streamURL
Сервер: (потоки к ответу)....