Demystifying Rest

advertisement
Kirsten Jones, Technical Leader, Cisco Systems

Application Developers
…Curious about using REST
…Wanting help debugging the system

Not REST API Architects (sorry!)






HTTP Overview
REST Web Services
OAuth Authentication Basics
REST Debugging





HyperText Transfer Protocol
Used for conversations between web clients
and servers
Most of the internet uses HTTP
Supports verbs for GET, PUT, POST, DELETE
Query parameter framework

Client sends a request






Method
URL
Headers
(sometimes) parameters
(sometimes) body
Server replies with a response
 Content
 Status
 Headers
HTTP response codes for dummies.
50x: we fucked up.
40x: you fucked up.
30x: ask that dude over there.
20x: cool.
Props to @DanaDanger for this

Headers
 Generally meta-information about the request
 For instance: requesting an image in a specific
format

Parameters
 Limit or describe how you want the resource
(searches, filters)
 Defines the resource you’re requesting

Request (client)
 Accept: Give me this kind of response. Here’s a
list in order of what I’m hoping you’ll send.
Accept: text/html,application/xhtml+xml,application/xml

Response (server)
 Content-Type: This is the kind of response I’m
sending you.
Content-Type: text/html; charset=UTF-8



Part of the URL
Everything after the question mark, delimited
by ampersands
http://www.example.com/search_people?this
=that&foo=bar

Chrome browser sends a request to Google
 Method: GET
 URL: http://www.google.com
 Headers:
▪
▪
▪
▪
▪
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Connection: keep-alive
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3)
AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.168 Safari/535.19
▪ Accept-Encoding: gzip,deflate,sdch
▪ Cookie: NID=59=EudJ2a15ql8832PCysQA0qchtuvGWMoA7rkp79VpIYAQ8j42IO17LFudCYNMXm9l6SHcu3YgrGRCdrRCyM468xPZaOek4PiAXQ8eARqU1SGYx6y7_9LW-c3HHb-vs2;
PREF=ID=994f8de0e8b39a5b:U=237805f1f710dc73:FF=0:TM=1336752507:LM=13
36752509:S=W0Hha7x4czdXp51U
▪ Host: www.google.com

Google sends a response
 Headers:
▪ Content-Length: 24716
▪ Content-Encoding: gzip
▪ Set-Cookie: NID=59=F48kbwfwOi-qCHJyrnMSUlDBVxKZVKZpq5B5jttt_25IRN4lS-0rQcVttqdnOIlQzafw1i4HPQAO0RpZ7NuC0WCKWta7SYoekx0--YGf2zIFZ9VXIKS_UEaOH9iBe; expires=Sat, 10-Nov-2012 21:26:46 GMT; path=/;
domain=.google.com; HttpOnly
▪ Expires: -1
▪ Server: gws
▪ X-XSS-Protection: 1; mode=block
▪ Cache-Control: private, max-age=0
▪ X-Frame-Options: SAMEORIGIN
▪ Content-Type: text/html; charset=UTF-8
▪ Date: Fri, 11 May 2012 21:26:46 GMT
 Content: A bunch of HTML
 Status: 200



Some browsers provide tools to view HTTP
traffic
Great for understanding
what your browser is
doing
Tracking
programmatic
traffic requires a
separate tool

Macintosh: HTTPScoop
http://tuffcode.com/

Macintosh: Charles (supports SSL)
http://www.charlesproxy.com/

Windows: Fiddler
http://www.fiddler2.com/fiddler2/

Unix (or Mac): Wireshark (X11)
http://www.wireshark.org/
Request
Headers
Request/Response


Uses URL paths to define resources
Create, Read, Update, Delete
 POST, GET, PUT, DELETE

Error Codes
 HTTP Status Codes

Request parameters
 Query parameters

Response types and configuration
 Headers




Blog Info from Tumblr
GET (read)
http://api.tumblr.com/v2/blog/synedra.tumbl
er.com/info
Requires api_key sent as parameter
http://api.tumblr.com/v2/blog/synedra.tumbl
r.com/info?api_key=my_api_key

Headers

