How to make REST API in Rails
Making a simple API in rails
This is the first part of the tutorial series on "How to make ReST API in Rails".
There are certain prerequisite which I assume that you had already installed.
Here is the screencast for this tutorial.
prerequisites:
Ruby
Rails
Postgresql
Create the app
$ rails new railsapi -d postgresql --skip-bundle
This will create the bare-bones scaffold of the rails application "railsapi" specifying
postgresql to use as database and do not install the gems while making the app.
In the Gemfile add gem to serialize the resources we are going to expose on the api
$ gem 'active_model_serializers'
Also comment the 'jbuilder' and 'turbolinks' gem in the Gemfile, as we are not going
to deal with the frontend part. We will only create the json response which doesn't need these gems.
Now go inside railsapi directory and install the gems
$ cd railsapi
$ bundle install
Making the API
To make api, we will isolate the api controllers under a separate namespace "api" by making a directory
"api" in "app/controller" directory.
$ mkdir app/controllers/api
Now we will add this namespace in our routes.rb file
Rails.application.routes.draw do
namespace :api do
end
end
Since we want our responses to be in json, So will set the default format of this api
to json. Change the above code.
Rails.application.routes.draw do
namespace :api, defaults:{ format: :json }do
end
end
For now, our endpoint url should look like
http://localhost:3000/api/
Version the API
We should version our API from the beginning, so that it gives a better structure to our
rails app and in future if we need to add new feature our old code may keep on serving
the older feature while the new version will start serving new feature.
In order to set the version for the api, we first need to add another directory under the api
directory
$ mkdir app/controllers/api/v1
Since we have another directory in api, we need to tell our routes.rb file to know
about this change. Let's modify routes.rb file
Rails.application.routes.draw do
# API routes path
namespace :api, defaults: { format: :json } do
namespace :v1 do
end
end
end
So we have added another namespace 'v1' inside api. For now, our endpoint url should look like
http://localhost:3000/api/v1/
Adding a Model
Now let's add the User model using devise. To use devise add the Gem devise in Gemfile
gem "devise"
Now run bundle install to install devise gem. After doing bundle install we need to run the devise install generator
$ rails g devise:install
Let's generate the user
model through the devise
generator
$ rails g devise User
After doing these, let's now create database and run the migrations
$ rake db:create
$ rake db :migrat
After installing devise the routes.rb should looks like this
Rails.application.routes.draw do
devise_for :users# API routes path namespace :api, defaults: { format: :json } do namespace :v1 do #devise_for :users resources :users, :only => [:show, :create] end end end
Building first endpoint
Now we have the User model ready, we will create the first endpoint with the show action
which will return the user record in json format.
First generate users controller
$ rails generate controller users
If the users_controller.rb file is not generated in api/v1/ directory than move the file
inside app/controllers/api/v1/
The users_controller.rb file should look like
class Api::V1::UsersController < ApplicationController
respond_to :json
def show
respond_with User.find(params[:id])
end
end
Here The 'A' of api and 'V' of v1 should be in caps. We have defined the response
format as json. The show action finds the user with the id passed as params and returns
the json representation of it.
For now, our endpoint url should look like
http://localhost:3000/api/v1/users/1
where 1 is the id
This will give an error now if you run the code as there is no record in the database.
So, Let's create one from rails console
$ rails console
> User.create({email: "example@railsapi.com",password: "12345678",password_confirmation: "12345678"})
This will create a record with id 1.
After this you can run rails server and check if our endpoint is working or not
$ rails s
In the new command line tab hit the endpoint to get the data
$ curl localhost:3000/api/v1/users/1
Output should be
{"id":1,"email":"example@railsapi.com","created_at":"2016-03-04T23:10:16.169Z","updated_at":"2016-03-04T23:10:16.169Z"}
If you are having problems with the response and have checked everything is well, then you
might need to visit the application_controller.rb
file and update it as follows.
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :null_session
end
we should be using null_session
to prevent CSFR attacks , so we should use it in order for POST or PUT requests to work
By now you have learned how to create api with an endpoint. In the next post will learn
how to add more actions like create, update and delete/destroy to our api.
it is not working for me.. route no match error
ReplyDeleteHey Khalidh, Can you please exactly specify the error. I doubt you must be have not specified the namespace in routes.rb file. If you have doubt in any steps than you can also watch the video tutorial available on youtube. https://www.youtube.com/watch?v=B-8dJLSB3hU
DeleteThis comment has been removed by the author.
DeleteRails.application.routes.draw do
ReplyDeletedevise_for :users
namespace :api, defaults: { format: :json } do
namespace :v1 do
resources :users, only: [:show, :update]
end
end
end
I guess we need to add after v1 namespace resources :users, only: [:show, :update]
ReplyDeleteYes Srinivas, Thanks for pointing it out. :)
DeleteGood post ajeet :-)
ReplyDeleteI am getting LoadError in rails 5.
ReplyDeletefabritronix@fabritronix:~/test/railsapi$ rails s
=> Booting Puma
=> Rails 5.0.0.1 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.6.0 (ruby 2.3.0-p0), codename: Sleepy Sunday Serenity
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://localhost:3000
Use Ctrl-C to stop
Started GET "/api/v1/users/1" for 127.0.0.1 at 2016-09-20 19:08:59 +0530
ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations".* FROM "schema_migrations"
LoadError (Unable to autoload constant UsersController, expected /home/fabritronix/test/railsapi/app/controllers/users_controller.rb to define it):
activesupport (5.0.0.1) lib/active_support/dependencies.rb:512:in `load_missing_constant'
activesupport (5.0.0.1) lib/active_support/dependencies.rb:203:in `const_missing'
activesupport (5.0.0.1) lib/active_support/dependencies.rb:543:in `load_missing_
for subsequent requests I am getting output.
ReplyDeletefabritronix@fabritronix:~/test/railsapi$ curl localhost:3000/api/v1/users/1
{"id":1,"email":"example@railsapi.com","created_at":"2016-09-20T13:00:56.393Z","updated_at":"2016-09-20T13:00:56.393Z"}
This is the expected output. What else you are expecting?
DeleteI did not move the controller to api/v1 directory that is way it was showing Load error.
DeleteEverything works fine.
Excellent tutorial.
Keep up the good work.
Thanks.
This comment has been removed by the author.
DeleteThank you for the appreciation. "Keep learning and Keep sharing"
DeleteYou need to add this [ "get 'users/:id' => 'users#show' ] in routes.
ReplyDeletethe route file looks like this:
Rails.application.routes.draw do
devise_for :users
namespace :api, defaults:{format: :json} do
namespace :v1 do
get 'users/:id' => 'users#show'
end
end
end
Thanks Jose for pointing it out. Actually the route is added but that piece of code is shown in the second part of this post - https://jee-appy.blogspot.in/2016/03/how-to-make-rest-api-in-rails-part-2.html
DeleteAlthough am also adding it in this part also.
Thanks
can you look at this problem
ReplyDeletecan you look at this problem
ReplyDeletehttp://stackoverflow.com/questions/41270507/running-curl-on-ruby-on-rails/41271519#41271519
I hope your problem is solved by this link http://stackoverflow.com/questions/1195962/submitting-post-data-from-the-controller-in-rails-to-another-website
Delete192-168-1-117:restapi leotyndall$ bundle install
ReplyDeleteCould not locate Gemfile
192-168-1-117:restapi leotyndall$
This is the error message
you need to run bundle install inside your application directory. Make sure you are in the root directory of your project.
DeleteAn error occurred while installing pg (1.0.0), and Bundler cannot continue. any ideas
ReplyDeleteCan you please share more error details. which OS you are using?
DeleteI am using Mac latest high sierra v10.13.4
ReplyDeleteextconf failed, exit code 1
Gem files will remain installed in /Users/leotyndall/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/pg-1.0.0 for inspection.
Results logged to
/Users/leotyndall/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/extensions/x86_64-darwin-17/2.4.0-static/pg-1.0.0/gem_make.out
An error occurred while installing pg (1.0.0), and Bundler cannot continue.
Make sure that `gem install pg -v '1.0.0'` succeeds before bundling.
here is the mkmf.log
ReplyDeletefind_executable: checking for pg_config... -------------------- no
--------------------
find_header: checking for libpq-fe.h... -------------------- no
"clang -o conftest -I/Users/leotyndall/.rbenv/versions/2.4.2/include/ruby-2.4.0/x86_64-darwin17 -I/Users/leotyndall/.rbenv/versions/2.4.2/include/ruby-2.4.0/ruby/backward -I/Users/leotyndall/.rbenv/versions/2.4.2/include/ruby-2.4.0 -I. -I/Users/leotyndall/.rbenv/versions/2.4.2/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT -O3 -Wno-error=shorten-64-to-32 -pipe conftest.c -L. -L/Users/leotyndall/.rbenv/versions/2.4.2/lib -L. -L/Users/leotyndall/.rbenv/versions/2.4.2/lib -fstack-protector -L/usr/local/lib -lruby-static -framework CoreFoundation -lpthread -ldl -lobjc "
checked program was:
/* begin */
1: #include "ruby.h"
2:
3: int main(int argc, char **argv)
4: {
5: return 0;
6: }
/* end */
"clang -E -I/Users/leotyndall/.rbenv/versions/2.4.2/include/ruby-2.4.0/x86_64-darwin17 -I/Users/leotyndall/.rbenv/versions/2.4.2/include/ruby-2.4.0/ruby/backward -I/Users/leotyndall/.rbenv/versions/2.4.2/include/ruby-2.4.0 -I. -I/Users/leotyndall/.rbenv/versions/2.4.2/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT -O3 -Wno-error=shorten-64-to-32 -pipe conftest.c -o conftest.i"
conftest.c:3:10: fatal error: 'libpq-fe.h' file not found
#include
^~~~~~~~~~~~
1 error generated.
checked program was:
/* begin */
1: #include "ruby.h"
2:
3: #include
/* end */
--------------------
using ruby 2.4.2 and rails 5.2.0
ReplyDeleteIt is very helpful information on Ruby on Rails Online Course
ReplyDeleteRUBY ON RAILS CUSTOM WEB APPLICATION SERVICES
ReplyDelete