mirror of
https://github.com/kennethreitz/requests.git
synced 2026-06-05 22:50:18 +00:00
First draft of full verbs.
This commit is contained in:
@@ -319,3 +319,159 @@ You can also configure proxies by environment variables ``HTTP_PROXY`` and ``HTT
|
||||
$ python
|
||||
>>> import requests
|
||||
>>> requests.get("http://example.org")
|
||||
|
||||
HTTP Verbs
|
||||
----------
|
||||
|
||||
Requests provides access to almost the full range of HTTP verbs: GET, OPTIONS,
|
||||
HEAD, POST, PUT, PATCH and DELETE. The following provides detailed examples of
|
||||
using these various verbs in Requests, using the GitHub API.
|
||||
|
||||
We will begin with the verb most commonly used: GET. HTTP GET is an idempotent
|
||||
method that returns a resource from a given URL. As a result, it is the verb
|
||||
you ought to use when attempting to retrieve data from a web location. An
|
||||
example usage would be attempting to get information about a specific commit
|
||||
from GitHub. Suppose we wanted commit ``a050faf`` on Requests. We would get it
|
||||
like so::
|
||||
|
||||
>>> import requests
|
||||
>>> r = requests.get('https://api.github.com/repos/kennethreitz/requests/git/commits/a050faf084662f3a352dd1a941f2c7c9f886d4ad')
|
||||
|
||||
We should confirm that GitHub responded correctly. If it has, we want to work
|
||||
out what type of content it is. Do this like so::
|
||||
|
||||
>>> if (r.status_code == requests.codes.ok):
|
||||
... print r.headers['content-type']
|
||||
...
|
||||
application/json; charset=utf-8
|
||||
|
||||
So, GitHub returns JSON. That's great, we can use the JSON module to turn it
|
||||
into Python objects. Because GitHub returned UTF-8, we should use the
|
||||
``r.text`` method, not the ``r.content`` method. ``r.content`` returns a
|
||||
bytestring, while ``r.text`` returns a Unicode-encoded string. I have no plans
|
||||
to perform byte-manipulation on this response, so I want any Unicode code
|
||||
points encoded.::
|
||||
|
||||
>>> import json
|
||||
>>> commit_data = json.loads(r.text)
|
||||
>>> print commit_data.keys()
|
||||
[u'committer', u'author', u'url', u'tree', u'sha', u'parents', u'message']
|
||||
>>> print commit_data[u'committer']
|
||||
{u'date': u'2012-05-10T11:10:50-07:00', u'email': u'me@kennethreitz.com', u'name': u'Kenneth Reitz'}
|
||||
>>> print commit_data[u'message']
|
||||
makin' history
|
||||
|
||||
So far, so simple. Well, let's investigate the GitHub API a little bit. Now,
|
||||
we could look at the documentation, but we might have a little more fun if we
|
||||
use Requests instead. We can take advantage of the Requests OPTIONS verb to
|
||||
see what kinds of HTTP methods are supported on the url we just used.::
|
||||
|
||||
>>> verbs = requests.options(r.url)
|
||||
>>> verbs.status_code
|
||||
500
|
||||
|
||||
Uh, what? That's unhelpful! Turns out GitHub, like many API providers, don't
|
||||
actually implement the OPTIONS method. This is an annoying oversight, but it's
|
||||
OK, we can just use the boring documentation. If GitHub had correctly
|
||||
implemented OPTIONS, however, they should return the allowed methods in the
|
||||
headers, e.g.::
|
||||
|
||||
>>> verbs = requests.options('http://a-good-website.com/api/cats')
|
||||
>>> print verbs.headers['allow']
|
||||
GET,HEAD,POST,OPTIONS
|
||||
|
||||
Turning to the documentation, we see that the only other method allowed for
|
||||
commits is POST, which creates a new commit. As we're using the Requests repo,
|
||||
we should probably avoid making ham-handed POSTS to it. Instead, let's play
|
||||
with the Issues feature of GitHub.
|
||||
|
||||
This documentation was added in response to Issue #482. Given that this issue
|
||||
already exists, we will use it as an example. Let's start by getting it.::
|
||||
|
||||
>>> r = requests.get('https://api.github.com/repos/kennethreitz/requests/issues/482')
|
||||
>>> r.status_code
|
||||
200
|
||||
>>> issue = json.loads(r.text)
|
||||
>>> print issue[u'title']
|
||||
Feature any http verb in docs
|
||||
>>> print issue[u'comments']
|
||||
3
|
||||
|
||||
Cool, we have three comments. Let's take a look at the last of them.::
|
||||
|
||||
>>> r = requests.get(r.url + u'/comments')
|
||||
>>> r.status_code
|
||||
200
|
||||
>>> comments = json.loads(r.text)
|
||||
>>> print comments[0].keys()
|
||||
[u'body', u'url', u'created_at', u'updated_at', u'user', u'id']
|
||||
>>> print comments[2][u'body']
|
||||
Probably in the "advanced" section
|
||||
|
||||
Well, that seems like a silly place. Let's post a comment telling the poster
|
||||
that he's silly. Who is the poster, anyway?::
|
||||
|
||||
>>> print comments[2][u'user'][u'login']
|
||||
kennethreitz
|
||||
|
||||
OK, so let's tell this Kenneth guy that we think this example should go in the
|
||||
quickstart guide instead. According to the GitHub API doc, the way to do this
|
||||
is to POST to the thread. Let's do it.::
|
||||
|
||||
>>> body = json.dumps({u"body": u"Sounds great! I'll get right on it!"})
|
||||
>>> url = u"https://api.github.com/repos/kennethreitz/requests/issues/482/comments"
|
||||
>>> r = requests.post(url=url, data=body)
|
||||
>>> r.status_code
|
||||
404
|
||||
|
||||
Huh, that's weird. We probably need to authenticate. That'll be a pain, right?
|
||||
Wrong. Requests makes it easy to use many forms of authentication, including
|
||||
the very common Basic Auth.::
|
||||
|
||||
>>> from requests.auth import HTTPBasicAuth
|
||||
>>> auth = HTTPBasicAuth('fake@example.com', 'not_a_real_password')
|
||||
>>> r = requests.post(url=url, data=body, auth=auth)
|
||||
>>> r.status_code
|
||||
201
|
||||
>>> content = json.loads(r.text)
|
||||
>>> print content[u'body']
|
||||
Sounds great! I'll get right on it.
|
||||
|
||||
Brilliant. Oh, wait, no! I meant to add that it would take me a while, because
|
||||
I had to go feed my cat. If only I could edit this comment! Happily, GitHub
|
||||
allows us to use another HTTP verb, PATCH, to edit this comment. Let's do
|
||||
that.::
|
||||
|
||||
>>> print content[u"id"]
|
||||
5804413
|
||||
>>> body = json.dumps({u"body": u"Sounds great! I'll get right on it once I feed my cat."})
|
||||
>>> url = u"https://api.github.com/repos/kennethreitz/requests/issues/comments/5804413"
|
||||
>>> r = requests.patch(url=url, data=body, auth=auth)
|
||||
>>> r.status_code
|
||||
200
|
||||
|
||||
Excellent. Now, just to torture this Kenneth guy, I've decided to let him
|
||||
sweat and not tell him that I'm working on this. That means I want to delete
|
||||
this comment. GitHub lets us delete comments using the incredibly aptly named
|
||||
DELETE method. Let's get rid of it.::
|
||||
|
||||
>>> r = requests.delete(url=url, auth=auth)
|
||||
>>> r.status_code
|
||||
204
|
||||
>>> r.headers['status']
|
||||
'204 No Content'
|
||||
|
||||
Excellent. All gone. The last thing I want to know is how much of my ratelimit
|
||||
I've used. Let's find out. GitHub sends that information in the headers, so
|
||||
rather than download the whole page I'll send a HEAD request to get the
|
||||
headers.::
|
||||
|
||||
>>> r = requests.head(url=url, auth=auth)
|
||||
>>> print r.headers
|
||||
// ...snip... //
|
||||
'x-ratelimit-remaining': '4995'
|
||||
'x-ratelimit-limit': '5000'
|
||||
// ...snip... //
|
||||
|
||||
Excellent. Time to write a Python program that abuses the GitHub API in all
|
||||
kinds of exciting ways, 4995 more times.
|
||||
|
||||
Reference in New Issue
Block a user