More complex APIs: Upload and Download Files with Flask

This example demonstrates uploading and downloading files to and from a Flask API.

Python Source Code

import os

from flask import Flask, request, abort, jsonify, send_from_directory


UPLOAD_DIRECTORY = "/project/api_uploaded_files"

if not os.path.exists(UPLOAD_DIRECTORY):
    os.makedirs(UPLOAD_DIRECTORY)


api = Flask(__name__)


@api.route("/files")
def list_files():
    """Endpoint to list files on the server."""
    files = []
    for filename in os.listdir(UPLOAD_DIRECTORY):
        path = os.path.join(UPLOAD_DIRECTORY, filename)
        if os.path.isfile(path):
            files.append(filename)
    return jsonify(files)


@api.route("/files/<path:path>")
def get_file(path):
    """Download a file."""
    return send_from_directory(UPLOAD_DIRECTORY, path, as_attachment=True)


@api.route("/files/<filename>", methods=["POST"])
def post_file(filename):
    """Upload a file."""

    if "/" in filename:
        # Return 400 BAD REQUEST
        abort(400, "no subdirectories directories allowed")

    with open(os.path.join(UPLOAD_DIRECTORY, filename), "wb") as fp:
        fp.write(request.data)

    # Return 201 CREATED
    return "", 201


if __name__ == "__main__":
    api.run(debug=True, port=8000)

Deployment

Assuming that you store this file as myapi.py to /project/myapidirectory in your project workspace, create an API in SherlockML with the following settings:

  • Type: Flask
  • Working Directory: /project/myapidirectory
  • Python module: myapi
  • Python object: api

Usage

Once you’ve spun up a development server for your API in SherlockML, get the URL and API Key for the server for the interface. Then, using Python requests (or any other suitable HTTP client), you can list the files on the server with:

import requests

API_URL = 'https://cube-64e0d7d8-1a3d-4fec-82da-fa7afea9138e.api.sherlockml.io'
API_KEY = 'i0cgsdYL3hpeOGkoGmA2TxzJ8LbbU1HpbkZo8B3kFG2bRKjx3V'

headers = {'SherlockML-UserAPI-Key': API_KEY}

response = requests.get('{}/files'.format(API_URL), headers=headers)

response.json()
>>> ['file1.txt', 'data.csv']

Upload new files with requests.post():

with open('newdata.csv') as fp:
    content = fp.read()

response = requests.post(
    '{}/files/newdata.csv'.format(API_URL), headers=headers, data=content
)

response.status_code
>>> 201

And download them with requests.get():

response = requests.get(
    '{}/files/newdata.csv'.format(API_URL), headers=headers
)

response.text
>>> '1,Joe Bloggs,27\n'