V1.3: RESTful Resource(s)


Hanami has native REST support.

At the routing level, there are two methods that can be used to declare them: resources and resource. The former is for plural resources, the latter for singular ones.

Declaring a resource means to generate several default routes with just one line of code.

RESTful Resources

Default Routes

# apps/web/config/routes.rb
resources :books

It generates:

Verb Path Action Name Named Route
GET /books Books::Index :index :books
GET /books/:id Books::Show :show :book
GET /books/new Books::New :new :new_book
POST /books Books::Create :create :books
GET /books/:id/edit Books::Edit :edit :edit_book
PATCH /books/:id Books::Update :update :book
DELETE /books/:id Books::Destroy :destroy :book

Remove Routes

In case we don’t need all the default routes we can use :only and pass one or more action names. We can also black list routes with :except.

resources :books, only: [:new, :create, :show]

# equivalent to

resources :books, except: [:index, :edit, :update, :destroy]

Add Routes

Alongside with default routes we can specify extra routes for single (member) or multiple (collection) resources.

resources :books do
  member do
    # Generates /books/1/toggle, maps to Books::Toggle, named :toggle_book
    get 'toggle'
  end

  collection do
    # Generates /books/search, maps to Books::Search, named :search_books
    get 'search'
  end
end

Configure Controller

Imagine we have a controller named manuscripts, where we have actions like Manuscripts::Index, but we still want to expose those resources as /books. Using the :controller option will save our day.

resources :books, controller: 'manuscripts'

# GET /books/1 will route to Manuscripts::Show, etc.

RESTful Resource

resource :account

It generates:

Verb Path Action Name Named Route
GET /account Account::Show :show :account
GET /account/new Account::New :new :new_account
POST /account Account::Create :create :account
GET /account/edit Account::Edit :edit :edit_account
PATCH /account Account::Update :update :account
DELETE /account Account::Destroy :destroy :account

Remove Routes

resource :account, only: [:show, :edit, :update, :destroy]

# equivalent to

resource :account, except: [:new, :create]

Add Routes

resource :account do
  member do
    # Generates /account/avatar, maps to Account::Avatar, named :avatar_account
    get 'avatar'
  end

  collection do
    # Generates /account/authorizations, maps to Account::Authorizations, named :authorizations_account
    get 'authorizations'
  end
end

Configure Controller

resource :account, controller: 'customer'

Nested Resource(s)

RESTful resource(s) can be nested in order to make available inner resources inside the scope of their parents.

Plural to plural

resources :books do
  resources :reviews
end

It generates default routes for books and the following ones.

Verb Path Action Name Named Route
GET /books/:book_id/reviews Books::Reviews::Index :index :book_reviews
GET /books/:book_id/reviews/:id Books::Reviews::Show :show :book_review
GET /books/:book_id/reviews/new Books::Reviews::New :new :new_book_review
POST /books/:book_id/reviews Books::Reviews::Create :create :book_reviews
GET /books/:book_id/reviews/:id/edit Books::Reviews::Edit :edit :edit_book_review
PATCH /books/:book_id/reviews/:id Books::Reviews::Update :update :book_review
DELETE /books/:book_id/reviews/:id Books::Reviews::Destroy :destroy :book_review

Plural to singular

resources :books do
  resource :cover
end

It generates default routes for books and the following ones.

Verb Path Action Name Named Route
GET /books/:book_id/cover Books::Cover::Show :show :book_cover
GET /books/:book_id/cover/new Books::Cover::New :new :new_book_cover
POST /books/:book_id/cover Books::Cover::Create :create :book_cover
GET /books/:book_id/cover/edit Books::Cover::Edit :edit :edit_book_cover
PATCH /books/:book_id/cover Books::Cover::Update :update :book_cover
DELETE /books/:book_id/cover Books::Cover::Destroy :destroy :book_cover

Singular To Plural

resource :account do
  resources :api_keys
end

It generates default routes for account and the following ones.

Verb Path Action Name Named Route
GET /account/api_keys Account::ApiKeys::Index :index :account_api_keys
GET /account/api_keys/:id Account::ApiKeys::Show :show :account_api_key
GET /account/api_keys/new Account::ApiKeys::New :new :new_account_api_key
POST /account/api_keys Account::ApiKeys::Create :create :account_api_keys
GET /account/api_keys/:id/edit Account::ApiKeys::Edit :edit :edit_account_api_key
PATCH /account/api_keys/:id Account::ApiKeys::Update :update :account_api_key
DELETE /account/api_keys/:id Account::ApiKeys::Destroy :destroy :account_api_key

Singular To Singular

resource :account do
  resource :avatar
end

It generates default routes for account and the following ones.

Verb Path Action Name Named Route
GET /account/avatar Account::Avatar::Show :show :account_avatar
GET /account/avatar/new Account::Avatar::New :new :new_account_avatar
POST /account/avatar Account::Avatar::Create :create :account_avatar
GET /account/avatar/edit Account::Avatar::Edit :edit :edit_account_avatar
PATCH /account/avatar Account::Avatar::Update :update :account_avatar
DELETE /account/avatar Account::Avatar::Destroy :destroy :account_avatar