Skip to content

Api exposure callbacks #3347

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open

Conversation

BSd3v
Copy link
Contributor

@BSd3v BSd3v commented Jun 27, 2025

This PR strives to allow callbacks to be exposed by the underlying server as an API by simply passing the callback a api_endpoint. The api will accept a body with the functional arguments provided as kwargs.

@BSd3v
Copy link
Contributor Author

BSd3v commented Jun 27, 2025

Here is an example of how to spin up the app and how to perform the api calls:

app.py

import time
import dash
from dash import html, dcc, Input, Output, ctx, callback
from flask import jsonify
import asyncio
import json

app = dash.Dash(__name__, use_async=True)
app.layout = html.Div([
    html.Button("Slow Callback", id="slow-btn"),
    html.Div(id="slow-output"),
    html.Button("Fast Callback", id="fast-btn"),
    html.Div(id="fast-output"),
])

async def get_async_data(n_clicks):
    # Simulate an async data fetch
    await asyncio.sleep(1)
    return f"Data fetched - {n_clicks}"

def get_data(n_clicks):
    # Simulate an async data fetch
    time.sleep(1)
    return f"Data fetched - {n_clicks}"

@app.callback(
    Output("slow-output", "children"),
    Input("slow-btn", "n_clicks"),
    prevent_initial_call=True,
    api_endpoint='/api/slow_callback',  # Example API path for the slow callback
)
def slow_callback(n_clicks):
    start = time.time()
    data = {}
    for i in range(5):
        data[f'step_{i}'] = get_data(n_clicks)
    ret = f"{json.dumps(data)} Time taken: {time.time() - start:.2f} seconds"
    if ctx:
        return ret
    return jsonify(ret)

@app.callback(
    Output("fast-output", "children"),
    Input("fast-btn", "n_clicks"),
    prevent_initial_call=True,
    api_endpoint='/api/fast_callback',  # Example API path for the fast callback
)
async def fast_callback(n_clicks):
    start = time.time()
    coros = [get_async_data(n_clicks) for _ in range(5)]
    results = await asyncio.gather(*coros)
    data = {f'step_{i}_async': result for i, result in enumerate(results)}
    ret = f"{json.dumps(data)} Time taken: {time.time() - start:.2f} seconds"
    if ctx:
        return ret
    return jsonify(ret)

app.setup_apis()

if __name__ == "__main__":
    app.run(debug=True)

api calls

import requests

resp = requests.post('http://127.0.0.1:8050/api/slow_callback',
                     json={"n_clicks": 1},
                    headers={"Content-Type": "application/json"})

print(resp.json())

resp = requests.post('http://127.0.0.1:8050/api/fast_callback',
                     json={"n_clicks": 1},
                    headers={"Content-Type": "application/json"})

print(resp.json())

@gvwilson gvwilson added feature something new P2 considered for next cycle community community contribution labels Jul 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
community community contribution feature something new P2 considered for next cycle
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants