Streamlit, Custom Components wrapping API

Anthony Alteirac
3 min readSep 29, 2022

--

As part of our work for the Power By Snowflake program, we promote our partners’ solutions through various channels.

Streamlit recently joined the Snowflake family and I strongly believe it can become a great vehicle to accelerate visibility and usage of our partners’ platforms.

With one of them, we are envisioning a Streamlit application that visualizes the results of marketing campaigns and predicts the results of future campaigns through an ML module.

We’d like to have an easy-to-handle “component” for Streamlit developers that allows them to write the prediction results back into the partner’s platform (which will end up in Snowflake). This can be done with a simple button from the user’s perspective. The goal being to abstract the call to the partner API for the developer, he/she will only need to instantiate the “Save Data” button component by simply filling in the login credentials.

This will shows something like this:

Of course we could use the raw API directly in the application, using a callback function on the out-of-box button. But we really wanted to wrap everything in a simple custom component and make developer’ life as easy as possible.

In order to build this button component and for sake of simplicity and readability, I’ll use vanilla JS, not the React flavor.

The API call itself has to happen in the component python code, for obvious reason (python code is backend)

The JS part is rather simple, a button :-)

The returned value from JS: button clicked, boolean

So far so good!

Houston ?

BUT, because of the way Streamlit rerun the code each time, if you press the button once, any other interaction on the application will cause the API call to be executed again! This behavior is due to the fact that Streamlit assigns the component the value of the last execution.

This is not related to API call, it’s a generic issue when trying to trigger Python code from JS user action.

JS Pseudo Code:

Python Pseudo Code:

Solution

Here’s the pattern I’ve used to workaround:

JS Pseudo Code:

Clicking on the button will always return a different value (I use random for simplicity)

Python Pseudo Code:

Doing that way, the button always returns a different value, I compare with the last run and then trigger the API call only when the button has been pressed.

This pattern can be used for any component needing to trigger Python function from a JS user input (button, text input etc)

Hope it can help!

Happy coding!

--

--

No responses yet