Flask:
docx --> bytesIO --encodebytes()--> bytes --decode()--> string --> array containing multiple of those string.
Vue:
array containing those strings --?--> blob
I am trying to return multiple byteIO files from Flask endpoint to my Vue application at once.
Based on this SO question, it may be done by converting the byteIO files to string using bytesencode() and .decode(). Then the string is attached to an array and json serialized.
I don't know how it can be done however to reverse the convestion in Vue back to a necessary blob object (which will be downloaded).
Any suggestions on how to accomplish this?
How I create my bytesIO document files from docx template (my code is heavily inspired by snakecharmerb's answer in this post):
def from_template_multiple(context): # context is a dict containing custom attributes to be rendered in the document
template = DocxTemplate(template_document.docx')
# Create in-memory buffer
target_file = BytesIO()
# Render template and save to the buffer
template.render(context)
template.save(target_file)
# Reset the buffer's file-pointer to the beginning of the file
target_file.seek(0)
# return target file instead of send_file directly
return target_file
My flask route that receives the axios call that receives the context attributes from Vue. The part with the file encoding is from this answer.
@hagis_api_bp.route('/docx/multiple', methods=['POST'])
def generate_word_multiple():
request_json = request.get_json()
# array to store blob derivations
blob_array = []
for item in request_json['body']:
context = json.loads(item)
target_file = process.from_template_multiple(context)
# encode as base64
from base64 import encodebytes
encoded_file = encodebytes(target_file.getvalue()).decode('ascii')
# append target file to blob array
blob_array.append(encoded_file)
return jsonify({'result': blob_array})
And finally the Vue part. This axios call is used to send the context information (json) and here I want to return the blob_array and then revert the encoding process to receive the "raw" blob files.
// axios request + file download
axios({
url: 'docx/multiple',
data: {body: body_array},
method: 'POST',
}).then((response) => {
// looping over each element in response.data (each converted bytesIO string)
response.data['result'].forEach((element) => {
// convert string to blob here ?
// download blob as docx file
const url = window.URL.createObjectURL(new Blob([converted_element])); // --> using result from missing conversion above
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'title.docx');
document.body.appendChild(link);
link.click();
});
});
I was able to solve the problem. The following axios request does the trick. This question was very helpful: Creating a BLOB from a Base64 string in JavaScript
// axios request + file download
axios({
url: 'docx/multiple',
data: {body: body_array},
method: 'POST',
}).then((response) => {
response.data['result'].forEach((element) => {
console.log(element)
// decode string to blob --> solution to question
const byteCharacters = atob(element);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
console.log(byteArray)
const url = window.URL.createObjectURL(new Blob([byteArray]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'test.docx');
document.body.appendChild(link);
link.click();
});
});