Class: Hanami::Router

Inherits:
Object
  • Object
show all
Defined in:
lib/hanami/router.rb,
lib/hanami/router/version.rb

Overview

Rack compatible, lightweight and fast HTTP Router.

Examples:

It offers an intuitive DSL, that supports most of the HTTP verbs:

require 'hanami/router'

endpoint = ->(env) { [200, {}, ['Welcome to Hanami::Router!']] }
router = Hanami::Router.new do
  get     '/', to: endpoint # => get and head requests
  post    '/', to: endpoint
  put     '/', to: endpoint
  patch   '/', to: endpoint
  delete  '/', to: endpoint
  options '/', to: endpoint
  trace   '/', to: endpoint
end

Specify an endpoint with ‘:to` (Rack compatible object)

require 'hanami/router'

endpoint = ->(env) { [200, {}, ['Welcome to Hanami::Router!']] }
router = Hanami::Router.new do
  get '/', to: endpoint
end

# :to is mandatory for the default resolver (`Hanami::Routing::EndpointResolver.new`),
# This behavior can be changed by passing a custom resolver to `Hanami::Router#initialize`

Specify an endpoint with ‘:to` (controller and action string)

require 'hanami/router'

router = Hanami::Router.new do
  get '/', to: 'articles#show' # => Articles::Show
end

# This is a builtin feature for a Hanami::Controller convention.

Specify a named route with ‘:as`

require 'hanami/router'

endpoint = ->(env) { [200, {}, ['Welcome to Hanami::Router!']] }
router = Hanami::Router.new(scheme: 'https', host: 'hanamirb.org') do
  get '/', to: endpoint, as: :root
end

router.path(:root) # => '/'
router.url(:root)  # => 'https://hanamirb.org/'

# This isn't mandatory for the default route class (`Hanami::Routing::Route`),
# This behavior can be changed by passing a custom route to `Hanami::Router#initialize`

Mount an application

require 'hanami/router'

router = Hanami::Router.new do
  mount Api::App, at: '/api'
end

# All the requests starting with "/api" will be forwarded to Api::App

Since:

  • 0.1.0

Defined Under Namespace

Classes: NotRoutableEndpointError

Constant Summary collapse

ROOT_PATH =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Defines root path

See Also:

Since:

  • 0.7.0

'/'.freeze
VERSION =

Since:

  • 0.1.0

'1.3.2'.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}, &blk) ⇒ Hanami::Router

Initialize the router.

Examples:

Basic example

require 'hanami/router'

endpoint = ->(env) { [200, {}, ['Welcome to Hanami::Router!']] }

router = Hanami::Router.new
router.get '/', to: endpoint

# or

router = Hanami::Router.new do
  get '/', to: endpoint
end

Body parsers

require 'json'
require 'hanami/router'

# It parses JSON body and makes the attributes available to the params

endpoint = ->(env) { [200, {},[env['router.params'].inspect]] }

router = Hanami::Router.new(parsers: [:json]) do
  patch '/books/:id', to: endpoint
end

# From the shell

curl http://localhost:2300/books/1    \
  -H "Content-Type: application/json" \
  -H "Accept: application/json"       \
  -d '{"published":"true"}'           \
  -X PATCH

# It returns

[200, {}, ["{:published=>\"true\",:id=>\"1\"}"]]

Custom body parser

require 'hanami/router'

class XmlParser
  def mime_types
    ['application/xml', 'text/xml']
  end

  # Parse body and return a Hash
  def parse(body)
    # ...
  end
end

# It parses XML body and makes the attributes available to the params

endpoint = ->(env) { [200, {},[env['router.params'].inspect]] }

router = Hanami::Router.new(parsers: [XmlParser.new]) do
  patch '/authors/:id', to: endpoint
end

# From the shell

curl http://localhost:2300/authors/1 \
  -H "Content-Type: application/xml" \
  -H "Accept: application/xml"       \
  -d '<name>LG</name>'               \
  -X PATCH

# It returns

[200, {}, ["{:name=>\"LG\",:id=>\"1\"}"]]

Parameters:

  • options (Hash) (defaults to: {})

    the options to initialize the router

  • blk (Proc)

    the optional block to define the routes

