koajs / koa

Expressive middleware for node.js using ES2017 async functions
https://koajs.com
MIT License
35.22k stars 3.23k forks source link

Call a new request in Koa. #1307

Closed wentianl20 closed 5 years ago

wentianl20 commented 5 years ago

Hi, I am fresh in Node.js and Koa. I just want to build a simple API. When a user calls this API, it can call a request with user's information and server's ID to a public API to get a token and then send back to the user. As the Koa does not supply a request function, I used the native request library. However, the callback function can't call the koa response correctly. I can print the token in my API, but I can't send it back to the user.

const request = require("request");

const jscode2session_url = "https://api.weixin.qq.com/sns/jscode2session";
const appid = "<REMOVED>";
const secret = "<REMOVED>";
const grant_type = "authorization_code";

let js_code = "";

var mini_session = async (ctx, next) => {

  let url = ctx.request.url;
  let query = ctx.request.query;
  let querystring = ctx.request.querystring;
  var errorMessage = "";
  var responseJson = {};

  if (!!query.code) {
    // ctx.response.body = { code: query.code };
    js_code = query.code;

    const form = {
      appid: appid,
      secret: secret,
      js_code: js_code,
      grant_type: grant_type
    };

    request(
      {
        url: jscode2session_url,
        method: "POST",
        json: true,
        headers: {
          "content-type": "application/json"
        },
        form: form
      },
      function(error, response, body) {
        if (!error && response.statusCode == 200) {
          console.log("The body is: ", body);
          responseJson = body;
          console.log("=======I am callback======");
          ctx.response.body = responseJson;
        } else {
          errorMessage = "Error: " + error;
          ctx.response.body = errorMessage;
        }
      }
    );
  } else {
    ctx.response.body = "Please supply the code para!!!";
  }
  console.log("=======I am so faster ...========");
  //   ctx.response.body = responseJson;
};

module.exports = {
  "GET /dev/passcode": mini_session
};
TehShrike commented 5 years ago

Use a promise-based api, like got, and then you can const response = await got(url) instead of trying to get a callback interface to mesh with your async function

fl0w commented 5 years ago

@wentianl20 I'm a bit concerned that both appid and secret looks real. I'm not at all aware what type of service you're requesting but I'd ensure that you haven't leaked credentials by mistake now.

As far as your problem goes, what you're experiencing is that the promise (which each mw of Koa is) resolves before the callback (thus response) from API service is called. You'll have to wrap that request in a promise and then return it (there's request-promise of the top of my head unless you'll want to do it yourself).

Here's a quick and dirty pseudo of how that could look.

...
if (!!query.code) {
  ...
  return new Promise((resolve, reject) => {
    request({
      url: ...,
      ...
    }, (err, response, body) => {
      if (err) return reject(err)
      ctx.body = body
      resolve()
    }
  })
}
...
fl0w commented 5 years ago

I'll close this for now as both responses should be sufficient as an answer. Please feel free to reopen if you're still experiencing issues.