The below code doesn’t work in Client code, which is where I’d like it to run, due to an import error. (Note: Imports are inside the function because Anvil complains about “not able to call a function here” when performed at the top of the file).
Error:
ModuleNotFoundError: No module named 'urllib.parse'
Code:
def get_short_url(long_url, *args, **kwargs):
API_URL = "http://tinyurl.com/api-create.php" # The URL shortner API: TinyURL
try:
from urllib.request import urlopen
from urllib.parse import urlencode # <-- Offending statement.
url = f"""{API_URL}?{urlencode({"url":long_url})}"""
with urlopen(url) as response:
short_url = response.read().decode('utf-8')
except Exception as e:
short_url = None
return short_url
The code works outside of Anvil.
Does anyone know what I can substitute for urllib above? (urllib3 is only available for Server Modules). Or perhaps has Client-working URL shortener code that uses a free shortener service (like TinyURL).
Lacking any suggestions on a prebuilt way of doing this on the client, you might look at the source for urlencode and see if you can port it to the client. It might work as is, or it might rely on features not yet in Skulpt: cpython/parse.py at main · python/cpython · GitHub
This approach looks interesting. Not totally yet familiar with the Anvil API, I didn’t think of this. Let me look into this later and post back. Thank you!
Anvil.http is a library that can be imported into either client or server Anvil code - which if I understand correctly, you’re hoping to use instead of code in an Anvil server module. So I’d expect you to run anvil.http methods in a function in your Anvil client code, which could be called from uplink code (not loaded into code running on your local machine connected by the uplink).
You’re likely going to have a problem with anvil.http methods in Anvil client modules (running cross domain requests). You won’t have those same problems when using anvil.http methods in Anvil server modules, but if you’ve got an uplink running, you could just run the code you first presented at the beginning of this thread, there… but that seems like an unnecessary kludge because that exact functionality can be achieved by just moving some code into an Anvil server module, and then your app doesn’t require an uplink machine. I think of uplink being most useful the other way around - using the uplink as a server to perform heavy lifting that’s difficult or impossible to achieve on Anvil servers (some library that can’t be loaded in your Anvil account, or controlling some local hardware, etc).
I don’t know if you got a chance to check out the clone I linked above - it’s fully functional, using the exact code that you presented (just it moved out of a client module, and into a server module). Either way, I’m hoping to understand where the benefit of calling anvil.http methods in client modules, from calls in uplink code. Why go to all the trouble of running code in Anvil client modules (which will get stuck executing cross domain requests), when you could just run your original code on the uplink machine - or even better, simply in an Anvil server module?
Hi. No the Uplink was just to perform some quick ad-hoc iteration via a REPL, not for anything permanent. Thank you for the explanation. Yes I saw the code share.
The CORS issues Nick mentioned are likely to continue to be an issue on the client side. Browsers are pretty particular about which domains you connect out to from a client web app.
If you run the code above and copy the printed ‘url’ value into you browser, it returns a proper response (should also work in curl, etc.).
anvil.http.request(url) above returns 'HttpError: HTTP error 0". If anyone has some experience handling cross-origin requests as mentioned in part 3 of Anvil Docs | Making HTTP requests (‘It needs to respond to an OPTIONS request, have the right CORS headers, etc.’), I’d love to learn how that’s done.
I’ll take a look at the JS library I mentioned - they do call the API from client code (perhaps it’s connecting to some backend code that I didn’t notice at first)…