моя мутация сервера graphql возвращает нулевое значение - PullRequest
0 голосов
/ 08 мая 2018

У меня проблемы с получением результатов моей мутации. Мне нужно создать запись в БД и отправить электронное письмо, уведомляющее пользователя об успешной регистрации. Так как отправка электронной почты и обновление базы данных осуществляется на стороне сервера, я хочу сделать обе в одной и той же мутации. Если сообщение электронной почты не удалось, БД не должна обновляться. Итак, у меня есть следующая мутация:

Mutation: {
        createDealer(_, params) {
            console.log("params: " + JSON.stringify(params));

            bcrypt.genSalt(10, function(err, salt) {
                bcrypt.hash(params.dealer.password, salt, function(err, hash) {
                    // Store hash in your password DB.
                    console.log("hashed password " + params.dealer.password)
                    params.dealer.password = hash;
                    console.log("hashed password " + params.dealer.password + " Hash: " + hash);
                    let session = driver.session();


                    let query = "CREATE (d:Dealer {email:$dealer.email}) SET d += $dealer RETURN d";
                    let here = "here".link("mymail@example.com");

                    let messageObj = {
                        to: params.dealer.email,
                        subject: 'Dealer Registration',
                        text: `Thank you for signing up. To complete and activate your registration please click ${here}.`
                    }

                    return (sendEmail(messageObj))
                        .then(data => {
                            console.log('SendMail data....' + JSON.stringify(data));
                            return session.run(query, params)
                        })
                        .then(result => {
                            console.log('SendNeo4j data....' + JSON.stringify(result));
                            return result.records[0].get("d").properties
                        })
                        .catch((err) => {
                            console.log(err);
                        });
                    //});
                });
            }); // genSalt
        } // Create Dealer
    }, // Mutation

Даже при том, что оба действия были успешными, я не могу получить результаты. Я получаю «неопределенный» для: console.log («Данные SendMail ....» + JSON.stringify (data)); в то время как console.log («Данные SendNeo4j ....» + JSON.stringify (результат)); действительно отображает правильные данные

но graphiql возвращает null для mutate. это мутация graphiql:

mutation CreateDealer($dealer: DealerInput!) {
  createDealer(dealer: $dealer) {
    email
    name
  }
}

с переменными DealerInput, конечно.

Я прочитал, где вы можете получить несколько результатов запроса / мутации, но я не уверен, как это работает. Здесь мне нужны как результаты sendEmail, так и обновление базы данных для моего интерфейса Angular / apollo .... Я бы хотел, чтобы graphiql ничего не знал о sendEmail, но я ожидал, что он вернет запрошенные свойства.

SendEmail:

module.exports = (message) =>
    new Promise((resolve, reject) => {
        const data = {
            from: 'mymail@example.com',
            to: message.to,
            subject: message.subject,
            text: message.text
        };

        mailgun.messages().send(data, (error) => {
            if (error) {
                return reject(error);
            }
            return resolve();
        });
    });

Может ли кто-нибудь с немного большим опытом, чем я, помочь мне здесь ... спасибо

1 Ответ

0 голосов
/ 08 мая 2018

Несколько вещей, чтобы исправить здесь. Возврат Обещания (или любого другого значения) внутри обратного вызова ничего не делает, и это не позволит вам связать дополнительные Обещания так, как вы хотите. Вместо этого ваше обещание срабатывает в режиме обратного вызова и не ожидается.

Как правило, не смешивайте Обещания и обратные вызовы. Если вам абсолютно необходимо использовать обратные вызовы, всегда оборачивайте обратный вызов в Promise (как вы это делали в sendMail). К счастью, большинство популярных библиотек сегодня поддерживают как обратные вызовы, так и обещания. Вот как можно реорганизовать приведенный выше код для правильной цепочки всех ваших обещаний:

