Subscribe to The New and Improved Ruby Codes        RSS Feed
-----

What's a WebAPI anyway? How can I use one? Are https get requests easy in ruby?

Icon Leave Comment
::What is a WebAPI anyway?
So let's say you're programming a desktop app and you'd like to get some information from a twitter account (yes you are that egotistical that you truly believe everyone using your app will want to know the last place you were, and what you were feeling at that moment).

So, the old school way of doing this was called scraping and botting (spidering?) to pull the information off the web. That method was complicated and broke whenever the layout of the website was changed. Then they invented webAPIs. Now you can use a simple API to get that information instead of having to bother with scraping it the hard way.

Oh, incase the term API is foreign to you, the most popular API in the world is the win32 API I believe... With it, you could say... launch a message box to the screen with just one line of code (amazing how rapidly technological achievements can become available to the coding community).

::How to use WebAPIs
WebAPIs are unbelievably simple. To use them, you simply send a get request to the server hosting a WebAPI (they'll tell you) and the server sends you back a string as a response. Think of the response string as just the result of running a function/method with a return value. You can literally simulate this using a web browser right now --with no code involved what so ever! Browse to https://api.github.com/users/TheNotary and the server will respond with json data (you're browser will be all like, "Save this to a file?").

GitHub has a WebAPI. It doesn't really matter what GitHub is for the purposes of this tutorial, but if you are curious, it's a free place where you can store your code and it even has a powerful and fast version control system (well... it is a version control system, I mean).

Now, we're going to do two things with GitHub. First, we're going to pull up a user (me!). Then we're going to upload two strings of text "A key title and an actual key" and tell the server to store those strings as a "GitHub Public Key". We could do anything, but this is what we're choosing to do. Now let's get started.

==========================================================================
Authenticate with GitHub API
=============================


First, a glance at the API documentation...

Quote

Getting User Information:

You can then get extended information on users by their username. The url format is:

/user/show/:username [GET]

so the following command

$ curl http://github.com/api/v2/json/user/show/defunkt
{
  "user": {
    "gravatar_id": "b8dbb1987e8e5318584865f880036796",
    "company": "GitHub",
    "name": "Chris Wanstrath",
    "created_at": "2007/10/19 22:24:19 -0700",
    "location": "San Francisco, CA",
    "public_repo_count": 98,
    "public_gist_count": 270,
    "blog": "http://chriswanstrath.com/",
    "following_count": 196,
    "id": 2,
    "type": "User",
    "permission": null,
    "followers_count": 1692,
    "login": "defunkt",
    "email": "chris@wanstrath.com"
  }
}



If you authenticated as that user, you will also get this information:

  total_private_repo_count: 1
  collaborators: 3
  disk_usage: 50384
  owned_private_repo_count: 1
  private_gist_count: 0
  plan:
    name: mega
    collaborators: 60
    space: 20971520
    private_repos: 125



Quote

Notice that the curl command curl http://github.com/ap...er/show/defunkt is the goto way of demonstrating 'get' and 'post' requests to UNIX users. And that's what you use to work with WebAPIs. It's interesting to note that when you boil the internet down, you're left with just a bunch of get and post requests. There is nothing else. There are no files, and there are no server. IP addresses are arbitrary. Just a mess of gets and posts.


First, some code to authenticate with GitHub. Although most people believe the hype about SSL protection is just a poorly thought out NSA marketing scheme, GitHub encourages the use of https and SSL and we must use it. This is a slight complication, but the ruby code remains fairly simple.

Refs:
http://chrismcmahons...basic-auth.html
http://www.ensta-par...s/Net/HTTP.html
http://openmaniak.com/ettercap.php Needed this due to lack of documentation


  #require "net/http"
  require 'net/https'    # we'll need this since we're using ssl
  
  
  server = 'api.github.com'
  path = '/users/TheNotary'
  username = 'thenotary'                # consider changing me
  password = 'MyPassword'               # me too
  
  
  http = Net::HTTP.new(server,443)       # A)  Net::HTTP
  http.use_ssl = true

  req = Net::HTTP::Get.new(path)               # B)  Net::HTTP::Get
  req.basic_auth username, password

  response = http.request(req)           # C)  Net::HTTP

  r = response.body
  p r



You can run the above code right in irb and look at what it returns. It looks much like a hash => "{\"message\":\"Bad credentials\"}" but in fact, it is a json string. Before we convert it to an actual hash, let's go over some of that SSL code in detail. It's telling you bad credentials cause you've entered the wrong password. You can either create your own user and do further testing with that account, or continue guessing my password until you get it right.