Options Hash (options):

  • :scheme (String)

    The HTTP scheme (defaults to ‘“http”`)

  • :host (String)

    The URL host (defaults to ‘“localhost”`)

  • :port (String)

    The URL port (defaults to ‘“80”`)

  • :resolver (Object, #resolve, #find, #action_separator)

    the route resolver (defaults to ‘Hanami::Routing::EndpointResolver.new`)

  • :route (Object, #generate)

    the route class (defaults to ‘Hanami::Routing::Route`)

  • :action_separator (String)

    the separator between controller and action name (eg. ‘dashboard#show’, where ‘#’ is the :action_separator)

  • :parsers (Array<Symbol,String,Object #mime_types, parse>)

    the body parsers for mime types

Since:

  • 0.1.0



237
238
239
240
# File 'lib/hanami/router.rb', line 237

def initialize(options = {}, &blk)
  @router = Routing::HttpRouter.new(options)
  define(&blk)
end

Class Method Details

.define(&blk) ⇒ Proc

Returns the given block as it is.

When Hanami::Router is used as a standalone gem and the routes are defined into a configuration file, some systems could raise an exception.

Imagine the following file into a Ruby on Rails application:

get '/', to: 'api#index'

Because Ruby on Rails in production mode use to eager load code and the routes file uses top level method calls, it crashes the application.

If we wrap these routes with Hanami::Router.define, the block doesn’t get yielded but just returned to the caller as it is.

Usually the receiver of this block is Hanami::Router#initialize, which finally evaluates the block.

Examples:

# apps/web/config/routes.rb
Hanami::Router.define do
  get '/', to: 'home#index'
end

Parameters:

  • blk (Proc)

    a set of route definitions

Returns:

  • (Proc)

    the given block

Since:

  • 0.5.0



140
141
142
# File 'lib/hanami/router.rb', line 140

def self.define(&blk)
  blk
end

Instance Method Details

#call(env) ⇒ Rack::Response, Array

Resolve the given Rack env to a registered endpoint and invoke it.

Parameters:

  • env (Hash)

    a Rack env instance

Returns:

  • (Rack::Response, Array)

Since:

  • 0.1.0



1018
1019
1020
# File 'lib/hanami/router.rb', line 1018

def call(env)
  @router.call(env)
end

#define(&blk) ⇒ Hanami::Routing::Route

To support defining routes in the ‘define` wrapper.

Examples:

In Hanami framework

class Application < Hanami::Application
  configure do
    routes 'config/routes'
  end
end

# In `config/routes`

define do
  get # ...
end

Parameters:

  • blk (Proc)

    the block to define the routes

Returns:

Since:

  • 0.2.0



276
277
278
# File 'lib/hanami/router.rb', line 276

def define(&blk)
  instance_eval(&blk) if block_given?
end

#defined?TrueClass, FalseClass

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Check if there are defined routes

Examples:


router = Hanami::Router.new
router.defined? # => false

router = Hanami::Router.new { get '/', to: ->(env) { } }
router.defined? # => true

Returns:

  • (TrueClass, FalseClass)

    the result of the check

Since:

  • 0.2.0



294
295
296
# File 'lib/hanami/router.rb', line 294

def defined?
  @router.routes.any?
end

#delete(path, options = {}, &blk) ⇒ Hanami::Routing::Route

Defines a route that accepts a DELETE request for the given path.

Parameters:

  • path (String)

    the relative URL to be matched

  • options (Hash) (defaults to: {})

    the options to customize the route

  • blk (Proc)

    the anonymous proc to be used as endpoint for the route

Options Hash (options):

  • :to (String, Proc, Class, Object#call)

    the endpoint

Returns:

See Also:

Since:

  • 0.1.0



488
489
490
# File 'lib/hanami/router.rb', line 488

def delete(path, options = {}, &blk)
  @router.delete(path, options, &blk)
end

#get(path, options = {}, &blk) ⇒ Hanami::Routing::Route

Defines a route that accepts a GET request for the given path.

Examples:

Fixed matching string

require 'hanami/router'

router = Hanami::Router.new
router.get '/hanami', to: ->(env) { [200, {}, ['Hello from Hanami!']] }

String matching with variables

require 'hanami/router'

router = Hanami::Router.new
router.get '/flowers/:id',
  to: ->(env) {
    [
      200,
      {},
      ["Hello from Flower no. #{ env['router.params'][:id] }!"]
    ]
  }

Variables Constraints

require 'hanami/router'

router = Hanami::Router.new
router.get '/flowers/:id',
  id: /\d+/,
  to: ->(env) { [200, {}, [":id must be a number!"]] }

String matching with globbling

require 'hanami/router'

router = Hanami::Router.new
router.get '/*',
  to: ->(env) {
    [
      200,
      {},
      ["This is catch all: #{ env['router.params'].inspect }!"]
    ]
  }

String matching with optional tokens

require 'hanami/router'

router = Hanami::Router.new
router.get '/hanami(.:format)',
  to: ->(env) {
    [200, {}, ["You've requested #{ env['router.params'][:format] }!"]]
  }

Named routes

require 'hanami/router'

router = Hanami::Router.new(scheme: 'https', host: 'hanamirb.org')
router.get '/hanami',
  to: ->(env) { [200, {}, ['Hello from Hanami!']] },
  as: :hanami

router.path(:hanami) # => "/hanami"
router.url(:hanami)  # => "https://hanamirb.org/hanami"

Duck typed endpoints (Rack compatible objects)

require 'hanami/router'

router = Hanami::Router.new

router.get '/hanami',      to: ->(env) { [200, {}, ['Hello from Hanami!']] }
router.get '/middleware', to: Middleware
router.get '/rack-app',   to: RackApp.new
router.get '/method',     to: ActionControllerSubclass.action(:new)

# Everything that responds to #call is invoked as it is

Duck typed endpoints (strings)

require 'hanami/router'

class RackApp
  def call(env)
    # ...
  end
end

router = Hanami::Router.new
router.get '/hanami', to: 'rack_app' # it will map to RackApp.new

Duck typed endpoints (string: controller + action)

require 'hanami/router'

module Flowers
  class Index
    def call(env)
      # ...
    end
  end
end

 router = Hanami::Router.new
 router.get '/flowers', to: 'flowers#index'

 # It will map to Flowers::Index.new, which is the
 # Hanami::Controller convention.

Parameters:

  • path (String)

    the relative URL to be matched

  • options (Hash) (defaults to: {})

    the options to customize the route

  • blk (Proc)

    the anonymous proc to be used as endpoint for the route

Options Hash (options):

  • :to (String, Proc, Class, Object#call)

    the endpoint

Returns:

Since:

  • 0.1.0



412
413
414
# File 'lib/hanami/router.rb', line 412

def get(path, options = {}, &blk)
  @router.get(path, options, &blk)
end

#inspectorObject

Returns an routes inspector

Examples:

require 'hanami/router'

router = Hanami::Router.new do
  get    '/',       to: 'home#index'
  get    '/login',  to: 'sessions#new',     as: :login
  post   '/login',  to: 'sessions#create'
  delete '/logout', to: 'sessions#destroy', as: :logout
end

puts router.inspector
  # =>        GET, HEAD  /                        Home::Index
       login  GET, HEAD  /login                   Sessions::New
              POST       /login                   Sessions::Create
       logout GET, HEAD  /logout                  Sessions::Destroy

See Also:

Since:

  • 0.2.0



1216
1217
1218
1219
# File 'lib/hanami/router.rb', line 1216

def inspector
  require 'hanami/routing/routes_inspector'
  Routing::RoutesInspector.new(@router.routes, @router.prefix)
end

Defines a route that accepts a LINK request for the given path.

Parameters:

  • path (String)

    the relative URL to be matched

  • options (Hash) (defaults to: {})

    the options to customize the route

  • blk (Proc)

    the anonymous proc to be used as endpoint for the route

Options Hash (options):

  • :to (String, Proc, Class, Object#call)

    the endpoint

Returns:

See Also:

Since:

  • 0.8.0



526
527
528
# File 'lib/hanami/router.rb', line 526

def link(path, options = {}, &blk)
  @router.link(path, options, &blk)
end

#mount(app, options) ⇒ Object

Mount a Rack application at the specified path. All the requests starting with the specified path, will be forwarded to the given application.

All the other methods (eg #get) support callable objects, but they restrict the range of the acceptable HTTP verb. Mounting an application with #mount doesn’t apply this kind of restriction at the router level, but let the application to decide.

Examples:

Basic usage

require 'hanami/router'

Hanami::Router.new do
  mount Api::App.new, at: '/api'
end

# Requests:
#
# GET  /api          # => 200
# GET  /api/articles # => 200
# POST /api/articles # => 200
# GET  /api/unknown  # => 404

Difference between #get and #mount

require 'hanami/router'

Hanami::Router.new do
  get '/rack1',      to: RackOne.new
  mount RackTwo.new, at: '/rack2'
end

# Requests:
#
# # /rack1 will only accept GET
# GET  /rack1        # => 200 (RackOne.new)
# POST /rack1        # => 405
#
# # /rack2 accepts all the verbs and delegate the decision to RackTwo
# GET  /rack2        # => 200 (RackTwo.new)
# POST /rack2        # => 200 (RackTwo.new)

Types of mountable applications

require 'hanami/router'

class RackOne
  def self.call(env)
  end
end

class RackTwo
  def call(env)
  end
end

class RackThree
  def call(env)
  end
end

module Dashboard
  class Index
    def call(env)
    end
  end
end

Hanami::Router.new do
  mount RackOne,                             at: '/rack1'
  mount RackTwo,                             at: '/rack2'
  mount RackThree.new,                       at: '/rack3'
  mount ->(env) {[200, {}, ['Rack Four']]},  at: '/rack4'
  mount 'dashboard#index',                   at: '/dashboard'
end

# 1. RackOne is used as it is (class), because it respond to .call
# 2. RackTwo is initialized, because it respond to #call
# 3. RackThree is used as it is (object), because it respond to #call
# 4. That Proc is used as it is, because it respond to #call
# 5. That string is resolved as Dashboard::Index (Hanami::Controller)

Parameters:

  • app (#call)

    a class or an object that responds to #call

  • options (Hash)

    the options to customize the mount

Options Hash (options):

  • the (:at)

    relative path where to mount the app

Since:

  • 0.1.1



1007
1008
1009
# File 'lib/hanami/router.rb', line 1007

def mount(app, options)
  @router.mount(app, options)
end

#namespace(namespace, &blk) ⇒ Hanami::Routing::Namespace

Defines a Ruby block: all the routes defined within it will be namespaced with the given relative path.

Namespaces blocks can be nested multiple times.

Examples:

Basic example

require 'hanami/router'

Hanami::Router.new do
  namespace 'trees' do
    get '/sequoia', to: endpoint # => '/trees/sequoia'
  end
end

Nested namespaces

require 'hanami/router'

Hanami::Router.new do
  namespace 'animals' do
    namespace 'mammals' do
      get '/cats', to: endpoint # => '/animals/mammals/cats'
    end
  end
end
require 'hanami/router'

router = Hanami::Router.new
router.namespace 'trees' do
  get '/sequoia', to: endpoint # => '/trees/sequoia'
end

Parameters:

  • namespace (String)

    the relative path where the nested routes will be mounted

  • blk (Proc)

    the block that defines the resources

Returns:

See Also:

Since:

  • 0.1.0



673
674
675
# File 'lib/hanami/router.rb', line 673

def namespace(namespace, &blk)
  Routing::Namespace.new(self, namespace, &blk)
end

#options(path, options = {}, &blk) ⇒ Hanami::Routing::Route

Defines a route that accepts a OPTIONS request for the given path.

Parameters:

  • path (String)

    the relative URL to be matched

  • options (Hash) (defaults to: {})

    the options to customize the route

  • blk (Proc)

    the anonymous proc to be used as endpoint for the route

Options Hash (options):

  • :to (String, Proc, Class, Object#call)

    the endpoint

Returns:

See Also:

Since:

  • 0.1.0



594
595
596
# File 'lib/hanami/router.rb', line 594

def options(path, options = {}, &blk)
  @router.options(path, options, &blk)
end

#patch(path, options = {}, &blk) ⇒ Hanami::Routing::Route

Defines a route that accepts a PATCH request for the given path.

Parameters:

  • path (String)

    the relative URL to be matched

  • options (Hash) (defaults to: {})

    the options to customize the route

  • blk (Proc)

    the anonymous proc to be used as endpoint for the route

Options Hash (options):

  • :to (String, Proc, Class, Object#call)

    the endpoint

Returns:

See Also:

Since:

  • 0.1.0



469
470
471
# File 'lib/hanami/router.rb', line 469

def patch(path, options = {}, &blk)
  @router.patch(path, options, &blk)
end

#path(route, *args) ⇒ String

Generate an relative URL for a specified named route. The additional arguments will be used to compose the relative URL - in

case it has tokens to match - and for compose the query string.

Examples:

require 'hanami/router'

router = Hanami::Router.new(scheme: 'https', host: 'hanamirb.org')
router.get '/login', to: 'sessions#new',    as: :login
router.get '/:name', to: 'frameworks#show', as: :framework

router.path(:login)                          # => "/login"
router.path(:login, return_to: '/dashboard') # => "/login?return_to=%2Fdashboard"
router.path(:framework, name: 'router')      # => "/router"

Parameters:

  • route (Symbol)

    the route name

Returns:

  • (String)

Raises:

Since:

  • 0.1.0



1164
1165
1166
# File 'lib/hanami/router.rb', line 1164

def path(route, *args)
  @router.path(route, *args)
end

#post(path, options = {}, &blk) ⇒ Hanami::Routing::Route

Defines a route that accepts a POST request for the given path.

Parameters:

  • path (String)

    the relative URL to be matched

  • options (Hash) (defaults to: {})

    the options to customize the route

  • blk (Proc)

    the anonymous proc to be used as endpoint for the route

Options Hash (options):

  • :to (String, Proc, Class, Object#call)

    the endpoint

Returns:

See Also:

Since:

  • 0.1.0



431
432
433
# File 'lib/hanami/router.rb', line 431

def post(path, options = {}, &blk)
  @router.post(path, options, &blk)
end

#put(path, options = {}, &blk) ⇒ Hanami::Routing::Route

Defines a route that accepts a PUT request for the given path.

Parameters:

  • path (String)

    the relative URL to be matched

  • options (Hash) (defaults to: {})

    the options to customize the route

  • blk (Proc)

    the anonymous proc to be used as endpoint for the route

Options Hash (options):

  • :to (String, Proc, Class, Object#call)

    the endpoint

Returns:

See Also:

Since:

  • 0.1.0



450
451
452
# File 'lib/hanami/router.rb', line 450

def put(path, options = {}, &blk)
  @router.put(path, options, &blk)
end

#recognize(env, options = {}, params = nil) ⇒ Hanami::Routing::RecognizedRoute

Recognize the given env, path, or name and return a route for testing inspection.

If the route cannot be recognized, it still returns an object for testing inspection.

Examples:

Successful Path Recognition

require 'hanami/router'

router = Hanami::Router.new do
  get '/books/:id', to: 'books#show', as: :book
end

route = router.recognize('/books/23')
route.verb      # => "GET" (default)
route.routable? # => true
route.params    # => {:id=>"23"}

Successful Rack Env Recognition

require 'hanami/router'

router = Hanami::Router.new do
  get '/books/:id', to: 'books#show', as: :book
end

route = router.recognize(Rack::MockRequest.env_for('/books/23'))
route.verb      # => "GET" (default)
route.routable? # => true
route.params    # => {:id=>"23"}

Successful Named Route Recognition

require 'hanami/router'

router = Hanami::Router.new do
  get '/books/:id', to: 'books#show', as: :book
end

route = router.recognize(:book, id: 23)
route.verb      # => "GET" (default)
route.routable? # => true
route.params    # => {:id=>"23"}

Failing Recognition For Unknown Path

require 'hanami/router'

router = Hanami::Router.new do
  get '/books/:id', to: 'books#show', as: :book
end

route = router.recognize('/books')
route.verb      # => "GET" (default)
route.routable? # => false

Failing Recognition For Path With Wrong HTTP Verb

require 'hanami/router'

router = Hanami::Router.new do
  get '/books/:id', to: 'books#show', as: :book
end

route = router.recognize('/books/23', method: :post)
route.verb      # => "POST"
route.routable? # => false

Failing Recognition For Rack Env With Wrong HTTP Verb

require 'hanami/router'

router = Hanami::Router.new do
  get '/books/:id', to: 'books#show', as: :book
end

route = router.recognize(Rack::MockRequest.env_for('/books/23', method: :post))
route.verb      # => "POST"
route.routable? # => false

Failing Recognition Named Route With Wrong Params

require 'hanami/router'

router = Hanami::Router.new do
  get '/books/:id', to: 'books#show', as: :book
end

route = router.recognize(:book)
route.verb      # => "GET" (default)
route.routable? # => false

Failing Recognition Named Route With Wrong HTTP Verb

require 'hanami/router'

router = Hanami::Router.new do
  get '/books/:id', to: 'books#show', as: :book
end

route = router.recognize(:book, {method: :post}, {id: 1})
route.verb      # => "POST"
route.routable? # => false
route.params    # => {:id=>"1"}

Parameters:

  • env (Hash, String, Symbol)

    Rack env, path or route name

  • options (Hash) (defaults to: {})

    a set of options for Rack env or route params

  • params (Hash) (defaults to: nil)

    a set of params

Returns:

See Also:

Since:

  • 0.5.0



1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
# File 'lib/hanami/router.rb', line 1130

def recognize(env, options = {}, params = nil)
  require 'hanami/routing/recognized_route'

  env          = env_for(env, options, params)
  responses, _ = *@router.recognize(env)

  Routing::RecognizedRoute.new(
    responses.nil? ? responses : responses.first,
    env, @router)
end

#redirect(path, options = {}, &endpoint) ⇒ Hanami::Routing::Route

Defines an HTTP redirect

Examples:

require 'hanami/router'

Hanami::Router.new do
  redirect '/legacy',  to: '/new_endpoint'
  redirect '/legacy2', to: '/new_endpoint2', code: 302
end
require 'hanami/router'

router = Hanami::Router.new
router.redirect '/legacy',  to: '/new_endpoint'

Parameters:

  • path (String)

    the path that needs to be redirected

  • options (Hash) (defaults to: {})

    the options to customize the redirect behavior

Options Hash (options):

  • the (Fixnum)

    HTTP status to return (defaults to ‘301`)

Returns:

  • (Hanami::Routing::Route)

    the generated route. This may vary according to the ‘:route` option passed to the initializer

See Also:

Since:

  • 0.1.0



624
625
626
627
628
629
# File 'lib/hanami/router.rb', line 624

def redirect(path, options = {}, &endpoint)
  destination_path = @router.find(options)
  get(path).redirect(destination_path, options[:code] || 301).tap do |route|
    route.dest = Hanami::Routing::RedirectEndpoint.new(destination_path, route.dest)
  end
end

#resource(name, options = {}, &blk) ⇒ Hanami::Routing::Resource

Defines a set of named routes for a single RESTful resource. It has a built-in integration for Hanami::Controller.

Examples:

Default usage

require 'hanami/router'

Hanami::Router.new do
  resource 'identity'
end

# It generates:
#
# +--------+----------------+-------------------+----------+----------------+
# | Verb   | Path           | Action            | Name     | Named Route    |
# +--------+----------------+-------------------+----------+----------------+
# | GET    | /identity      | Identity::Show    | :show    | :identity      |
# | GET    | /identity/new  | Identity::New     | :new     | :new_identity  |
# | POST   | /identity      | Identity::Create  | :create  | :identity      |
# | GET    | /identity/edit | Identity::Edit    | :edit    | :edit_identity |
# | PATCH  | /identity      | Identity::Update  | :update  | :identity      |
# | DELETE | /identity      | Identity::Destroy | :destroy | :identity      |
# +--------+----------------+-------------------+----------+----------------+

Limit the generated routes with :only

require 'hanami/router'

Hanami::Router.new do
  resource 'identity', only: [:show, :new, :create]
end

# It generates:
#
# +--------+----------------+------------------+----------+----------------+
# | Verb   | Path           | Action           | Name     | Named Route    |
# +--------+----------------+------------------+----------+----------------+
# | GET    | /identity      | Identity::Show   | :show    | :identity      |
# | GET    | /identity/new  | Identity::New    | :new     | :new_identity  |
# | POST   | /identity      | Identity::Create | :create  | :identity      |
# +--------+----------------+------------------+----------+----------------+

Limit the generated routes with :except

require 'hanami/router'

Hanami::Router.new do
  resource 'identity', except: [:edit, :update, :destroy]
end

# It generates:
#
# +--------+----------------+------------------+----------+----------------+
# | Verb   | Path           | Action           | Name     | Named Route    |
# +--------+----------------+------------------+----------+----------------+
# | GET    | /identity      | Identity::Show   | :show    | :identity      |
# | GET    | /identity/new  | Identity::New    | :new     | :new_identity  |
# | POST   | /identity      | Identity::Create | :create  | :identity      |
# +--------+----------------+------------------+----------+----------------+

Additional single routes

require 'hanami/router'

Hanami::Router.new do
  resource 'identity', only: [] do
    member do
      patch 'activate'
    end
  end
end

# It generates:
#
# +--------+--------------------+--------------------+------+--------------------+
# | Verb   | Path               | Action             | Name | Named Route        |
# +--------+--------------------+--------------------+------+--------------------+
# | PATCH  | /identity/activate | Identity::Activate |      | :activate_identity |
# +--------+--------------------+--------------------+------+--------------------+

Additional collection routes

require 'hanami/router'

Hanami::Router.new do
  resource 'identity', only: [] do
    collection do
      get 'keys'
    end
  end
end

# It generates:
#
# +------+----------------+----------------+------+----------------+
# | Verb | Path           | Action         | Name | Named Route    |
# +------+----------------+----------------+------+----------------+
# | GET  | /identity/keys | Identity::Keys |      | :keys_identity |
# +------+----------------+----------------+------+----------------+

Parameters:

  • name (String)

    the name of the resource

  • options (Hash) (defaults to: {})

    a set of options to customize the routes

  • blk (Proc)

    a block of code to generate additional routes

Options Hash (options):

  • :only (Array<Symbol>)

    a subset of the default routes that we want to generate

  • :except (Array<Symbol>)

    prevent the given routes to be generated

Returns:

See Also:

Since:

  • 0.1.0



795
796
797
# File 'lib/hanami/router.rb', line 795

def resource(name, options = {}, &blk)
  Routing::Resource.new(self, name, options.merge(separator: @router.action_separator), &blk)
end

#resources(name, options = {}, &blk) ⇒ Hanami::Routing::Resources

Defines a set of named routes for a plural RESTful resource. It has a built-in integration for Hanami::Controller.

Examples:

Default usage

require 'hanami/router'

Hanami::Router.new do
  resources 'articles'
end

# It generates:
#
# +--------+--------------------+-------------------+----------+----------------+
# | Verb   | Path               | Action            | Name     | Named Route    |
# +--------+--------------------+-------------------+----------+----------------+
# | GET    | /articles          | Articles::Index   | :index   | :articles      |
# | GET    | /articles/:id      | Articles::Show    | :show    | :articles      |
# | GET    | /articles/new      | Articles::New     | :new     | :new_articles  |
# | POST   | /articles          | Articles::Create  | :create  | :articles      |
# | GET    | /articles/:id/edit | Articles::Edit    | :edit    | :edit_articles |
# | PATCH  | /articles/:id      | Articles::Update  | :update  | :articles      |
# | DELETE | /articles/:id      | Articles::Destroy | :destroy | :articles      |
# +--------+--------------------+-------------------+----------+----------------+

Limit the generated routes with :only

require 'hanami/router'

Hanami::Router.new do
  resources 'articles', only: [:index]
end

# It generates:
#
# +------+-----------+-----------------+--------+-------------+
# | Verb | Path      | Action          | Name   | Named Route |
# +------+-----------+-----------------+--------+-------------+
# | GET  | /articles | Articles::Index | :index | :articles   |
# +------+-----------+-----------------+--------+-------------+

Limit the generated routes with :except

require 'hanami/router'

Hanami::Router.new do
  resources 'articles', except: [:edit, :update]
end

# It generates:
#
# +--------+--------------------+-------------------+----------+----------------+
# | Verb   | Path               | Action            | Name     | Named Route    |
# +--------+--------------------+-------------------+----------+----------------+
# | GET    | /articles          | Articles::Index   | :index   | :articles      |
# | GET    | /articles/:id      | Articles::Show    | :show    | :articles      |
# | GET    | /articles/new      | Articles::New     | :new     | :new_articles  |
# | POST   | /articles          | Articles::Create  | :create  | :articles      |
# | DELETE | /articles/:id      | Articles::Destroy | :destroy | :articles      |
# +--------+--------------------+-------------------+----------+----------------+

Additional single routes

require 'hanami/router'

Hanami::Router.new do
  resources 'articles', only: [] do
    member do
      patch 'publish'
    end
  end
end

# It generates:
#
# +--------+-----------------------+-------------------+------+-------------------+
# | Verb   | Path                  | Action            | Name | Named Route       |
# +--------+-----------------------+-------------------+------+-------------------+
# | PATCH  | /articles/:id/publish | Articles::Publish |      | :publish_articles |
# +--------+-----------------------+-------------------+------+-------------------+

Additional collection routes

require 'hanami/router'

Hanami::Router.new do
  resources 'articles', only: [] do
    collection do
      get 'search'
    end
  end
end

# It generates:
#
# +------+------------------+------------------+------+------------------+
# | Verb | Path             | Action           | Name | Named Route      |
# +------+------------------+------------------+------+------------------+
# | GET  | /articles/search | Articles::Search |      | :search_articles |
# +------+------------------+------------------+------+------------------+

Parameters:

  • name (String)

    the name of the resource

  • options (Hash) (defaults to: {})

    a set of options to customize the routes

  • blk (Proc)

    a block of code to generate additional routes

Options Hash (options):

  • :only (Array<Symbol>)

    a subset of the default routes that we want to generate

  • :except (Array<Symbol>)

    prevent the given routes to be generated

Returns:

See Also:

Since:

  • 0.1.0



918
919
920
# File 'lib/hanami/router.rb', line 918

def resources(name, options = {}, &blk)
  Routing::Resources.new(self, name, options.merge(separator: @router.action_separator), &blk)
end

#root(options = {}, &blk) ⇒ Hanami::Routing::Route

Defines a root route (a GET route for ‘/’)

Examples:

Fixed matching string

require 'hanami/router'

router = Hanami::Router.new
router.root to: ->(env) { [200, {}, ['Hello from Hanami!']] }

Included names as ‘root` (for path and url helpers)

require 'hanami/router'

router = Hanami::Router.new(scheme: 'https', host: 'hanamirb.org')
router.root to: ->(env) { [200, {}, ['Hello from Hanami!']] }

router.path(:root) # => "/"
router.url(:root)  # => "https://hanamirb.org/"

Parameters:

  • options (Hash) (defaults to: {})

    the options to customize the route

  • blk (Proc)

    the anonymous proc to be used as endpoint for the route

Options Hash (options):

  • :to (String, Proc, Class, Object#call)

    the endpoint

Returns:

Since:

  • 0.7.0



575
576
577
# File 'lib/hanami/router.rb', line 575

def root(options = {}, &blk)
  @router.get(ROOT_PATH, options.merge(as: :root), &blk)
end

#routesself

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns self

This is a duck-typing trick for compatibility with ‘Hanami::Application`. It’s used by ‘Hanami::Routing::RoutesInspector` to inspect both apps and routers.

Returns:

  • (self)

Since:

  • 0.2.0



252
253
254
# File 'lib/hanami/router.rb', line 252

def routes
  self
end

#trace(path, options = {}, &blk) ⇒ Hanami::Routing::Route

Defines a route that accepts a TRACE request for the given path.

Parameters:

  • path (String)

    the relative URL to be matched

  • options (Hash) (defaults to: {})

    the options to customize the route

  • blk (Proc)

    the anonymous proc to be used as endpoint for the route

Options Hash (options):

  • :to (String, Proc, Class, Object#call)

    the endpoint

Returns:

See Also:

Since:

  • 0.1.0



507
508
509
# File 'lib/hanami/router.rb', line 507

def trace(path, options = {}, &blk)
  @router.trace(path, options, &blk)
end

Defines a route that accepts an UNLINK request for the given path.

Parameters:

  • path (String)

    the relative URL to be matched

  • options (Hash) (defaults to: {})

    the options to customize the route

  • blk (Proc)

    the anonymous proc to be used as endpoint for the route

Options Hash (options):

  • :to (String, Proc, Class, Object#call)

    the endpoint

Returns:

See Also:

Since:

  • 0.8.0



545
546
547
# File 'lib/hanami/router.rb', line 545

def unlink(path, options = {}, &blk)
  @router.unlink(path, options, &blk)
end

#url(route, *args) ⇒ String

Generate a URL for a specified named route. The additional arguments will be used to compose the relative URL - in

case it has tokens to match - and for compose the query string.

Examples:

require 'hanami/router'

router = Hanami::Router.new(scheme: 'https', host: 'hanamirb.org')
router.get '/login', to: 'sessions#new', as: :login
router.get '/:name', to: 'frameworks#show', as: :framework

router.url(:login)                          # => "https://hanamirb.org/login"
router.url(:login, return_to: '/dashboard') # => "https://hanamirb.org/login?return_to=%2Fdashboard"
router.url(:framework, name: 'router')      # => "https://hanamirb.org/router"

Parameters:

  • route (Symbol)

    the route name

Returns:

  • (String)

Raises:

Since:

  • 0.1.0



1191
1192
1193
# File 'lib/hanami/router.rb', line 1191

def url(route, *args)
  @router.url(route, *args)
end