RESTful API with Grape gem
Bài đăng này đã không được cập nhật trong 7 năm
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.
All rights reserved