Consuming external API in Ruby

How to get the data from an external site via API? You need to send a GET request using HTTP. But the best way is to use on of the popular gems. I will use Httparty.

I put everything into a separate folder. I added httparty into a custom Gemfile and bundled it. To simplify I will put the calls in irb.

First I need to add httparty gem:

2.3.0 :001 > require 'httparty'
 => true 
2.3.0 :002 >

Then I need some good example of a password protected API. I chose Open weather map, it’s free for limited usage and easy to implement. Registration takes a couple of minutes and in the end you get the authentication code necessary to get a response for a get request.

Let’s simply call the current weather in London:

2.3.0 :006 > HTTParty.get('http://api.openweathermap.org/data/2.5/weather?q=London,uk&appid=YourSecretCode')
 => #<HTTParty::Response:0xf38388 parsed_response={"coord"=>{"lon"=>-0.13, "lat"=>51.51}, "weather"=>[{"id"=>521, "main"=>"Rain", "description"=>"shower rain", "icon"=>"09n"}], "base"=>"stations", "main"=>{"temp"=>283.7, "pressure"=>1018, "humidity"=>93, "temp_min"=>283.15, "temp_max"=>285.15}, "visibility"=>10000, "wind"=>{"speed"=>6.2, "deg"=>260}, "clouds"=>{"all"=>76}, "dt"=>1492375800, "sys"=>{"type"=>1, "id"=>5187, "message"=>0.014, "country"=>"GB", "sunrise"=>1492318833, "sunset"=>1492369239}, "id"=>2643743, "name"=>"London", "cod"=>200}, @response=#<Net::HTTPOK 200 OK readbody=true>, @headers={"server"=>["openresty"], "date"=>["Sun, 16 Apr 2017 21:45:27 GMT"], "content-type"=>["application/json; charset=utf-8"], "content-length"=>["443"], "connection"=>["close"], "x-cache-key"=>["/data/2.5/weather?q=london,uk"], "access-control-allow-origin"=>["*"], "access-control-allow-credentials"=>["true"], "access-control-allow-methods"=>["GET, POST"]}> 
2.3.0 :007 >

As you can see I got lots of data in JSON format. It’s much better to actually defined method parsed_response to read it:

2.3.0 :027 > req.parsed_response['weather']
 => [{"id"=>500, "main"=>"Rain", "description"=>"light rain", "icon"=>"10n"}, {"id"=>310, "main"=>"Drizzle", "description"=>"light intensity drizzle rain", "icon"=>"09n"}] 
2.3.0 :028 >

OK, this is it.  I managed to quickly get the data and parse it to get the necessary info.

Advertisements

on APIs

Today a short one on APIs. Web applications like frruby may either generate the views by Rails or set up an API for others to read  and it may be as well a mobile app or a JS framework. So you can minimize your Rails application to back end only.

Let’s create an example app and scaffold a Page there. By opening Page controller you will notice that Rails 5 by default in a scaffold creates two output formats:

def create
 @page = Page.new(page_params)

respond_to do |format|
 if @page.save
 format.html { redirect_to @page, notice: 'Page was successfully created.' }
 format.json { render :show, status: :created, location: @page }
 else
 format.html { render :new }
 format.json { render json: @page.errors, status: :unprocessable_entity }
 end
 end
 end

It reposnds to a format which can be either html or json. You can easily add more, like xml. It is clear that it’s not the best solution, because for every action you need to write separate code and it will be messy if the application grows larger.

So this is one way to deal with app modularity: instead of generating html you generate json and then front end framework like AngularJS or a mobile app can read it.

The other path is to get data from external sources via API. There are additional topics here as: API authentication and caching data(usually you are allowed to make only a limited number of API calls per minute).

TODO:

  • create a simple external API application to possibly incorporate it into frruby

 

 

 

View from the front.On React.js

This day is the day of looking from the other side. So far I concentrated on the back end, now I want to start the second thread which is  front end of frrruby.

I decided to learn React and to use it in the project. Actually it is a topic which could easily serve as a main area to explore in frrruby so I need to be cautious.

Let’s try with a simple hello world using a simplified installation method from the official website. I will not mix the project with my Rails project now, so I put to some other folder and then:

npm install -g create-react-app

