0

Im trying to write a REST Client for a closed API. I call a specific function twice but it only works the first time. It's the same command. If i run the script twice with batch It works. Im suspecting Requests keeps the connection alive or caches data. How do i "reset" Requests ?

base_headers = {"Connection":"keep-alive",
            "User-Agent":user_agent,
            "Accept-Encoding":"gzip",
            "Host":"xxxxxxxxxxx",
            "Content-Type":"application/json; charset=UTF-8"}
global auth
auth = 'xxxxxx'


def create_header(doAuth = True):
    headers = base_headers
    if doAuth:
       headers['Authorization'] = auth
    return headers
def do_get(url):
    return requests.get(url, headers=create_header());


def do_put(url, payload):
    if payload is None:
        return requests.put(url, headers=create_header())

    return requests.put(url, data=payload, headers=create_header())


def upvote(postid):
    return do_put("xxxxxxxxxxxxx" % postid, None).content


def set_pos(longtitude, latitude, place, country="DE"):
    payload = {'xxxxx':'xxxx'}

    json_payload = json.dumps(payload)

    return do_put("xxxxxxxxxxxxxxx",json_payload).content


def do_post(url, payload, doAuth=True):
    return requests.post(url, data=payload, headers=create_header(doAuth=doAuth))

def new_acc(place, latitude, longtitude):
    access = get_access_token(place, latitude, longtitude)
    print access
    global auth
    auth = "Bearer %s" % access['access_token']
    set_pos(longtitude, latitude, place) # Does a POST

for i in range(1,30):
    posts = new_acc(uni['city'], uni['latitude'], uni['longtitude'])
    upvote('xxxxxxxxxxxxx')

Basically the first upvote() goes through every time but every succeding does not.

Jan
  • 205
  • 3
  • 9
  • 2
    Connection pooling only happens when you use a session. How are you calling the API, can you share sample code? – Martijn Pieters Nov 11 '15 at 22:48
  • 1
    Also see [Python-Requests close http connection](http://stackoverflow.com/q/10115126) – Martijn Pieters Nov 11 '15 at 22:48
  • 1
    There is no definition for the `upvote()`, `get_access_token()`, `create_header()` and `set_pos()` functions. – Martijn Pieters Nov 11 '15 at 23:12
  • Sidenote: `data` defaults to `None`, there is no need to branch in `do_put()`; just pass in `data=payload` and if `payload` is set to `None` things work as expected anyway. – Martijn Pieters Nov 11 '15 at 23:13
  • @MartijnPieters done – Jan Nov 11 '15 at 23:23
  • You've modified the global headers dictionary. `Auth` is now always present the moment you do `auth=True`. Not likely the cause of your problems, but a problems nonetheless. Using `global` outside of a function is pointless, the names set outside functions are already globals. – Martijn Pieters Nov 11 '15 at 23:47
  • 2
    Further notes: Don't set the `Host` header, `requests` handles that for you. Use the `json` keyword argument and you don't need to encode to JSON yourself and you don't have to set the `Content-Type` header. – Martijn Pieters Nov 11 '15 at 23:49
  • 2
    Next, look into using a Session object and have it handle common headers, like `Auth`. Create one Session object per authentication token, for example, and reuse that. – Martijn Pieters Nov 11 '15 at 23:50
  • @Jan can you explain what you mean when you say subsequent requests do not succeed. How do you determine success? – Ian Stapleton Cordasco Nov 12 '15 at 04:06
  • @sigmavirus24 First call returns 200. The proceeding call return 404. – Jan Nov 12 '15 at 07:22

1 Answers1

1

I'm almost positive that keep-alive is not doing this. I would suggest writing some handlers to debug the response if you don't get the expected response code after the request.

Also, might I suggest a slightly different design that avoids global?

class RESTClient(object):

    BASE_HEADERS = {"Connection":"keep-alive",
                    "Accept-Encoding":"gzip",
                    "Host":"xxxxxxxxxxx",
                    "Content-Type":"application/json; charset=UTF-8"}

    def __init__(self, user_agent, auth = None):
        self.headers = dict(self.BASE_HEADERS)
        self.headers['User-Agent'] = user_agent
        self.auth = auth

    def create_header(self):
        headers = dict(self.headers)
        if auth:
            headers['Authorization'] = auth
        return headers

    def do_get(self, url):
        return requests.get(url, headers=self.create_header());


    def do_put(self, url, payload = None):
        if not payload:
            return requests.put(url, headers=self.create_header())
        return requests.put(url, data=payload, headers=self.create_header())


    def upvote(self, postid):
        return do_put("xxxxxxxxxxxxx" % postid).content

    def set_pos(self, longtitude, latitude, place, country="DE"):
        payload = {'xxxxx':'xxxx'}
        json_payload = json.dumps(payload)
        return do_put("xxxxxxxxxxxxxxx",json_payload).content

    def do_post(self, url, payload, do_auth = None):
        return requests.post(url, data=payload, headers=self.create_header())

    def new_acc(self, place, latitude, longtitude):
        access = get_access_token(place, latitude, longtitude)
        print access
        self.auth = "Bearer %s" % access['access_token']
        set_pos(longtitude, latitude, place)

rc = RESTClient('Mozilla/5.0 ... Firefox/38.0', 'my-auth-token')
rc.upvote(post_id)
etc...

It could be that your use of globals is breaking things. Having not run your code, I can't check, but I would avoid using globals and favor tighter control of your state via objects.

EDIT: Given that this answer was accepted by the OP, I am assuming the defect was caused by mutation of globals.

Bobby Russell
  • 475
  • 2
  • 12