createDealer(_, params) {
  return bcrypt.hash(params.dealer.password, 10) // note the return here!
    .then(hash => {
      params.dealer.password = hash
      const session = driver.session()
      const query = "CREATE (d:Dealer {email:$dealer.email}) SET d += $dealer RETURN d"
      const here = "here".link("mymail@example.com")
      const messageObj = {
         to: params.dealer.email,
         subject: 'Dealer Registration',
         text: `Thank you for signing up. To complete and activate your registration please click ${here}.`
      }
      return sendEmail(messageObj) // note the return here!
    }).then(data => {
      return session.run(query, params) // note the return here!
    }).then(result => {
      result.records[0].get("d").properties // note the return here!
    })
  • bcrypt.hash автоматически сгенерирует для вас соль, если вы не передадите одну - нет необходимости вызывать две отдельные функции
  • Мы запускаем нашу цепочку обещаний с bcrypt.hash, поэтому нам нужно вернуть обещание, которое она возвращает. Средство распознавания должно возвращать значение или Promise, которое будет преобразовано в значение, в противном случае оно возвращает ноль.
  • Внутри каждого then мы возвращаем Обещание. Таким образом, мы «связываем» наши Обещания, позволяя конечному значению, которое мы возвращаем в преобразователе, быть значением, к которому разрешается последнее Обещание в цепочке.

Нам также нужно исправить вашу функцию sendMail, чтобы она действительно возвращала значение. Вы правильно возвращаете новое обещание внутри функции, но вам также нужно передать возвращенный объект data для разрешения. Это говорит Обещанию разрешить это значение.

module.exports = (message) => new Promise((resolve, reject) => {
  const data = // ...etc
  mailgun.messages().send(data, (error) => {
    if (error) reject(error) // no need to return, it's pointless
    resolve(data) // pass data to resolve
  })
})

Примечание: похоже на то, что официальная библиотека почтового оружия поддерживает Promises.

Кроме того, я настоятельно рекомендую вам использовать async / await, особенно при работе с длинной цепочкой Promise. Он менее подвержен ошибкам и более читабелен:

createDealer async (_, params) {
  const hash = await bcrypt.hash(params.dealer.password)
  params.dealer.password = hash
  const session = driver.session()
  const query = "CREATE (d:Dealer {email:$dealer.email}) SET d += $dealer RETURN d"
  const here = "here".link("mymail@example.com")
  const messageObj = {
    to: params.dealer.email,
    subject: 'Dealer Registration',
    text: `Thank you for signing up. To complete and activate your registration please click ${here}.`
  }
  const emailResult = await sendEmail(messageObj)
  const result = await session.run(query, params)
  return result.records[0].get("d").properties // still need to return!
}

РЕДАКТИРОВАТЬ: Что касается обнаружения ошибок, GraphQL будет отлавливать любые ошибки, выданные вашим распознавателем, что означает, что вы часто можете пропустить, используя catch самостоятельно. Например, если ваш запрос к почтовому оружию завершится неудачно, он сгенерирует какую-то ошибку, и ваш запрос вернет ноль для data и подробности ошибки внутри массива errors.

Этого может быть достаточно, хотя 1) вы, возможно, захотите записать свой стек ошибок в другом месте; и 2) в процессе работы вы, вероятно, не хотите раскрывать подробности внутренних ошибок.

Это означает, что вы, вероятно, захотите использовать пользовательские ошибки. В качестве бонуса вы можете добавить некоторые собственные свойства к своим ошибкам, чтобы помочь клиенту красноречиво справиться с ними. Таким образом, ваш код может выглядеть примерно так:

class DeliveryFailureError extends Error {}
DeliveryFailureError.code = 'DELIVERY_FAILURE'
DeliveryFailureError.message = 'Sorry, we could not deliver the email to your account'

try {
  await mailgun.messages.create()
} catch (err) {
  logger.error('Mailgun request failed:', err.stack)
  throw new DeliveryFailureError()
}
...