/home/ubuntu/.nvm/versions/node/v4.7.3/bin/create-react-app -> /home/ubuntu/.nvm/versions/node/v4.7.3/lib/node_modules/create-react-app/index.js
create-react-app@1.3.0 /home/ubuntu/.nvm/versions/node/v4.7.3/lib/node_modules/create-react-app
├── semver@5.3.0
├── tmp@0.0.31 (os-tmpdir@1.0.2)
├── commander@2.9.0 (graceful-readlink@1.0.1)
├── validate-npm-package-name@3.0.0 (builtins@1.0.3)
├── chalk@1.1.3 (escape-string-regexp@1.0.5, supports-color@2.0.0, ansi-styles@2.2.1, strip-ansi@3.0.1, has-ansi@2.0.0)
├── cross-spawn@4.0.2 (lru-cache@4.0.2, which@1.2.14)
├── fs-extra@1.0.0 (jsonfile@2.4.0, klaw@1.3.1, graceful-fs@4.1.11)
├── tar-pack@3.4.0 (uid-number@0.0.6, once@1.4.0, debug@2.6.3, readable-stream@2.2.6, tar@2.2.1, fstream-ignore@1.0.5, rimraf@2.6.1, fstream@1.0.11)
└── hyperquest@2.1.2 (through2@0.6.5, duplexer2@0.0.2, buffer-from@0.1.1)

The installation was extremely easy because I used node and a module called create-react-app. As you can it loaded some modules but the names are not very clear.  Still this is the package to create a single page app.

create-react-app hello-world
Creating a new React app in /home/ubuntu/workspace/playReact/hello-world.

Installing packages. This might take a couple minutes.
Installing react, react-dom, and react-scripts...

And there are lots of scripts there, there came a warning  that I’m using npm2 etc. In the end you just need to navigate into the app folder and type:

npm start

By opening the root you will get a nice dynamic welcome screen:

react_hello

Let’s have a look what is in:

ls
README.md node_modules/ package.json public/ src/

Package.json describes some basic project settings

