Equivalent of getWebAppBackendUrl in Python?
I would like to get the `WebAppBackendUrl` from the Python backend, i.e. I need the Python equivalent of the `getWebAppBackendUrl` JavaScript function. Looking at the path manually, I have construction a function that *almost* does what I need,
def get_web_app_backend_url():
magic_id = "HLc3IXv8" # TODO: What is this? How to get it? Hardcoded for now...
return f"web-apps-backends/{os.environ.get('DKU_CURRENT_PROJECT_KEY')}/{magic_id}"
However, I haven't found out what the magic_id is. It's not in environment variables. And it's not the WEBAPP_ID. Does anyone know how what it is; or even better - how to get it?
Answers
-
HI @emher
!Unfortunately, it is impossible to get the ID of the webapp you are running on. You have to hardcode it.
The ID is a random string generated by DSS. You can find it in the search bar (${webappID}_${webappNAME}) or in the iframe generated in HTML.
Is it possible to say a little bit more about your use-case to see if there is no workaround?
-
Hi HenriC,
I am sorry to hear that. Is the magic_id constant? Could I cache it after creating the app or something like that? I need it before the first request is made. Note that the magic_id if different from the WEBAPP_ID.
I am creating a small template to setup Plotly Dash applications in dataiku. In Plotly Dash, the page interacitivity is achieved via requests from the frontend application. These requests must be prefixed with the web app backend url for the application to work, i.e. I am passing the web_app_backend_url like this,
dash_app = dash.Dash(__name__, requests_pathname_prefix=web_app_backend_url)
With this setup everything works as intended. Well, apart from the user having to manually enter the magic_id. It would be much leaner, if the requests_pathname_prefix was generated automatically.
-
Hi Emher,
You can get the id from the REST API using the correct API key at the following endpoint:
{Your DSS URL}public/api/projects/{your project key}/webapps/
which will return a JSON response for the web apps for that project. You can then view the 'magic id' in the id field.
Knowing this we can construct a python call to the REST endpoint and pull out the id from there. The following code is using a project that only has a single web app, so we can hardcode the index to 0. A project with multiple web apps will need some additional logic. Additionally, make sure the code environment used for the project has the requests module installed (the default DSS built in environment will suffice)
import dataiku import pandas as pd from flask import request import requests @app.route('/first_api_call') def first_call(): host='http://localhost:3803' project = 'DKU_TUTORIAL_DATAIKU_APPS_1' apikey='8cEnl8KVBOKdDxMxnhgka4x9hjY9fnpJ' #Use an API key that has access to the project session = requests.Session() session.auth = (apikey, '') auth = session.post(host) response = session.get(host +'/public/api/projects/'+project+'/webapps/') #only one web app in this project, so we can hardcode to 0. If you have multiple web apps, you will need additional logic here to get the correct web app jsonResponse = json.loads(response.text)[0] magicId = jsonResponse["id"] return json.dumps(magicId)
This code is only an example, you will need to modify it further to suit your needs.
Thank you,
Andrew M
-
Hi Andrew,
Thanks for the example! Using your code I was able to get the WEBAPP_ID before launching the app, which feels like a step forward. However, as noted before, it is a different ID that I am looking for (that's why I called it magic_id). As an example, if I add this JavaScript snippet,
console.log(getWebAppBackendUrl('/'))
it will print the following URL to the JavaScript console,
/web-apps-backends/DKU_TUTORIAL_MACHINE_LEARNING_BASICS/HLc3IXv8/
The ID I am interested in is HLc3IXv8. Since I am a total newbie to dataiku (I just started using it a few days ago), I am not sure what to call this ID, hence I have called it magic_id so far. If I look at the URL in the browser, it says
http://localhost:11000/projects/DKU_TUTORIAL_MACHINE_LEARNING_BASICS/webapps/jfL3nSj_advanced/edit
where, as I understand, the WEBAPP_ID is jfL3nSJ. This is also in agreement with the code you posted; it returns jfL3nSJ in the end. However, I still need to get the other ID, i.e. in this example HLc3IXv8.
-
Hi Emher,
That ID is dynamically generated each time the web app backend starts, meaning it probably can't be hardcoded either, as it will change after each restart.
I've found a workaround for this. We cannot actually get the web app backend URL from Python, however, we can pass it in as a query string parameter from the JS file and then parse that parameter out of the URL. I've included some updated sample code below.
You can modify the JS file code to look like this for the endpoint call:
$.getJSON(getWebAppBackendUrl('/first_api_call?URL='+getWebAppBackendUrl(''))
notice the addition of the query string parameter, URL. This is passed in when the call is made, which means we can parse the URL to get the ID. The rest of JS function can remain as-is.
Here's what my full JS function looks like for reference:
$.getJSON(getWebAppBackendUrl('/first_api_call?URL='+getWebAppBackendUrl('')), function(data) { console.log('Received data from backend', data) console.log(getWebAppBackendUrl('/')) const output = $('<pre />').text('Backend reply: ' + JSON.stringify(data) + ' ' + getWebAppBackendUrl('')); $('body').append(output) });
The python code will now look like this:
import dataiku import pandas as pd from flask import request #import requests import urlparse @app.route('/first_api_call') def first_call(): #Get the full path of the call from the JS and parse into a URL Python can work with #The JS is passing in a query string parameter called URL with the getWebAppBackend() content path_info = request.url parsed = urlparse.urlparse(path_info) #Pull out the query string parameter we passed in value= urlparse.parse_qs(parsed.query)['URL'] #Perform some processing on it. Need to convert it to a string #Then get the length #Then get the acual ID value from the URL parameter. #NOTE: YOU MAY NEED TO PLAY AROUND WITH THE SUBSTRING VALUES sValue = str(value).rstrip() l=len(sValue) magicId = sValue[l-11:l-3] # host='http://localhost:3803' # project = 'DKU_TUTORIAL_DATAIKU_APPS_1' # apikey='8cEnl8KVBOKdDxMxnhgka4x9hjY9fnpJ' #Use an API key that has access to the project # session = requests.Session() # session.auth = (apikey, '') # auth = session.post(host) # response = session.get(host +'/public/api/projects/'+project+'/webapps/') # jsonResponse = json.loads(response.text)[0] # magicId = jsonResponse["id"] return json.dumps({"id": magicId})
Notice the new library import, urlparse. This allows us to parse the current URL for any query string parameters and strip them out. From there we can convert it to a string and then select a substring that has the ID in it. This is probably not needed for your use case though. Based on your first message, it looks like you're just trying to rebuild the URL anyway. You can probably just pass it in and then skip the ID parsing part.
Hope this helps.
Andrew M
-
Hi Andrew,
passing the webAppBackendUrl as a parameter was in fact also my initial idea. The problem with this approach is that the parameter is needed before the server starts. I have ended up with a slightly hacky fix, where webAppBackendUrl is written to a file, and the user will then have to restart the backend for the changes to be applied. It's not perfect, but it seems to work reliably. And since the magic_id might change (as you noted), I guess this solution is an improvement as compared to simply hardcoding the magic_id .
If you (or anyone else) come up with a way to get the magic_id before the server starts, I am very interested
-
Now that I have a working solution, I was thinking about posting it, so that others can use it too. Is there a recommended way to do these kind of posts? In other forums I would use the "Show & Tell" tag, but I couldn't find an equivalent here.
-
CoreyS Dataiker Alumni, Dataiku DSS Core Designer, Dataiku DSS Core Concepts, Registered Posts: 1,150 ✭✭✭✭✭✭✭✭✭
@emher
We're happy you found the answer you were looking for. For starters you can accept a solution from any of the comments in this thread that provided you with the answer you were looking for. Accepted Solutions are a great way to help both connect people with the answers they need, and recognize the diligent members who invest time to answer questions!We can also look to build this out into a Knowledge Base article as well. I hope this helps!