Search code examples
typescriptaxioschunked-encoding

How await all chunks of responses if request is stream (Axios)


I have an proxy server that needed to make a request on external API server for synthesize a voice from a some text. In API docs there is sentence that tell me: after request I'll get first response with headers and after that I'll get in stream mode binary data, cause in body of response there is 'Transfer-Encoding: chunked'.

So, I am using responseType: 'stream' for this thing and this code

export const synthesizeVoice = async (contentType: ContentType,
                                      dataForSynthesize: string,
                                      format: string = 'wav16', 
                                      voice:  string = 'Nec_24000') => {
    const token = await authHandler.getAuthData();
    const date  = new Date(); const timestamp = date.getTime();
    const file  = fs.createWriteStream(timestamp + '.wav'); // I'm storing getted data on server, so this one needed for that
    
    const response = await axios({
        method: 'POST',
        url: SAPI.SS_SYNTH,

        headers: {
            Authorization:  'Bearer ' + token,
            'Content-Type': (contentType === 'ssml') ? 'application/ssml' : 'application/text',
        },
        params: {
            format: format,
            voice:  voice,
        },
        data: dataForSynthesize,

        responseType: 'stream',
    });
    
    // I'm writting getted data to a file 
    response.data.pipe(file);
    // and return a path on method above in call stack to return getted binary data on front
    return file.path;
};

My main problem, that after getting a first chunk of response (If Im not mistaken) my method return the path of file (In that moment file isn't full form) and on front side come not full audio file.

How can I await to get full binary data and send their only after that after that or maybe I should use stream request from my front side also to get data by chunks?

Also, maybe this ways isn't good and I should use something another?

UPD: Working code

axios({
    // nothing to changes here, I've just hidden it to short code example
})
.then(resp => {
    // Event listeners on files didn't working in my case, so
    // I used it with axios response 
    resp.data.pipe(file);

    resp.data.on('end', () => {
        file.close();

        res.set({
            'Content-Type': 'audio/wav16',
        });
        const resFile = fs.createReadStream(file.path).pipe(res);
    });
})
.catch(err => {
    console.log(err.message)
});

Solution

  • You can try consuming data in this way.

    file.on('data', chunk => {
      console.log(chunk.toString());
    });
    

    To do something after the end of the data stream, you can use

    file.on('end', chunk => {
      console.log("End");
    });
    

    Combining these two I think you will be able to wait and get the full file.