NodeJS: Должен ли я использовать обещание для предварительной обработки? - PullRequest
1 голос
/ 19 марта 2020

NodeJS + Express. Я пытаюсь добиться следующего:

  • клиент отправляет по почте запрос со следующим JSON документом data={text: "I love Stackoverflow", shouldPreprocess: <true or false>};
  • Мне нужно вызвать внешнюю службу WebSocket, чтобы настроиться анализ текста и возврат результата в виде JSON, например, {sentiment: 'positive'};
  • Однако, если shouldPreprocess имеет значение true, я должен вызвать другую службу предварительной обработки раньше;

Вопросы:

  1. Я не уверен, что правильный способ сделать это, но вот две попытки. Я чувствую, что они оба взломаны.
  2. Я не уверен, как обращаться с неверным вводом от клиента. Подробности ниже.
router.post('/analyse', function (req, res, next) {
    const data = req.body;

    if (typeof data.text === 'undefined' || typeof data.shouldPreprocess === 'undefined') {
        return next(new Error('Please provide text and flag'));
    }

    analyseSentiment(data.text, data.shouldPreprocess)
        .then(doc => res.json(doc))
        .catch(err => next(err));
});

function analyseSentiment(text, shouldPreprocess) {
    let promise;
    if (shouldPreprocess === true) {
        textP = preprocess(text);
    } else promise = new Promise((res, req) => res(text));
    return textP
        .then(text => axios.post(<URL to sentiment analyser>, text))

function preprocess(text) {
    const ws = WebSocket(<URL of preprocessor>);
    // But what if I wanted to check for some property of text here and throw an error
    // that gets sent to the client, just as I do in the main function, i.e. in router.post above?
    ws.on('open', () => ws.send(text));
    return new Promise((res, rej) => ws.on('message', preprocText => res(preprocText)));
}

Итак, это первый способ. Это кажется хакерским, потому что я создаю бесполезное обещание в analyseSentiment, которое просто возвращает текст, так что у меня есть унифицированный способ работы как со сценарием предварительной обработки, так и без предварительной обработки ios. Также смотрите вопрос в комментарии в функции preprocess выше.

Второй способ - сделать все в router.post, то есть что-то вроде:

router.post('/analyse', function (req, res, next) {
    const data = req.body;

    if (typeof data.text === 'undefined' || typeof data.shouldPreprocess === 'undefined') {
        return next(new Error('Please provide text and flag'));
    }

    if (data.shouldPreprocess) {
        preprocess(data.text)
            .then(text => axios.post(<URL to sentiment analyser>, text)))
            .then(doc => res.json(doc))
            .catch(err => next(err));
    } else {
        axios.post(<URL to sentiment analyser>, text)
            .then(doc => res.json(doc))
            .catch(err => next(err));
    }

});

Но, конечно, нет фрагмент дублированного кода

Спасибо!

Ответы [ 2 ]

2 голосов
/ 19 марта 2020

Я бы использовал тот факт, что в Express вы можете передавать несколько функций в качестве обработчиков запросов. Они будут вызываться один за другим, когда вы вызываете next() без аргумента.

Пример реализации:

router.post('/analyse', validate, preprocess, analyse)

function validate (req, res, next) {
  let text = req.body.text
  let preprocess = req.body.shouldPreprocess
  if (typeof text === 'string' &&
      text.length > 0 &&
      text.length < 400 &&
      typeof preprocess === 'boolean') {
    next() // validation complete, go to the next request handler
  } else {
    return res.status(400).json({ reason: 'Please provide text and flag' })
  }
}

function preprocess (req, res, next) {
  if (req.body.shouldPreprocess) {
    const ws = WebSocket(<URL of preprocessor>)

    ws.on('open', () => ws.send(text))
    ws.on('message', preprocessed_text => {
      // check for some properties of text
      // this function is not implemented here
      if (validatePreprocessedText(preprocessed_text) {
        // send error to client
        return res.status(400).json({ reason: 'Malformed preprocessing result.' })
      }
      // seems legit, go on...
      res.locals.text_to_analyze = preprocessed_text
      next()
    }
    ws.on('error', next) // or return res.status(500).json({ reason: 'whatever...' })
  } else {
    res.locals.text_to_analyze = req.body.text
    next() // nothing to see here, move on...
  }
}

function analyse (req, res, next) {
  axios.post(<URL to sentiment analyser>, res.locals.text_to_analyze)
    .then(reply => res.json(reply.data))
    .catch(error => {
      console.log(error)
      res.status(500).json({ reason: 'Sentiment service has blown up.' })
    })
}

Надеюсь, это поможет! :)

1 голос
/ 19 марта 2020

Вы можете захотеть разделить предварительную обработку и проверку на express middlewares и поместить их перед основным обработчиком, это может выглядеть примерно так:

const validate = (req, res, next) => {
  const data = req.body;

  if (typeof data.text === 'undefined' || typeof data.shouldPreprocess === 'undefined') {
    return next(new Error('Please provide text and flag'));
  }
  return next();
}

const preprocess = (req, res, next) => {
  if (req.body.shouldPreprocess) {
    const ws = WebSocket('<URL of preprocessor>');
    ws.on('message', preprocText => {
      req.body.text = preprocText;
      next();
    });
  } else {
    next()
  }
}

router.post('/analyse', validate, preprocess, function (req, res, next) {
  const text = req.body.text;

  axios.post('<URL to sentiment analyser>', text)
    .then(doc => res.json(doc))
    .catch(err => next(err));
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...