A) Net::HTTP

  http = Net::HTTP.new(server,443)


Here we're creating a new 'Net::HTTP' object. Allow me to highlight it's coolest properties.

Net::HTTP
   http.address        # We put our server address here
   http.port           # We put 443 here, the port for SSL
   use_ssl             # We set this to true to tell ruby to actually encrypt our data with...
                       #  SSL rather than just send it plain text to the https port



C) Net::HTTP Continued...

Basically, you can use these objects to send 'post' and 'get' requests (in addition to puts and deletes too I'm sure but never mind that for now). Once you've created a suitable request object, you can use the Net::HTTP object to fire off the request to your targeted server...

   response = http.request(req)           # C)  Net::HTTP





B) Net::HTTP::Get

  req = Net::HTTP::Get.new(path)               # B)  Net::HTTP::Get
  req.basic_auth username, password



There are 4 different request types in the "restful resource" model: Get, post, put, and delete. In ruby, each one get's it's own object. Get's is called "Net::HTTP::Get". Allow me to go over it's articles of interest.

Net::HTTP::Get
   path               # we set this to the path to the WebAPI method, it's "controller", "method" and "parameter" if you will
   
   basic_auth         # This is a method which can be used to setup the username password to access the webpage requested



It's pretty straight forward. Once you have it setup, just fire it off using a Net::HTTP object and you'll get a response back from the server.


==========================================================================
Add a new ssh key to GitHub
===========================

The first step was to make it work on the command line. This took me hours to do because githubs documentation was incorrect/ changed between versions!

$ curl -u 'thenotary:MyPass' -d '{"title":"fromcurl", "key":"rsablabla"}' https://api.github.com/user/keys

That got me a result that I liked at least. Otherwise it was telling me {"message":"not found"} or something. The '-d' stands for data btw.


(Adjust username and password and paste into irb)
def install_key(username, password, rsa_key)
  require 'net/https'
  require 'json'
  
  server = 'api.github.com'
  path = '/user/keys'

  
  http = Net::HTTP.new(server, 443)   # 443 for ssl
  http.use_ssl = true
  
  req = Net::HTTP::Post.new(path)
  req.basic_auth username, password
  req.body = "{\"title\":\"fromruby\", \"key\":\"#{rsa_key}\"}"
  
  response = http.start {|http| http.request(req) }
  
  return_hash = http.request(req).body
  
  my_hash = JSON.parse(return_hash)
  
  p my_hash
  
  the_code = my_hash["errors"][0]["code"]
  
  if my_hash.key?("errors")   # this doesn't work due to it being a buggy API atm
    
    return true  # false
  end
  
  return true
end

#authentication_style

rsa_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCpxktnx2k7aYkxLnvLq8ZeUI8d/d00MeV32na3GZ35qKtJ3Vmvzvb8anF1eZD8/+BtBgYer9/3E0KUi3YNYCeejkdUPj3/Z+aV7Ft0+IeKdzFSqfnfN9UsuS/zkeyia2bjgQJYqk2ZbkMuVIn79UI5ypJWGOXNfKyQ2adYJD7Pjgsxvx8qEXHlU+SszidkwYFEFwT7rZtSXILylmcwCnZryy91cs50vGWxKzKrOV/2iMd8V4Qv7RbhKtQ7OCd19CaZ08H3xqcG1U2lqXIgxSN75bLL71AM0KfIvNOzvigBZnYyb/RKiUQUhA0FnnIYc/7hF9rOe/S1acRiOF6ihz1x"

result = install_key("TheNotary", "MyPassword", rsa_key)




Ok, after much trial and error, and a little packet sniffing, I got things to work. The WebAPI always returns the same error, even when the call was effective. That's pretty lame, but there's a way to check that it worked. I'll leave that to your imaginations though.



In summary, Web APIs are useful, and... well... this one was actually a bitch to get working, but all in all, I'd say the code I generated in my project is more stable than scraping the data manually. Hopefully reading this guide encourages you to use this technology and build something that would have otherwise been 'not worth the time'. Good Luck.

0 Comments On This Entry

 

Trackbacks for this entry [ Trackback URL ]

There are no Trackbacks for this entry

October 2014

S M T W T F S
   1234
567891011
12131415161718
19 20 2122232425
262728293031 

Tags

    Search My Blog

    0 user(s) viewing

    0 Guests
    0 member(s)
    0 anonymous member(s)

    Categories