I'm generating a URL (in string) that depends on 3 optional parameters, file
, user
and active
.
From a base url: /hey
I want to generate the endpoint, this means:
- If
file
is specificied, my desired output would is:/hey?file=example
- If
file
anduser
is specified, my desired output is:/hey?file=example&user=boo
- If
user
andactive
are specified, my desired output is:/hey?user=boo&active=1
- If no optional parameters are specified, my desired output is:
/hey
- and so on with all the combinations...
My code, which is working correctly, is as follows (change the None
's at the top if you want to test it):
file = None
user = None
active = 1
ep = "/hey"
isFirst = True
if file:
if isFirst:
ep+= "?file=" + file;
isFirst = False;
else: ep += "&file=" + file;
if user:
if isFirst:
ep+= "?user=" + user;
isFirst = False;
else: ep += "&user=" + user;
if active:
if isFirst:
ep+= "?active=" + str(active);
isFirst = False;
else: ep += "&active=" + str(active);
print ep
Can someone give me a more python implementation for this? I can't use modules as requests
.
Thanks in advance.
2 Answers 2
The most Pythonic version of this depends a bit on what you do with that URL afterwards. If you are using the requests
module (which you probably should), this is already built-in by specifying the params
keyword:
import requests
URL = "https://example.com/hey"
r1 = requests.get(URL, params={"file": "example"})
print(r1.url)
# https://example.com/hey?file=example
r2 = requests.get(URL, params={"file": "example", "user": "boo"})
print(r2.url)
# https://example.com/hey?file=example&user=boo
r3 = requests.get(URL, params={"user": "boo", "active": 1})
print(r3.url)
# https://example.com/hey?user=boo&active=1
r4 = requests.get(URL, params={})
print(r4.url)
# https://example.com/hey
If you do need a pure Python solution without any imports, this is what I would do:
def get_url(base_url, **kwargs):
if not kwargs:
return base_url
params = "&".join(f"{key}={value}" for key, value in kwargs.items())
return base_url + "?" + params
Of course this does not urlencode the keys and values and may therefore be a security risk or fail unexpectedly, but neither does your code.
Example usage:
print(get_url("/hey", file="example"))
# /hey?file=example
print(get_url("/hey", file="example", user="boo"))
# /hey?file=example&user=boo
print(get_url("/hey", user="boo", active=1))
# /hey?user=boo&active=1
print(get_url("/hey"))
# /hey
-
\$\begingroup\$ Due to the implementation of the rest of the code, I need to do it everything without any requests module, just improving the code I posted using strings. \$\endgroup\$Avión– Avión2018年12月17日 10:09:18 +00:00Commented Dec 17, 2018 at 10:09
-
2\$\begingroup\$ @Avión: Just did. It captures all keyword arguments you pass to the function into one dictionary. \$\endgroup\$Graipher– Graipher2018年12月17日 10:13:13 +00:00Commented Dec 17, 2018 at 10:13
-
4\$\begingroup\$ Your code is good for illustrative purposes but it fails to URLencode the parameters and is therefore a potential security risk. \$\endgroup\$Konrad Rudolph– Konrad Rudolph2018年12月17日 14:35:32 +00:00Commented Dec 17, 2018 at 14:35
-
1\$\begingroup\$ @KonradRudolph Added a short disclaimer regarding that. \$\endgroup\$Graipher– Graipher2018年12月17日 14:38:32 +00:00Commented Dec 17, 2018 at 14:38
-
1\$\begingroup\$ It's not just that it's a security risk, it's also that if you have
&
in one of the values, it will fail to send the correct value (and most likely fail in general, unless there's also another=
in the values). \$\endgroup\$ChatterOne– ChatterOne2018年12月18日 08:33:18 +00:00Commented Dec 18, 2018 at 8:33
You're pretty much reinventing urllib.parse.urlencode
:
from urllib.parse import urlencode
def prepare_query_string(**kwargs):
return urlencode([(key, value) for key, value in kwargs.items() if value is not None])
Usage being:
>>> prepare_query_string(active=1)
'active=1'
>>> prepare_query_string(active=1, user=None)
'active=1'
>>> prepare_query_string(active=1, user='bob')
'active=1&user=bob'
>>> prepare_query_string(file='foo.tar.gz', user='bob')
'file=foo.tar.gz&user=bob'
>>> prepare_query_string(file='foo.tar.gz', user='bob', active=None)
'file=foo.tar.gz&user=bob'
>>> prepare_query_string(file='foo.tar.gz', user='bob', active=1)
'file=foo.tar.gz&user=bob&active=1'
;
. makes python look ugly \$\endgroup\$