0

New to programming in python. Looking to connect to an API, but don't fully understand calling arguments within a string, using curly braces. I realize this is a fairly basic concept, but I've been search and can't really find an explanation other than using .format()

values = """
{
    "postUserLogin":{
        "login":"{email_address}",
        "password":"{password}",
        "remember":1|0,
        "verify_level":0|2
    }
}"""

I tried

values.format(email_address ='test_email@gmail.com', password='mypass')

and I've tried just setting the variable normally.

Full API documentation to use from GoodData: https://help.gooddata.com/display/doc/API+Reference#/reference/authentication/log-in/log-in

from urllib2 import Request, urlopen

values = """
{
    "postUserLogin":{
        "login":"{email_address}",
        "password":"{password}",
        "remember":1|0,
        "verify_level":0|2
    }
}"""

headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}
request = Request('https://secure.gooddata.com/gdc/account/login', data=values, headers=headers)

response_body = urlopen(request).read()
print response_body
Matt W.
  • 3,692
  • 2
  • 23
  • 46
  • 2
    why do you need a string representing a dictionary instead of the dictionary itself? – Julien Spronck Mar 13 '18 at 23:22
  • 1
    And what happens? What error do you see? More importantly, what is the API you are trying to call? As @JulienSpronck suggests, perhaps the API expects a dictionary, not a string representing one. `"remember":1|0` looks highly suspicious as a parameter. – Ken Y-N Mar 13 '18 at 23:24
  • 2
    If you _do_ need a string representing a dictionary instead of the dictionary itself, it's very likely that what you actually need is JSON. Which means you should first manipulate the dictionary using normal Python stuff, and then do a `json.dumps(d)` to get the string to pass to the API at the end. – abarnert Mar 13 '18 at 23:25
  • The API I'm looking to connect to is the GoodData API -- https://help.gooddata.com/display/doc/API+Reference#/reference/authentication/log-in It gives code for connecting via the login, and then downloading data etc. I'm trying to just teach myself how to connect and post so I can effectively download what is in there to use in another script. – Matt W. Mar 13 '18 at 23:25
  • Anyway, if you really do want to use `str.format` to fill in `{…}` variables within a string template, you have to escape (by doubling) all the other curly braces in the template. Your attempt is going to complain that you didn't provide a value for the whole messy contents of the expression representing the value of `postUserLogin`. – abarnert Mar 13 '18 at 23:27
  • Yeah that is the error I got initailly, and makes sense why I got it. The documentation I have directs me to using JSON – Matt W. Mar 13 '18 at 23:28
  • Please see the dup; you would do something like `values = {"postUserLogin": {"login": "foo@example.com", "remember": remember_flag ... etc... }}`. – Ken Y-N Mar 13 '18 at 23:34

1 Answers1

3

You're trying to connect to a web service API that takes JSON. (It looks like it can also take form-encoded data, but ignore that; JSON will be easier for you to understand.)

So, don't try to build the strings manually. Instead, build the equivalent objects in Python, and then JSON-encode them at the end. Like this:

values = {
    "postUserLogin": {
        "login": 'test_email@gmail.com', 
        "password": 'mypass',
        "remember": 1|0,
        "verify_level":0|2
    }
}

Or, of course, you can use variables or constants or function calls instead of hardcoded literals for some or all of the values—this is just a normal Python dict display, so you can do anything you can do in any Python expression.

values = {
    "postUserLogin": {
        "login": my_email,
        "password": my_password,
        "remember": look_up_remember_flag(),
        "verify_level": 2
    }
}

Then, at some point, something like this:

encoded_values = json.dumps(values)
my_favorite_http_library.post(my_url, data=encoded_values)

You may also need to set the Content-Type header to tell the service you're sending JSON.

It's worth noting that some HTTP libraries can automatically handle encoding to JSON and setting the header for you, which is pretty nice. I don't remember off the top of my head whether urllib.request does, but if you can't figure it out yourself from the docs, you can ask a new question explaining where you're confused.


As a side note, that 1|0 in the spec means that you're supposed to send either 1 or 0, and presumably it explains what those different values mean. If you literally use 1|0, that's a bitwise or between 1 or 0, and the value will be 1, which is one of the values the service is expecting, but it may or may not be the one you wanted to send.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • Thank you for the explanation, that was extremely helpful and solved my issue. I learned a lot through your post. Still confused on the remaining steps but I'll work through them or post new questions. Thanks again! – Matt W. Mar 14 '18 at 03:35