API is an important part of web applications. They provide interfaces for communication with the app from the outside. While Rails has built-in support for API application, we believe that grape
gem provides a cleaner and more isolated approach to build APIs.
- API files go under the
app/apis
directory. - API files go under a subdirectory named by API purpose + version (e.g.
app_v1_api
,mobile_v1_api
), even if there is only one API is foreseeing now. - Each API module directory should contain
api.rb
file with classAPI
which defines configurations and mounts all needed resources and helpers for this API. - Each API subdirectory contains predefined directories (
resources/
,entities/
,helpers/
) to store corresponding classes. - Each API resource are stored in separate file (e.g.
UsersResource
,OrdersResource
,RegistrationsResource
, etc) and class which is inherited fromGrape::API.
. - Each API resource class (e.g.
UsersResource
) defines a single resource (e.g.resource :users do ... end
). - Entities are stored in
entities/
directory and inherited fromGrape::Entity
class. - Each API resource, entity class or helpers module class are wrapped into corresponding module (e.g.
AppV1API::Resources
,AppV1API::Entities
,AppV1API::Helpers
). - Entity class name corresponds with the model it is related to (e.g.
UserEntity
forUser
model,OrderEntity
forOrder
model). - Specs directory structure follows same directory names (e.g.
spec/apis/app_v1_api/
,spec/apis/mobile_v1_api/
). - Consider using
rails generate auxiliary_rails:api_resource
by auxiliary_rails gem.
app/
apis/
app_v1_api/ - API for a generic purpose (default)
entities/
user_entity.rb
helpers/
api_helper.rb
users_api_helper.rb
resources/
sessions_resource.rb
users_resource.rb
api.rb
mobile_v1_api/ - API for mobile apps (version 1)
...
mobile_v2_api/ - API for mobile apps (version 2)
...
twilio_v1_api/ - API for webhooks and callbacks from Twilio
entities/
helpers/
resources/
api.rb
spec/
apis/
app_v1_api/
resources/
sessions_resource_spec.rb
twilio_v1_api/
resources/
*_resource_spec.rb
## AppV1API ##
# app/apis/app_v1_api/api.rb
module AppV1API
class API < Grape::API
version 'v1'
format :json
rescue_from :all
helpers Helpers::APIHelper
helpers Helpers::UsersAPIHelper
mount Resources::SessionsResource
add_swagger_documentation(
info: {
title: 'Application API V1'
}
)
end
end
# app/apis/app_v1_api/resources/sessions_resource.rb
module AppV1API::Resources
class SessionsResource < Grape::API
resource :sessions do
desc 'Login user'
params do
requires :email, type: String, desc: 'User email'
requires :password, type: String, desc: 'User password'
end
post do
# login user
present user,
with: AppV1API::Entities::UserEntity
end
desc 'Logout user'
delete do
# logout user
end
end
end
end
# app/apis/app_v1_api/resources/users_resource.rb
module AppV1API::Resources
class UsersResource < Grape::API
resource :users do
desc 'Returns resource collection'
get do
# ...
end
# Nested Versioning if you need minor updates to API
version 'v1.1' do
desc 'Returns resource collection (API Version 1.1)'
get do
# ...
end
end
end
end
end
# app/apis/app_v1_api/entities/user_entity.rb
module AppV1API::Entities
class UserEntity < Grape::Entity
expose :email
end
end
# app/apis/app_v1_api/helpers/api_helper.rb
module AppV1API::Helpers
class APIHelper
# generic API helpers
end
end
# app/apis/app_v1_api/helpers/users_api_helper.rb
module AppV1API::Helpers
class UsersAPIHelper
# API helpers specific for user resource
end
end
# config/routes.rb
mount AppV1API::API => '/api'
# spec/apis/app_v1_api/resources/sessions_resource_spec.rb
require 'rails_helper'
describe AppV1API::Resources::SessionsResource, type: :request do
describe 'POST /api/v1/sessions' do
# ...
end
describe 'DELETE /api/v1/sessions' do
# ...
end
end
## MobileV1API ##
# app/apis/mobile_v1_api/api.rb
module MobileV1API
class API < Grape::API
version 'v1'
format :json
rescue_from :all
helpers Helpers::APIHelper
helpers Helpers::UsersAPIHelper
mount Resources::SessionsResource
end
end
# config/routes.rb
mount MobileV1API::API => '/api'
Some of the more commonly used HTTP status codes are:
200 OK
— request has succeeded.201 Created
— new resource has been created.204 No Content
— no content needs to be returned (e.g. when deleting a resource).
400 Bad Request
— request is malformed in some way (e.g. wrong formatting of JSON, invalid request params, etc).401 Unauthorized
— authentication failed (valid credentials are required).403 Forbidden
— authorization failed (client/user is authenticated but does not have permissions for the requested resource or action).404 Not Found
— resource could not be found.422 Unprocessable Entity
— resource hasn't be saved (e.g. validations on the resource failed) or action can't be performed.
500 Internal Server Error
— something exploded in your application.
# Gemfile
gem 'grape'
gem 'grape-entity'
gem 'grape-swagger'
gem 'grape-swagger-entity'
gem 'grape-swagger-rails'
group :test do
gem 'airborne'
end
# config/initializers/swagger.rb
GrapeSwaggerRails.options.app_name = 'Application Swagger'
GrapeSwaggerRails.options.hide_url_input = true
GrapeSwaggerRails.options.before_action do
GrapeSwaggerRails.options.app_url = \
request.protocol + request.host_with_port + '/api/v1'
end
# config/routes.rb
if Rails.env.in? %w[development]
mount GrapeSwaggerRails::Engine => '/api/docs'
end
- Gems for APIs - ErgoServ's list of recommended gems.
- https://github.com/ergoserv/auxiliary_rails
- httpstatuses.com - HTTP Status Codes is an easy to reference database of HTTP Status Codes with their definitions and helpful code references all in one place.
- JSON:API - A specification for building advanced APIs in JSON.