title | type | duration | creator | competencies | ||||
---|---|---|---|---|---|---|---|---|
Rails API |
Lesson |
"1:25" |
|
Databases |
In Unit 3 we're gonna learn how to create and consume an API. As an intro, we're gonna see what this looks like using Rails since you should be intimately familar with the framework by now. This Rails app will have no views, however, we'll test our API using Insominia. Later, we'll use jQuery to access it and render data onto a page.
The original idea behind Rails API was to serve as a starting point for a version of Rails better suited for JS-heavy apps. As of today, Rails API provides: trimmed down controllers and middleware stack together with a matching set of generators, all specifically tailored for API type applications.
You can actually check this out by going to an index view of your Project 2 and typing .json
to the end of the URL. Note- this should work if you scaffolded your resources.
Objectives
- Create a Rails API to serve JSON data only (no views)
- Test our REST-ful endpoints using Insominia
- Consume our API using jQuery
Check out the Rails API Gem documentation.
-
Let's run
gem install rails-api
to install the gem. You may need to re-open your Terminal window for the commands to work. -
Run
rails-api new my_api --database=postgresql -T
to create a new API only Rails app. -
Add this to the
Gemfile
thenbundle install
:gem 'rack-cors' gem 'active_model_serializers'
rack-cors will help us with CORS request errors. Serialize will help us serve our data as a serialized JSON object.
-
Let's include our serialization gem by adding the following to
application_controller.rb
inside theclass
declaration:class ApplicationController < ActionController::API include ActionController::Serialization end
By the way, what's going on with our inheritance here?
- Add to the following to
application.rb
inside theclass
declaration:
module MyApiAgain
class Application < Rails::Application
config.api_only = true
...
end
end
# This keeps Rails lightweight by only inculding those middlewares needed for an API.
-
To scaffold our Todo resource:
rails g scaffold todo title completed:boolean order:integer
-
Run
rake db:create && rake db:migrate
-
Take a look at
controllers/todos_controller.rb
- What do you notice that's different from a regular scaffolded controller?
- Which actions are we missing? Why?
- Why do the actions only respond with JSON?
-
Next, check out
config/routes.rb
then runrake routes
. What is different and why?
Serializers will determine what info is sent to the requesters. We now have a working backend!
-
Fire up our
rails s
and gotohttp://localhost:3000/todos
. What is returned? -
Add the Chrome extension Insominia and open it. We're gonna use Insomnia to make HTTP requests and interact with our Rails server via the API we created. There will be a little bit of set-up involved the first time you open it. We will walk through it.
-
Let's make a
GET
request for all the todos. It's essentially the same URL to grab an index view, only we add.json
to the end of it.http://localhost:3000/todos.json
-
This should return an empty array because we have no todos in our database. How could we
POST
a newTodo
to our database?# send a POST request to this route http://localhost:3000/todos.json # Our Todo object, just like what we'd see in our params hash. { "todo": { "title": "Adding our First Todo!", "completed": false, "order": 20 } }
-
After step 4 we should see a
Success 201
message! Try theGET
request from step 3 again. You should now have oneTodo
in your array.
YOU DO
- Using Insomnia, add two more todos to the database
- Using Insomnia,
UPDATE
one of the todos - Using Insomnia,
DELETE
one of the todos - Add a
location
field to our Todo model and make it accessible to our API for all CRUD actions. HINT: check out theapp/serializers/todo_serializers.rb
file. What is it doing?
##Part 2 - Using AJAX to access our DB
The beauty of hosting our database separately is that it is decoupled from the client. This gives us flexibility and options. We could create an Angular front-end, an Ionic mobile app, or a static html page and they can all access our API.
We're gonna dive into AngularJS in unit 4. However, we can accomplish some of the same behavior using jQuery. Let's see what that looks like by building a basic index.html
page that will consume our API.
-
In your
ga
folder, create a new folder calledrails_api_frontend_sample
. Create anindex.html
file and add the code below.
<script type="text/javascript" src='https://code.jquery.com/jquery-2.2.0.min.js'></script>
<script type="text/javascript">
$.getJSON('http://localhost:3000/todos.json', function(data){
$('#todo').text("Todo title: " + data.todos[0].title);
console.log(data.todos[0]);
});
</script>
-
Let's break down what
$.getJSON()
is doing:$.getJSON()
is a jQuery method that takes a URL and a callback as arguments.- The
data
object that is returned can be passed in to the callback itself as an argument. - We insert the title of our Todo into the
#todo
element using the jQuery method.text()
.
-
Start Python Simple Server by running
python -m SimpleHTTPServer 8080
. This is a basic HTTP server that you have installed on your Mac. It's a simple, lightweight option to serve static assets (HTML, CSS, JS). We need a server in order to make AJAX requests. -
If you encounter any CORS errors or issues, add this Chrome extension called Allow-Control-Request-Origin and turn it on.
-
Add this code to
application_controller.rb
anddevelopement.rb
if you STILL encounter any CORS errors or issues:
# application_controller.rb
before_filter :add_allow_credentials_headers
def add_allow_credentials_headers
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#section_5
#
# Because we want our front-end to send cookies to allow the API to be authenticated
# (using 'withCredentials' in the XMLHttpRequest), we need to add some headers so
# the browser will not reject the response
response.headers['Access-Control-Allow-Origin'] = request.headers['Origin'] || '*'
response.headers['Access-Control-Allow-Credentials'] = 'true'
end
def options
head :status => 200, :'Access-Control-Allow-Headers' => 'accept, content-type'
end
# development.rb
config.debug_exception_response_format = :api
Also, try adding
:null_session
toapplication_controller.rb
if you encounter more Insomnia errors.
Using the lesson above, see if you can access a movie from the Open Movie Database and render some data.
Using the lesson above, see if you can render Atlanta's current weather data from the Open Weather Map API. NOTE - You'll need to register for an API key.
Possible solution to Bonuses
<!DOCTYPE html>
<html>
<head>
<title>AJAX!</title>
</head>
<body>
<h1>AJAX!</h1>
<div id="todo"></div><br>
<div id="movie"></div><br>
<div id="weather"></div>
<script type="text/javascript" src='https://code.jquery.com/jquery-2.2.0.min.js'></script>
<script type="text/javascript">
$.getJSON('http://localhost:3000/todos.json', function(data){
$('#todo').text("Todo location: " + data.todos[1].location);
console.log(data);
});
$.getJSON('http://www.omdbapi.com/?t=batman&y=1989&plot=full&r=json', function(data){
$("#movie").html("<div>Title: " + data.Title + "</div><div>Release: " + data.Released + "</div>");
})
$.getJSON('http://api.openweathermap.org/data/2.5/weather?q=Atlanta&appid=< YOUR-API-KEY-HERE >', function(data){
$("#weather").text("Atlanta's current weather is: " + data.weather[0].description);
})
</script>
</body>
</html>