Request/Response
Status: 200
Content:
{"meta":
{"status":200, "msg":"OK” },
"response":{
"blog":{"title":"Untitled","posts":0,
"name":"synedra",
"url":"http:\/\/synedra.tumblr.com\/",
"updated":0,
"description":"","ask":false,"likes":0}}}
Used by many APIs
Each application gets a consumer key and secret
Authentication server handles authentication
Each user of an application gets a unique user
token and secret
 Supports tracking of application/member use of
the API
 Allows users to protect username/password
 Industry standard – libraries for most
programming languages






REST web services call adds verification
signature to each request
Query parameters
 Authorization header



Secrets are used to create signature
Authentication server checks signature to
verify that it was created using shared secrets
If authentication succeeds, request is
processed by API server

Signature is generated based on





URL
Parameters
Consumer key
User token
http://api.linkedin.com/v1/people/url=http%3A%2F%2Fw
ww.linkedin.com%2Fin%2Fsynedra?oauth_body_hash=2j
mj7l5rSw0yVb%2FvlWAYkK%2FYBwk%3D&oauth_nonce
=6283929&oauth_timestamp=1336775605&oauth_consu
mer_key=***KEY***&oauth_signature_method=HMACSHA1&oauth_version=1.0&oauth_token=***TOKEN***
&oauth_signature=CqHiZI6tI3pQGe5a0vVgoT0822A%3D

Request

Headers (nothing special)

Request/Response

Signature is generated based on




URL
Parameters
Consumer key
User token
URL is unchanged:
http://api.linkedin.com/v1/people/~/shares
 Authorization header has oauth stuff:
OAuth realm="http://api.linkedin.com",
oauth_body_hash="JtgCKBurLIPLM4dXkn2E3lgrfI4%3D",
oauth_nonce="60723468", oauth_timestamp="1336776657",
oauth_consumer_key=”***KEY***",
oauth_signature_method="HMAC-SHA1", oauth_version="1.0",
oauth_token=”***TOKEN***",
oauth_signature="8iWVpIK3LhRbu8JPf2gzC1YxQy4%3D"


No authorization parameters

Authorization is in the header

Request/response works the same

Download the oauth2 package from github
 No, it’s OAuth 1.0a, ignore the name

Quick walkthrough to understand process
 (but this talk is not about OAuth)
import oauth2 as oauth
consumer_key
=
'xxxxxxxxxxxxxx'
consumer_secret =
'xxxxxxxxxxxxxx’
consumer = oauth.Consumer(consumer_key,
consumer_secret)
client = oauth.Client(consumer)


First step in OAuth: Get a request token for
this authorization session
OAuth library handles signing the request
import oauth2 as oauth
consumer_key
=
'xxxxxxxxxxxxxx'
consumer_secret =
'xxxxxxxxxxxxxx’
consumer = oauth.Consumer(consumer_key, consumer_secret)
client = oauth.Client(consumer)
resp, content = client.request(request_token_url, "POST")
request_token = dict(urlparse.parse_qsl(content))


Second step: Send the user to the server to
authorize your application
After the user authorizes your application,
the server returns a verification code for you
to use
print "Go to the following link in your browser:"
print "%s?oauth_token=%s" % (authorize_url,
request_token['oauth_token'])
accepted = 'n'
while accepted.lower() == 'n':
accepted = raw_input('Have you authorized me? (y/n) ')
oauth_verifier = raw_input('What is the PIN? ’)


Third step: Use the verifier and the request
token to get an access token
This is usually a long lived token
token = oauth.Token(request_token['oauth_token'],
request_token['oauth_token_secret'])
token.set_verifier(oauth_verifier)
client = oauth.Client(consumer, token)
resp, content = client.request(access_token_url, "POST")
access_token = dict(urlparse.parse_qsl(content))


Make an API call using the OAuth library
The library handles the signature generation
url = http://api.linkedin.com/v1/people/~
consumer = oauth.Consumer(
key=”XXXXX",
secret=”XXXXX")
token = oauth.Token(
key=”XXXXX",
secret=”XXXXX")
client = oauth.Client(consumer, token)
resp, content = client.request(url)




Use the documentation and resources
provided by the platform team
Consoles, IODocs, OAuth signature checkers
Use existing, tested libraries
Code defensively




401 authentication errors (signatures, tokens)
403 authorization errors (throttles,
permissions)
400 errors – parameters, headers
Library out of sync with API



Try building the request using just the OAuth
library
Find someone else’s code that works
HTTP Servers aren’t that smart



HTTP: Hypertext Transfer Protocol
REST: REpresentational State Transfer
OAuth: Authentication
Download