Send request to Flask api with Dash inside

I have a stack overflow post on this question: https://stackoverflow.com/questions/55504078/sending-request-to-flask-api-within-a-plotly-dash-app

Essentially I have a Dash app inside of a Flask app and I want to send a request to the Flask API using python requests package where I have a dataframe saved in the Flask session in json format. But when I send the request I just get back the page html (see in post).

I’m not sure what I’m doing wrong, or maybe you cannot pull that json from a request when it’s in a Dash app?

Check what is happening with your if statement, print out the resut, eg.:

print('IM IN ROUTE /TEST')
print('data' not in flask.session)

if 'data' not in flask.session:

I’m guessing this if condition is returning True and you are being redirected to the Dash app, as per your flask.redirect.

In fact I’m not sure why you would think anything else would happen. Try putting a breakpoint() there in the code and inspecting the variables to see what they actually contain.

1 Like

You’re right, it returns True. So does that mean I can’t send a request to that flask session from a separate script? Maybe this is more of a requests question than a Dash question.

I’m pretty new to API requests.

You can, but it’s not as simple as you might think. You need to understand where the data is being stored and how it is being accessed. And as best as I can tell you’ve not provided any example of how you’re actually trying to do it here.

Now for flask.session the data is stored on the client side: http://flask.pocoo.org/docs/1.0/api/#sessions

session makes it possible to remember information from one request to another. The way Flask does this is by using a signed cookie

In this case you are making a single request, there is nothing stored on the client side and therefore no cookie it can read the data out of. You can store cookies with requests, but you need to make multiple requests with the Sessions object: Advanced Usage — Requests 2.31.0 documentation . And I’m not sure that’s what you want.

I think you should take a step back and ask a new question around what you’re actually trying to achieve not how you think you should solve it.

Thank you, this helps a lot. Just for clarification, my thought was that I could have a user upload a csv to the Dash page, then save that csv in the flask session, then have another script request that csv in json form via a Flask api. Maybe this is not the best method of going about this I guess. Here’s my full code in case you’re interested:

I store the uploaded csv in the flask session, and then also store that json in a hidden div.

import base64
import datetime
import io
import os

import dash
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
import dash_table

import flask
import uuid

import pandas as pd


external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

server = flask.Flask(__name__)
app = dash.Dash(__name__, sharing=True, server=server, csrf_protect=False, external_stylesheets=external_stylesheets, routes_pathname_prefix='/dash/')

app.config.suppress_callback_exceptions = True

app.server.secret_key = str(uuid.uuid4())

app.layout = html.Div([
    dcc.Upload(
        id='upload-data',
        children=html.Div([
            'Drag and Drop or ',
            html.A('Select Files')
        ]),
        style={
            'width': '100%',
            'height': '60px',
            'lineHeight': '60px',
            'borderWidth': '1px',
            'borderStyle': 'dashed',
            'borderRadius': '5px',
            'textAlign': 'center',
            'margin': '10px'
        },
        # Allow multiple files to be uploaded
        multiple=True
    ),
    html.Div(id='output-data-upload'),
    html.Div(id='hidden-div0', style = {'visibility': 'hidden'}),
    html.Div(id='hidden-div1', style = {'visibility': 'hidden'}),
])

def store_df(contents, filename):
    content_type, content_string = contents.split(',')

    decoded = base64.b64decode(content_string)
    try:
        if 'csv' in filename:
            # Assume that the user uploaded a CSV file
            df = pd.read_csv(
                io.StringIO(decoded.decode('utf-8')))
        elif 'xls' in filename:
            # Assume that the user uploaded an excel file
            df = pd.read_excel(io.BytesIO(decoded))
    except Exception as e:
        print(e)
        return html.Div([
            'There was an error processing this file.'
        ])
    return df


def parse_contents(contents, filename, date):
    content_type, content_string = contents.split(',')

    decoded = base64.b64decode(content_string)
    try:
        if 'csv' in filename:
            # Assume that the user uploaded a CSV file
            df = pd.read_csv(
                io.StringIO(decoded.decode('utf-8')))
        elif 'xls' in filename:
            # Assume that the user uploaded an excel file
            df = pd.read_excel(io.BytesIO(decoded))
    except Exception as e:
        print(e)
        return html.Div([
            'There was an error processing this file.'
        ])

    return html.Div([
        html.H5(filename),
        html.H6(datetime.datetime.fromtimestamp(date)),

        dash_table.DataTable(
            data=df.to_dict('rows'),
            columns=[{'name': i, 'id': i} for i in df.columns]
        ),

        html.Hr(),  # horizontal line

        # For debugging, display the raw contents provided by the web browser
        html.Div('Raw Content'),
        html.Pre(contents[0:200] + '...', style={
            'whiteSpace': 'pre-wrap',
            'wordBreak': 'break-all'
        })
    ])


@app.callback(Output('output-data-upload', 'children'),
              [Input('upload-data', 'contents')],
              [State('upload-data', 'filename'),
               State('upload-data', 'last_modified')])
def update_output(list_of_contents, list_of_names, list_of_dates):
    if list_of_contents is not None:
        children = [
            parse_contents(c, n, d) for c, n, d in
            zip(list_of_contents, list_of_names, list_of_dates)]
        return children


@app.callback(Output('hidden-div0', 'children'),
              [Input('upload-data', 'contents')],
              [State('upload-data', 'filename')])
def update_output(list_of_contents, list_of_names):
    if list_of_contents is not None:
        df = [store_df(c, f) for c, f in zip(list_of_contents,list_of_names)][0]

        print(df)

        flask.session['data'] = df.to_json()

        return df.to_json(date_format='iso', orient='split')


@server.route('/')
def index():
    return flask.redirect(flask.url_for('/dash/'))


@server.route('/test/', methods=['GET'])
def test_api_request():
    print('IM IN ROUTE /TEST')

    print('data' not in flask.session)

    if 'data' not in flask.session:
        return flask.redirect(flask.url_for('/dash/'))

    return flask.session['data']


if __name__ == '__main__':
    # os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
    app.run_server(host='0.0.0.0', debug=True)