Requests works and URLFetch doesn't
Question: I'm trying to make a request to the particle servers in python in a google app
engine app.

In my terminal, I can complete the request simply and successfully with
requests as:

    
    
    res = requests.get('https://api.particle.io/v1/devices', params={"access_token": {ACCESS_TOKEN}})
    

But in my app, the same thing doesn't work with urlfetch, which keeps telling
me it can't find the access token:

    
    
        url = 'https://api.particle.io/v1/devices'
        payload = {"access_token": {ACCESS_TOKEN}}
        form_data = urllib.urlencode(payload)
        res = urlfetch.fetch(
            url=url,
            payload=form_data,
            method=urlfetch.GET,
            headers={
                'Content-Type':
                'application/x-www-form-urlencoded'
            },
            follow_redirects=False 
        )
    

I have no idea what the problem is, and no way to debug. Thanks!


Answer: In a nutshell, your problem is that in your `urlfetch` sample you're embedding
your access token into the request body, and since you're issuing a GET
request -which cannot carry any request body with them- this information gets
discarded.

**Why does your first snippet work?**

Because `requests.get()` takes that optional `params` argument that means:
"take this dictionary I give you, convert all its key/value pairs into a
[query string](https://en.wikipedia.org/wiki/Query_string) and append it to
the main URL"

So, behind the curtains, `requests.get()` is building a string like this:

`https://api.particle.io/v1/devices?access_token=ACCESS_TOKEN`

That's the correct endpoint you should point your GET requests to.

**Why doesn't your second snippet work?**

This time, `urlfetch.fetch()` uses a different syntax than `requests.get()`
(but equivalent nonetheless). The important bit to note here is that `payload`
argument **doesn't** mean the same as our `params` argument that you used
before in `requests.get()`.

`urlfetch.fetch()` expects our query string -if any- to be already urlencoded
into the URL (that's why `urllib.urlencode()` comes into play here). On the
other hand, `payload` is where you should put your request body in case you
were issuing a POST, PUT or PATCH request, but particle.io's endpoint is not
expecting your OAuth access token to be there.

Something like this should work (disclaimer: not tested):

    
    
    auth = {"access_token": {ACCESS_TOKEN}}
    url_params = urllib.urlencode(auth)
    url = 'https://api.particle.io/v1/devices?%s' % url_params
    
    res = urlfetch.fetch(
        url=url,
        method=urlfetch.GET,
        follow_redirects=False 
    )
    

Notice how now we don't need your previous `Content-type` header anymore,
since we aren't carrying any content after all. Hence, `headers` parameter can
be removed from this example call.

For further reference, take a look at `urlfetch.fetch()`
[reference](https://cloud.google.com/appengine/docs/python/refdocs/google.appengine.api.urlfetch#google.appengine.api.urlfetch.fetch)
and [this SO thread](http://stackoverflow.com/questions/14551194/how-are-
parameters-sent-in-an-http-post-request) that will hopefully give you a better
insight into HTTP methods, parameters and request bodies than my poor
explanation here.

**PS:** If particle.io servers support it (they should), you should move away
from this authentication schema and carry your tokens in a `Authorization:
Bearer <access_token>` header instead. Carrying access tokens in URLs is not a
good idea because they are much more visible that way and tend to stay logged
in servers, hence posing a security risk. On the other hand, in a TLS session
all request headers are always encrypted so your auth tokens are well hidden
there.

