I have a koa router I need to call a api where will async return result. This means I cannot get my result immediately, the api will call my callback url when it's ok. But now I have to use it like a sync api which means I have to wait until the callback url is called.
My router like this:
router.post("/voice", async (ctx, next) => {
    // call a API here
    const params = {
        data: "xxx",
        callback_url: "http//myhost/ret_callback",
    };
    const req = new Request("http://xxx/api", {
        method: "POST",
        body: JSON.stringify(params),
    });
    const resp = await fetch(req);
    const data = await resp.json();
    // data here is not the result I want, this api just return a task id, this api will call my url back
    const taskid = data.taskid;
    // now I want to wait here until I got "ret_callback"
    // .... wait .... wait
    // "ret_callback" is called now
    // get the answer in "ret_callback"
    ctx.body = {
        result: "ret_callback result here",
    }
})
my callback url like this:
router.post("/ret_callback", async (ctx, next) => {
    const params = ctx.request.body;
    // taskid will tell me this answer to which question
    const taskid = params.taskid;
    // this is exactly what I want
    const result = params.text;
    ctx.body = {
        code: 0,
        message: "success",
    };
})
So how can I make this aync api act like a sync api?
Just pass a resolve() to another function. For example, you can do it this way:
// use a map to save a lot of resolve()
const taskMap = new Map();
router.post("/voice", async (ctx, next) => {
    // call a API here
    const params = {
        data: "xxx",
        callback_url: "http//myhost/ret_callback",
    };
    const req = new Request("http://xxx/api", {
        method: "POST",
        body: JSON.stringify(params),
    });
    const resp = await fetch(req);
    const data = await resp.json();
    const result = await waitForCallback(data.taskid);
    ctx.body = {
        result,
    } })
const waitForCallback = (taskId) => {
    return new Promise((resolve, reject) => {
        const task = {};
        task.id = taskId;
        task.onComplete = (data) => {
            resolve(data);
        };
        task.onError = () => {
            reject();
        };
        taskMap.set(task.id, task);
    });
};
router.post("/ret_callback", async (ctx, next) => {
    const params = ctx.request.body;
    // taskid will tell me this answer to which question
    const taskid = params.taskid;
    // this is exactly what I want
    const result = params.text;
    // here you continue the waiting response
    taskMap.get(taskid).onComplete(result);
    // not forget to clean rubbish
    taskMap.delete(taskid);
    ctx.body = {
        code: 0,
        message: "success",
    }; })
I didn't test it but I think it will work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With