After attending the CodeRage challenge, I realised I didn’t know how REST API’s and JSON really worked. I knew what they were and their place in the stack but not how they really worked. The only way to figure that out is to build something that made use of these technologies.
We would be using Sinatra as the framework, Rspec for testing, and json and jsonify to parse JSON. Let’s start by creating the necessary files.
/src/sapify
└── .gitignore
└── Gemfile
└── README.md
└── Rakefile
└── api_server.rb
└── api_server_test.rb
In .gitignore
we can ignore files that shouldn’t be in version control. I usually have *.swp
as I use vim. We can start building our Gemfile with the required gems.
# Gemfile
source :rubygems
gem 'rspec'
gem 'rack-test'
gem 'sinatra'
gem 'jsonify'
Rspec and rack-test are for testing, Sinatra and jsonify are for our application. Running bundle
would install and check that we have the necessary gems that we’re gonna use.
Building our API server and our test suite.
#api_server_test.rb
require './api_server'
require 'rspec'
require 'rack/test'
set :environment, :test
describe 'The REST API server' do
include Rack::Test::Methods
def app
Sinatra::Application
end
it "returns all users" do
get '/api/users/'
last_response.should be_ok
end
end
We describe our test, followed by including Rack::Test::Methods
so we can use methods such as get
, post
, put
and delete
in our tests. It also provides a nice object last_response
which we can use to check the response.
With our test suite in place, we add a test method to our Rakefile
as we would want to be able to run the tests by issuing just a rake test
command.
We are now ready to start building our application. We know we are going to have users. We start adding tests to check individual user id’s. The tests check that the response is what we expect.
In this commit, we create a schema, a Person class where we have 2 attributes that can be accessed, id
and name
. Follwed by adding 2 people to our list, John and Peter.
Next, we proceed to write the methods for our API. The first method is to return all id’s of existing users when a get
requests hits our /api/users/
endpoint. With this method complete, we should pass our first test.
The second method is to return the values of the user when a get
request hits our /api/users/:id
endpoint, where :id
is a valid user id. It should return a json error if the user id does not exist. Now, when we run our tests, they should both pass.
In this commit. I realise that I could make use of JSON.parse to parse the response. Previously, I comparing strings to make sure they match. Now with JSON.parse, we can compare the values in the hashmap’s instead.
We also add some new tests for creating a user. We check that the our api can create a new user but returns an error when the user already exists. We also check that the request is properly formed.
Now that we’ve got the tests, we neeed to write the code pass the tests. We create a post
request endpoint and parse the request. If there are missing elements, we return an error. If the JSON request is well formed, we check if the user already exists. Once we know that the user does not exist, we add the user to our list of users. If the user already exists, we return the corresponding error.
Our API server now has the ability to query the users, and add new user. Now we would like to modify these users. We start out by writing the appropriate tests. First, we check that the user data is correctly modified on the request.
Next, we check that the server does not modify any data if the request is not well formed. Following that, we check that the server rejects the request if the user does not exist.
Now that we have our tests, we can write the code for modifying the user details. We write a put
request endpoint and parse the JSON request. Once again, we check if request is well formed, and rejects the request if it isn’t. Next we check if the user exists in our list. Only if the user exists, we modify the details. If not, we respond with the appropriate error message.
We can further complete this API endpoint by writing a delete
request endpoint to delete a user.
After this quick exercise, I learnt how REST APIs work. Writing these API endpoints were easy with Sinatra. I also learnt why JSON is used as a messaging format and parsing them in Ruby is trivial. On top of that, I picked up some Rspec knowledge!
Published on 19 Dec 2012 by Stanley Tan