How to upload files with Flask API
Tags: webdev, programming, python, tutorial
Published: 2022-10-18 14:01:24

In this article, I will present code with python about how to upload files with flask API. Before you will start development, I want to you checkup and install the [python library](https://www.python.org/downloads/release/python-391/) , Preparing to set up a virtual environment (env) for development with `$ python3 -m venv venv` and the active environment with `$ source venv/bin/activate ` 

**Next step,** We will install flask with `$ pip install flask` and create a folder in the project.

```
app.py
/ static
  => css
     / style.css
  => img
     / upload_icon.png
     / success_icon.png
/ templates
  => index.html
  => download.html
```
 
For the last one, I will install `$ pip3 install -r requirements.txt` and freeze the library with `$ pip freeze > requirements.txt` to finish the setup.

After finishing setting up, I will be imported JSON, flask template, and utils of the secure file name. You can follow up on the code below.

```python
import os
import json
from flask import Flask, request, render_template, flash, redirect, url_for, send_from_directory
from werkzeug.utils import secure_filename
```

In the second step, I have to provide constants that allow checking file format extensions (**example:** for checking ".txt" file)

```python
ALLOWED_EXTENSIONS = {'txt'}
```

In the third step, I have to create a new instance for the configuration file format on the code below.

```python
application = Flask(__name__)
application.secret_key = os.urandom(24)
application.config['UPLOAD_FOLDER'] = 'data'
application.config['MAX_CONTENT_LENGTH'] = 4 * 1024 * 1024  # 4MB max-limit.
```

And I have to create an extension for checking allowed files with **ALLOWED_EXTENSIONS**

```python
def allowed_file(filename):
    return '.' in filename and filename.rsplit('.',1)[1].lower() in ALLOWED_EXTENSIONS  
```

The fourth step, I have to create API for uploading files with the browser. If It has a user request to upload the file with localhost IP `http://127.0.0.1:5000/`, the system will be checking the file part and read the text in document. 

```python
# home page
@application.route('/', methods=['POST', 'GET'])
def upload_file():
    if request.method == 'POST':
       if 'file' not in request.files:
          flash('No file part')
          return redirect(request.url)
       
       file = request.files['file']

       read_text = []
       for text in request.files.get('file'):
          read_text.append(str(text).replace("b'",""))
       print(read_text[0])

       # if the user does not select a file, the browser submits an empty file without a filename.
       if file.filename == '':
         flash('No selected file')
         return redirect(request.url)

       # if the user submits a file with the correct format
       if file and allowed_file(file.filename):
         filename = secure_filename(file.filename)
         file.save(os.path.join(application.config['UPLOAD_FOLDER'], filename))
         os.remove(os.path.join(application.config['UPLOAD_FOLDER'], filename))
         return redirect(url_for('download_file'))

    return render_template('index.html')
```

After creating the upload file API already. So, I will create a download file API.   

```python
# download page
@application.route('/download', methods=['POST', 'GET'])
def download_file():
    if request.method == 'POST':
        if request.form['Download Result File'] == 'Download File':
            return send_from_directory(application.config['UPLOAD_FOLDER'], 'result_file.txt')
```

For the HTML side, I have to create index.html and download.html on templates folder.

**index.html**

```html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
    <title>Download File</title>
</head>

<body>
    <div class="container">
        <section class="vh-100 gradient-custom">
            <div class="text-center justify-content-between py-4 px-4 px-xl-5 bg-dark">
                <div class="text-white mb-2 mb-md-0">
                    <p>Download File</p>
                </div>
            </div>
            <div class="container-fluid h-custom py-4">
                <div class="h-100">
                    <div class="row d-flex justify-content-center align-items-center h-100">
                        <div class="col-12 col-md-9 col-lg-7 col-xl-6">
                            <div class="card" style="border-radius: 15px;">
                                <div class="card-body p-5">
                                    <form method=post enctype=multipart/form-data>
                                        <div style="text-align:center;">
                                            <div class="form-outline mb-4">
                                                <input type=file name=file>
                                            </div>
                                            <div class="form-outline mb-4">
                                                <button type=submit class="btn btn-primary">Upload</button>
                                            </div>
                                        </div>
                                    </form>

                                    {% with messages = get_flashed_messages() %} {% if messages %}
                                    <ul class=flashes>
                                        {% for message in messages %}
                                        <li>{{ message }}</li>
                                        {% endfor %}
                                    </ul>
                                    {% endif %} {% endwith %}
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </section>
    </div>
</body>

</html>
```

**download.html**

```html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
    <title>Download File Success</title>
</head>

<body>
    <div class="container">
        <section class="vh-100 gradient-custom">
            <div class="container-fluid h-custom py-4">
                <div class="h-100">
                    <div class="row d-flex justify-content-center align-items-center h-100">
                        <div class="col-12 col-md-9 col-lg-7 col-xl-6">
                            <div class="card" style="border-radius: 15px;">
                                <div class="card-body p-5">
                                    <h2 class="text-uppercase text-center mb-5">Download result file</h2>
                                    <form method=post>
                                        <div style="text-align:center;">
                                            <div class="form-outline mb-4">
                                                <input type="submit" name="Download Result File" value="Download BPMN File">
                                            </div>
                                        </div>
                                    </form>
                                    <div style="text-align:center;">
                                        <a href="{{url_for('upload_file')}}">Back to Upload File</a>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </section>
    </div>
</body>

</html>
```

**Result app.py**

```python
import os
import json
from flask import Flask, request, render_template, flash, redirect, url_for, send_from_directory
from werkzeug.utils import secure_filename

ALLOWED_EXTENSIONS = {'txt'}

application = Flask(__name__)
application.secret_key = os.urandom(24)
application.config['UPLOAD_FOLDER'] = 'data'
application.config['MAX_CONTENT_LENGTH'] = 4 * 1024 * 1024  # 4MB max-limit.

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.',1)[1].lower() in ALLOWED_EXTENSIONS

# home page
@application.route('/', methods=['POST', 'GET'])
def upload_file():
    if request.method == 'POST':
       if 'file' not in request.files:
          flash('No file part')
          return redirect(request.url)
       
       file = request.files['file']

       read_text = []
       for text in request.files.get('file'):
          read_text.append(str(text).replace("b'",""))
       print(read_text[0])

       # if the user does not select a file, the browser submits an empty file without a filename.
       if file.filename == '':
         flash('No selected file')
         return redirect(request.url)

       # if the user submits a file with the correct format
       if file and allowed_file(file.filename):
         filename = secure_filename(file.filename)
         file.save(os.path.join(application.config['UPLOAD_FOLDER'], filename))
         os.remove(os.path.join(application.config['UPLOAD_FOLDER'], filename))
         return redirect(url_for('download_file'))

    return render_template('index.html')

# download page
@application.route('/download', methods=['POST', 'GET'])
def download_file():
    if request.method == 'POST':
        if request.form['Download Result File'] == 'Download File':
            return send_from_directory(application.config['UPLOAD_FOLDER'], 'result_file.txt')
```