{
 "name": "hello-world",
 "version": "0.1.0",
 "private": true,
 "dependencies": {
 "react": "^15.4.2",
 "react-dom": "^15.4.2"
 },
 "devDependencies": {
 "react-scripts": "0.9.5"
 },
 "scripts": {
 "start": "react-scripts start",
 "build": "react-scripts build",
 "test": "react-scripts test --env=jsdom",
 "eject": "react-scripts eject"
 }

The basic app has 3 node modules: react, react-dom, react-scripts. Sounds reasonable.Public folders stores icons and index.html file. And last folder is: src.

App.css  App.js  App.test.js  index.css  index.js  logo.svg

In index.js  you can find some imports especially the App:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './index.css';

ReactDOM.render(
 <App />,
 document.getElementById('root')
);

So,  the place where I was encouraged to modify something was App.js:

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {
 render() {
 return (
 
logo

Welcome to React

<p className="App-intro"> To get started, edit <code>src/App.js</code> and save to reload. </p> </div> ); } } export default App;

The code is quite clear here. Class App has a single method render which is being called.

I could have pasted the verb conjugation data straight into the div classified as ‘App-header’, but this is too simple. I need to read more to follow the React logic of putting things on the right place..

 

Templates in HAML. Using a gem.

Templates in HAML. Using a gem.

So far I used the default templating which is ERB. ERB is considered verbose, there is a lot of opening ERB tags and then closing them etc. Have a look at verbs views:

ls app/views/verb/

index.html.erb show.html.erb

ERB allows you to embed Ruby code into the HTML code. But there is a quite interesting way, more Ruby way of writing templates and it’s called HAML. It favors simplicity, replaces id= with #, class = with . so it looks like a css file.

But the main question is: how to use it since it is not in Rails 5 by default? If we replace the code inside the page index to match HAML and replace the extension?

$ cat app/views/page/index.html.erb 
<h1>Here are the verbs you can learn so far</h1>
<% @verbs.each do |v| %>
<p><%= v.infinitive %></p>
<% end %>
<h1>Here are some adjectives you can learn so far</h1>
<% @adjectives.each do |a| %>
<p><%= a.base %></p>
<% end %>

Becomes:

%h1 Here are the verbs you can learn so far
- @verbs.each do |v|
  %p -  v.infinitive 
- end 
%h1 Here are some adjectives you can learn so far
- @adjectives.each do |a| 
  %p - a.base 
- end

As you can see the code is cleaner, it respects double space indentation to mark the nesting items. Last but not least replace the file extension:

 mv   app/views/page/index.html.erb app/views/page/index.html.haml

Try to run the sever again and you get the error of the day. ‘Unknown format’. Who could expect that? To remedy this I need to install the gem – library – that will enable .haml files reading. Haml page says: add it to your Gemfile. So I added it just above the group:development section:

# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'
gem 'haml'
# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development

Now run bundle. Stop Rails server if you haven’t done so already. Run it again.

It should work. But it does not.  It is because haml does not require the ‘end’ keyword, which is nice. So we end up with a clean template:

<h1>Here are the verbs you can learn so far</h1>
- @verbs.each do |v| 
 %p - v.infinitive
<h1>Here are some adjectives you can learn so far</h1>
- @adjectives.each do |a| 
 %p - a.base

But what is amazing about using HAML is that it does not exclude using ERB! As of now I have only a single template in .haml and all the rest in .erb

Git status shows it all: modified Gemfile, removed .erb file and created .haml. Commit.

git status
On branch master
Changes to be committed:
 (use "git reset HEAD <file>..." to unstage)

modified: Gemfile
 modified: Gemfile.lock
 deleted: app/views/page/index.html.erb
 new file: app/views/page/index.html.haml

 

 

 

 

 

 

Rails Guides Walk-through. Active Record p.2

There are some conventions when relating two tables with each other via foreign key. As for now frrruby does not have any relation between the only two existing tables. Thanks to Rails magic you can easily add the foreign key when you create a migration.

Let’s say I need a table of difficult verbs (actually it would be much better to create a new column in the verbs table). It will reference verb table by id and have a difficulty level descried by a number.

rails g model HardVerb verb:references difficulty:integer

By displaying the content of migration file you can see that verb id is a foreign key now:

class CreateHardVerbs < ActiveRecord::Migration[5.0]
 def change
 create_table :hard_verbs do |t|
 t.references :verb, foreign_key: true
 t.integer :difficulty

t.timestamps
 end
 end
end

After migration the schema follows the pattern mentioned in the guides:

 create_table "hard_verbs", force: :cascade do |t|
 t.integer "verb_id"
 t.integer "difficulty"
 t.datetime "created_at", null: false
 t.datetime "updated_at", null: false
 t.index ["verb_id"], name: "index_hard_verbs_on_verb_id"
 end

So, this one was easy.

By default the table for HardVerb is called hard_verbs. You can replace it and put the all verbs as hard by passing in the following statement into the model:

class HardVerb < ApplicationRecord
 self.table_name = "verbs"

Now list all hard verbs in the console:

HardVerb.all
 HardVerb Load (0.6ms) SELECT "verbs".* FROM "verbs"
 => #, #, #

I managed to set the source table for the hard verbs. Nice.

CRUD

I don’t want to spend much time basics of CRUD in Active Record as I have already used it a lot in frrruby. It’s all about creating, reading, updating and deleting operations.

More important may be the validation section. There is a whole Rails Guide on validations so I will skip most of it for now, but let me point out where I need to give at least some validations. If anybody wants to say how hard the verb is then I need to require the number, it cannot be null in HardVerb model.

class HardVerb < ApplicationRecord
 # self.table_name = "verbs"
 belongs_to :verb
 validates :difficulty, presence: true
end

I commented the table switch line out.  The keyword validates takes the column name as a parameter, here it’s difficulty and then I specify what kind of validation I need. Rudimentary one is bare presence of the value. Test it:

2.4.0 :012 > c = HardVerb.new(verb_id:2)
 => # 
2.4.0 :013 > c.save
 (0.1ms) begin transaction
 Verb Load (0.4ms) SELECT "verbs".* FROM "verbs" WHERE "verbs"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]]
 (0.1ms) rollback transaction
 => false 
2.4.0 :014 > c.errors
 => #, @messages={:difficulty=>["can't be blank"]}, @details={:difficulty=>[{:error=>:blank}]}

I’m trying to call new (C from CRUD) on a HardVerb with only reference verb specified. No error pops up. But when trying to call save on the object. Again quite usual you access it in Ruby by calling .errors, which are human readable:

@messages={:difficulty=>["can't be blank"]}, @details={:difficulty=>[{:error=>:blank}]

And this is it, my first Rails Guides walk-through is finished.