RESTful API with Grape gem
In this post we'll make a Rails API using Grape gem. And we'll also attach Swagger UI with it to get a nice API interface to play with. So what is Grape? I can quote directly from their official docs, Grape is a REST-like API framework for Ruby. It's designed to run on Rack or complement ...
In this post we'll make a Rails API using Grape gem. And we'll also attach Swagger UI with it to get a nice API interface to play with.
So what is Grape? I can quote directly from their official docs,
Grape is a REST-like API framework for Ruby. It's designed to run on Rack or complement existing web application frameworks such as Rails and Sinatra by providing a simple DSL to easily develop RESTful APIs. It has built-in support for common conventions, including multiple formats, subdomain/prefix restriction, content negotiation, versioning and much more.
We'll make two api for our user model. One POST api for creating a user and one GET api for get a user info.
Lets start by adding grape gem in our Gemfile.
gem "grape"
Make a folder named api inside our app/controller folder and create a new file base.rb inside this folder.
Grape APIs are Rack applications that are created by subclassing the API modules under Grape::API. So lets define our base class in base.rb file.
module API class Base < Grape::API mount API::V1::Base end end
Here we define our API module and wrote a class Base which is inheriting Grape::API. We use mount to tell Rails that our API locates here. If you dont know about mount or engine already take a look here.http://guides.rubyonrails.org/engines.html
As Grape supports versioning, we can make a version friendly structure for our API. So we're going to make another folder v1 inside the api folder. For future version we can create v2, v3 and so on.
Inside v1 folder we'll create another base.rb file. This file will be used for mounting all the API classes that will nest inside v1 folder. Lets put these code here,
module API module V1 class Base < Grape::API mount API::V1::Users end end end
Here we already mount our upcoming api class Users. So make another file users.rb inside v1 folder. In this file we'll write our API for users.
module API module V1 class Users < Grape::API include API::V1::Defaults desc "Create user" params do requires :name, type: String end post "/create" do User.create! name: permitted_params[:name] end desc "Get a user" params do requires :id, type: Integer end post "/login" do User.find_by! id: permitted_params[:id] end end end end end
As you can see our first api takes a POST request with a param :name. We define this param type as string. If someone call this api without this param Grape will send back a error message. More info about params can be found in their nice documentation here. https://github.com/ruby-grape/grape#parameters When this api will be called with name param we will take the param and create a new user.
And the second api takes a GET request with a integer param :id. We'll use the id param to find the user and give a json response containing user info. We'll use a serializer for this after a while.
At the top of our class you can see I include a Defaults class. We'll use this class to define some helper methods. Create a new file defaults.rb inside v1 folder.
module API module V1 module Defaults extend ActiveSupport::Concern included do prefix "api" version "v1", using: :path default_format :json format :json formatter :json, Grape::Formatter::ActiveModelSerializers helpers do def permitted_params @permitted_params ||= declared(params, include_missing: false) end end rescue_from ActiveRecord::RecordNotFound do |e| error_response(message: e.message, status: 404) end rescue_from ActiveRecord::RecordInvalid do |e| error_response(message: e.message, status: 422) end end end end end
Here I declare a helper method permitted params which will be useful to identify those params which we mentioned in our api. We extend ActiveSupport::Concern class to handle the error events. We'll send error response in case if there is any error to create or find the user.
You can see at top we declare some basic settings which are mentioned in grape documents. And as a json formatter we choose ActiveModelSerializers. To use this we need to add this gem in our Gemfile.
gem 'grape-active_model_serializers'
Now write a serializer for our user model. Create user_serializer.rb inside app/serializers folder and add this codes.
class GraduateSerializer < ActiveModel::Serializer attributes :id, :name end
We define these two attributes to show in our api response.
To access the api we need to initialize it in our router.
Rails.application.routes.draw do mount API::Base, at: "/" end
And for cross origin resource sharing we'll use rack-cors gem. Add this in gemfile.
gem 'rack-cors', :require => 'rack/cors'
And add this code to your config/application.rb file.
module Api class Application < Rails::Application config.middleware.use Rack::Cors do allow do origins "*" resource "*", headers: :any, methods: [:get, :post, :put, :delete, :options] end end config.active_record.raise_in_transactional_callbacks = true end
Pretty much done. Finally we can add another gem for swagger documentation support.
gem "grape-swagger-rails"
Go to app/controllers/api/v1/base.rb and put some lines to enable swagger.
require "grape-swagger" module API module V1 class Base < Grape::API mount API::V1::Users add_swagger_documentation( api_version: "v1", hide_documentation_path: true, mount_path: "/api/v1/swagger_doc", hide_format: true ) end end end
We also need to define a route for this in the config/routes.rb file.
mount GrapeSwaggerRails::Engine, at: "/documentation"
Now start the rails server and go to http://localhost/documentation. In the url area filled it with our mounted path: http://localhost:3000/api/v1/swagger_doc And we're done. We got our two api with nice documentation ready to go.