hanami-router 1.3.2 → 2.0.0.alpha1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -3
- data/README.md +192 -154
- data/hanami-router.gemspec +23 -20
- data/lib/hanami/middleware/body_parser.rb +17 -13
- data/lib/hanami/middleware/body_parser/class_interface.rb +56 -56
- data/lib/hanami/middleware/body_parser/errors.rb +7 -4
- data/lib/hanami/middleware/body_parser/json_parser.rb +5 -3
- data/lib/hanami/middleware/error.rb +16 -0
- data/lib/hanami/router.rb +262 -149
- data/lib/hanami/router/version.rb +3 -1
- data/lib/hanami/routing.rb +193 -0
- data/lib/hanami/routing/endpoint.rb +122 -104
- data/lib/hanami/routing/endpoint_resolver.rb +20 -16
- data/lib/hanami/routing/prefix.rb +102 -0
- data/lib/hanami/routing/recognized_route.rb +40 -26
- data/lib/hanami/routing/resource.rb +9 -7
- data/lib/hanami/routing/resource/action.rb +58 -33
- data/lib/hanami/routing/resource/nested.rb +4 -1
- data/lib/hanami/routing/resource/options.rb +3 -1
- data/lib/hanami/routing/resources.rb +6 -4
- data/lib/hanami/routing/resources/action.rb +11 -6
- data/lib/hanami/routing/routes_inspector.rb +22 -20
- data/lib/hanami/routing/scope.rb +112 -0
- metadata +47 -25
- data/lib/hanami-router.rb +0 -1
- data/lib/hanami/routing/error.rb +0 -7
- data/lib/hanami/routing/force_ssl.rb +0 -212
- data/lib/hanami/routing/http_router.rb +0 -220
- data/lib/hanami/routing/http_router_monkey_patch.rb +0 -38
- data/lib/hanami/routing/namespace.rb +0 -98
- data/lib/hanami/routing/parsers.rb +0 -113
- data/lib/hanami/routing/parsing/json_parser.rb +0 -33
- data/lib/hanami/routing/parsing/parser.rb +0 -61
- data/lib/hanami/routing/route.rb +0 -71
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa833cfc2bc3e9d0f796738dc3c8c649f001afdee01662094f387aabc3afa496
|
4
|
+
data.tar.gz: c7f7314b65e6ab36fee40e4a8d2037b4086c0f5a6ae9ddf5002e4d42007826b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd5ca50885e99302376c13c8d0ccdc48db6e59b97d64ca8c3740f976ecfdf0687c6c2f841273286b92af16d880051216e8888353ef24e92285f918c31d67a65f
|
7
|
+
data.tar.gz: b9107bc2be7289893809d2837c37fb5cc6642715239b6c510b76af47a86c71daa186f167f8890a2f7b59292be1eeadaf0aca90bb358e2951563b0414c17245c7
|
data/CHANGELOG.md
CHANGED
@@ -1,10 +1,21 @@
|
|
1
1
|
# Hanami::Router
|
2
2
|
Rack compatible HTTP router for Ruby
|
3
3
|
|
4
|
-
##
|
4
|
+
## v2.0.0.alpha1 - 2019-01-30
|
5
5
|
### Added
|
6
|
-
- [Luca Guidi]
|
7
|
-
- [
|
6
|
+
- [Luca Guidi] Introduce `Hanami::Router#scope` to support single routing tier for Hanami
|
7
|
+
- [Semyon Pupkov] Added `inflector:` option for `Hanami::Router#initialize` based on `dry-inflector`
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
- [Luca Guidi] Drop support for Ruby: MRI 2.3, and 2.4.
|
11
|
+
- [Luca Guidi] Renamed `Hanami::Router#namespace` => `#prefix`
|
12
|
+
- [Gustavo Caso] Remove body cleanup for `HEAD` requests
|
13
|
+
- [Semyon Pupkov] Remove the ability to force SSL (`force_ssl:` option for `Hanami::Router#initialize`)
|
14
|
+
- [Gustavo Caso] Remove router body parsers (`parsers:` option for `Hanami::Router#initialize`)
|
15
|
+
- [Luca Guidi] Globbed path requires named capture (was `get "/files/*"`, now is `get "/files/*names"`)
|
16
|
+
- [Luca Guidi] Router is frozen after initialization
|
17
|
+
- [Luca Guidi] All the code base respects the frozen string pragma
|
18
|
+
- [Luca Guidi] `Hanami::Router#initialize` requires `configuration:` option if routes endpoints are `Hanami::Action` subclasses
|
8
19
|
|
9
20
|
## v1.3.1 - 2019-01-18
|
10
21
|
### Added
|
data/README.md
CHANGED
@@ -5,7 +5,7 @@ Rack compatible, lightweight and fast HTTP Router for Ruby and [Hanami](http://h
|
|
5
5
|
## Status
|
6
6
|
|
7
7
|
[](https://badge.fury.io/rb/hanami-router)
|
8
|
-
[](https://travis-ci.org/hanami/router)
|
9
9
|
[](https://circleci.com/gh/hanami/router/tree/master)
|
10
10
|
[](https://codecov.io/gh/hanami/router)
|
11
11
|
[](https://depfu.com/github/hanami/router?project=Bundler)
|
@@ -22,7 +22,7 @@ Rack compatible, lightweight and fast HTTP Router for Ruby and [Hanami](http://h
|
|
22
22
|
|
23
23
|
## Rubies
|
24
24
|
|
25
|
-
__Hanami::Router__ supports Ruby (MRI) 2.
|
25
|
+
__Hanami::Router__ supports Ruby (MRI) 2.5+
|
26
26
|
|
27
27
|
|
28
28
|
## Installation
|
@@ -47,14 +47,23 @@ $ gem install hanami-router
|
|
47
47
|
|
48
48
|
## Getting Started
|
49
49
|
|
50
|
+
Create a file named `config.ru`
|
51
|
+
|
50
52
|
```ruby
|
51
|
-
|
53
|
+
# frozen_string_literal: true
|
54
|
+
require "hanami/router"
|
52
55
|
|
53
56
|
app = Hanami::Router.new do
|
54
|
-
get
|
57
|
+
get "/", to: ->(env) { [200, {}, ["Welcome to Hanami!"]] }
|
55
58
|
end
|
56
59
|
|
57
|
-
|
60
|
+
run app
|
61
|
+
```
|
62
|
+
|
63
|
+
From the shell:
|
64
|
+
|
65
|
+
```shell
|
66
|
+
$ bundle exec rackup
|
58
67
|
```
|
59
68
|
|
60
69
|
## Usage
|
@@ -68,38 +77,38 @@ For the standalone usage, it supports neat features:
|
|
68
77
|
|
69
78
|
```ruby
|
70
79
|
Hanami::Router.new do
|
71
|
-
root to: ->(env) { [200, {}, [
|
72
|
-
get
|
73
|
-
get
|
74
|
-
get
|
75
|
-
get
|
76
|
-
get
|
80
|
+
root to: ->(env) { [200, {}, ["Hello"]] }
|
81
|
+
get "/lambda", to: ->(env) { [200, {}, ["World"]] }
|
82
|
+
get "/dashboard", to: Dashboard::Index
|
83
|
+
get "/rack-app", to: RackApp.new
|
84
|
+
get "/flowers", to: "flowers#index"
|
85
|
+
get "/flowers/:id", to: "flowers#show"
|
77
86
|
|
78
|
-
redirect
|
87
|
+
redirect "/legacy", to: "/"
|
79
88
|
|
80
|
-
mount Api::App, at:
|
89
|
+
mount Api::App, at: "/api"
|
81
90
|
|
82
|
-
|
83
|
-
get
|
91
|
+
prefix "admin" do
|
92
|
+
get "/users", to: Users::Index
|
84
93
|
end
|
85
94
|
|
86
|
-
resource
|
95
|
+
resource "identity" do
|
87
96
|
member do
|
88
|
-
get
|
97
|
+
get "/avatar"
|
89
98
|
end
|
90
99
|
|
91
100
|
collection do
|
92
|
-
get
|
101
|
+
get "/api_keys"
|
93
102
|
end
|
94
103
|
end
|
95
104
|
|
96
|
-
resources
|
105
|
+
resources "robots" do
|
97
106
|
member do
|
98
|
-
patch
|
107
|
+
patch "/activate"
|
99
108
|
end
|
100
109
|
|
101
110
|
collection do
|
102
|
-
get
|
111
|
+
get "/search"
|
103
112
|
end
|
104
113
|
end
|
105
114
|
end
|
@@ -110,8 +119,9 @@ end
|
|
110
119
|
### Fixed string matching:
|
111
120
|
|
112
121
|
```ruby
|
113
|
-
|
114
|
-
|
122
|
+
Hanami::Router.new do
|
123
|
+
get "/hanami", to: ->(env) { [200, {}, ["Hello from Hanami!"]] }
|
124
|
+
end
|
115
125
|
```
|
116
126
|
|
117
127
|
|
@@ -119,8 +129,9 @@ router.get '/hanami', to: ->(env) { [200, {}, ['Hello from Hanami!']] }
|
|
119
129
|
### String matching with variables:
|
120
130
|
|
121
131
|
```ruby
|
122
|
-
|
123
|
-
|
132
|
+
Hanami::Router.new do
|
133
|
+
get "/flowers/:id", to: ->(env) { [200, {}, ["Hello from Flower no. #{ env["router.params"][:id] }!"]] }
|
134
|
+
end
|
124
135
|
```
|
125
136
|
|
126
137
|
|
@@ -128,8 +139,9 @@ router.get '/flowers/:id', to: ->(env) { [200, {}, ["Hello from Flower no. #{ en
|
|
128
139
|
### Variables Constraints:
|
129
140
|
|
130
141
|
```ruby
|
131
|
-
|
132
|
-
|
142
|
+
Hanami::Router.new do
|
143
|
+
get "/flowers/:id", id: /\d+/, to: ->(env) { [200, {}, [":id must be a number!"]] }
|
144
|
+
end
|
133
145
|
```
|
134
146
|
|
135
147
|
|
@@ -137,8 +149,9 @@ router.get '/flowers/:id', id: /\d+/, to: ->(env) { [200, {}, [":id must be a nu
|
|
137
149
|
### String matching with globbing:
|
138
150
|
|
139
151
|
```ruby
|
140
|
-
|
141
|
-
|
152
|
+
Hanami::Router.new do
|
153
|
+
get "/*match", to: ->(env) { [200, {}, ["This is catch all: #{ env["router.params"].inspect }!"]] }
|
154
|
+
end
|
142
155
|
```
|
143
156
|
|
144
157
|
|
@@ -146,8 +159,9 @@ router.get '/*', to: ->(env) { [200, {}, ["This is catch all: #{ env['router.par
|
|
146
159
|
### String matching with optional tokens:
|
147
160
|
|
148
161
|
```ruby
|
149
|
-
|
150
|
-
|
162
|
+
Hanami::Router.new do
|
163
|
+
get "/hanami(.:format)" to: ->(env) { [200, {}, ["You"ve requested #{ env["router.params"][:format] }!"]] }
|
164
|
+
end
|
151
165
|
```
|
152
166
|
|
153
167
|
|
@@ -155,15 +169,17 @@ router.get '/hanami(.:format)' to: ->(env) { [200, {}, ["You've requested #{ env
|
|
155
169
|
### Support for the most common HTTP methods:
|
156
170
|
|
157
171
|
```ruby
|
158
|
-
|
159
|
-
endpoint = ->(env) { [200, {}, ['Hello from Hanami!']] }
|
172
|
+
endpoint = ->(env) { [200, {}, ["Hello from Hanami!"]] }
|
160
173
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
174
|
+
Hanami::Router.new do
|
175
|
+
get "/hanami", to: endpoint
|
176
|
+
post "/hanami", to: endpoint
|
177
|
+
put "/hanami", to: endpoint
|
178
|
+
patch "/hanami", to: endpoint
|
179
|
+
delete "/hanami", to: endpoint
|
180
|
+
trace "/hanami", to: endpoint
|
181
|
+
options "/hanami", to: endpoint
|
182
|
+
end
|
167
183
|
```
|
168
184
|
|
169
185
|
|
@@ -171,8 +187,9 @@ router.trace '/hanami', to: endpoint
|
|
171
187
|
### Root:
|
172
188
|
|
173
189
|
```ruby
|
174
|
-
|
175
|
-
|
190
|
+
Hanami::Router.new do
|
191
|
+
root to: ->(env) { [200, {}, ["Hello from Hanami!"]] }
|
192
|
+
end
|
176
193
|
```
|
177
194
|
|
178
195
|
|
@@ -180,9 +197,10 @@ router.root to: ->(env) { [200, {}, ['Hello from Hanami!']] }
|
|
180
197
|
### Redirect:
|
181
198
|
|
182
199
|
```ruby
|
183
|
-
|
184
|
-
|
185
|
-
|
200
|
+
Hanami::Router.new do
|
201
|
+
get "/redirect_destination", to: ->(env) { [200, {}, ["Redirect destination!"]] }
|
202
|
+
redirect "/legacy", to: "/redirect_destination"
|
203
|
+
end
|
186
204
|
```
|
187
205
|
|
188
206
|
|
@@ -190,8 +208,9 @@ router.redirect '/legacy', to: '/redirect_destination'
|
|
190
208
|
### Named routes:
|
191
209
|
|
192
210
|
```ruby
|
193
|
-
router = Hanami::Router.new(scheme:
|
194
|
-
|
211
|
+
router = Hanami::Router.new(scheme: "https", host: "hanamirb.org") do
|
212
|
+
get "/hanami", to: ->(env) { [200, {}, ["Hello from Hanami!"]] }, as: :hanami
|
213
|
+
end
|
195
214
|
|
196
215
|
router.path(:hanami) # => "/hanami"
|
197
216
|
router.url(:hanami) # => "https://hanamirb.org/hanami"
|
@@ -199,13 +218,14 @@ router.url(:hanami) # => "https://hanamirb.org/hanami"
|
|
199
218
|
|
200
219
|
|
201
220
|
|
202
|
-
###
|
221
|
+
### Prefixed routes:
|
203
222
|
|
204
223
|
```ruby
|
205
|
-
router = Hanami::Router.new
|
206
|
-
|
207
|
-
|
208
|
-
|
224
|
+
router = Hanami::Router.new do
|
225
|
+
prefix "animals" do
|
226
|
+
prefix "mammals" do
|
227
|
+
get "/cats", to: ->(env) { [200, {}, ["Meow!"]] }, as: :cats
|
228
|
+
end
|
209
229
|
end
|
210
230
|
end
|
211
231
|
|
@@ -220,11 +240,11 @@ router.path(:animals_mammals_cats) # => "/animals/mammals/cats"
|
|
220
240
|
|
221
241
|
```ruby
|
222
242
|
Hanami::Router.new do
|
223
|
-
mount RackOne,
|
224
|
-
mount RackTwo,
|
225
|
-
mount RackThree.new,
|
226
|
-
mount ->(env) {[200, {}, [
|
227
|
-
mount
|
243
|
+
mount RackOne, at: "/rack1"
|
244
|
+
mount RackTwo, at: "/rack2"
|
245
|
+
mount RackThree.new, at: "/rack3"
|
246
|
+
mount ->(env) {[200, {}, ["Rack Four"]]}, at: "/rack4"
|
247
|
+
mount "dashboard#index", at: "/dashboard"
|
228
248
|
end
|
229
249
|
```
|
230
250
|
|
@@ -241,11 +261,12 @@ end
|
|
241
261
|
Everything that responds to `#call` is invoked as it is:
|
242
262
|
|
243
263
|
```ruby
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
264
|
+
Hanami::Router.new do
|
265
|
+
get "/hanami", to: ->(env) { [200, {}, ["Hello from Hanami!"]] }
|
266
|
+
get "/middleware", to: Middleware
|
267
|
+
get "/rack-app", to: RackApp.new
|
268
|
+
get "/method", to: ActionControllerSubclass.action(:new)
|
269
|
+
end
|
249
270
|
```
|
250
271
|
|
251
272
|
|
@@ -258,23 +279,25 @@ class RackApp
|
|
258
279
|
end
|
259
280
|
end
|
260
281
|
|
261
|
-
|
262
|
-
|
282
|
+
Hanami::Router.new do
|
283
|
+
get "/hanami", to: "rack_app" # it will map to RackApp.new
|
284
|
+
end
|
263
285
|
```
|
264
286
|
|
265
287
|
It also supports Controller + Action syntax:
|
266
288
|
|
267
289
|
```ruby
|
268
290
|
module Flowers
|
269
|
-
class Index
|
270
|
-
def
|
291
|
+
class Index < Hanami::Action
|
292
|
+
def handle(*)
|
271
293
|
# ...
|
272
294
|
end
|
273
295
|
end
|
274
296
|
end
|
275
297
|
|
276
|
-
|
277
|
-
|
298
|
+
Hanami::Router.new do
|
299
|
+
get "/flowers", to: "flowers#index" # it will map to Flowers::Index.new
|
300
|
+
end
|
278
301
|
```
|
279
302
|
|
280
303
|
|
@@ -283,7 +306,7 @@ router.get '/flowers', to: 'flowers#index' # it will map to Flowers::Index.new
|
|
283
306
|
|
284
307
|
```ruby
|
285
308
|
router = Hanami::Router.new
|
286
|
-
router.call(Rack::MockRequest.env_for(
|
309
|
+
router.call(Rack::MockRequest.env_for("/unknown")).status # => 404
|
287
310
|
```
|
288
311
|
|
289
312
|
### Controllers:
|
@@ -293,7 +316,7 @@ It allows to declare an action as an endpoint, with a special syntax: `<controll
|
|
293
316
|
|
294
317
|
```ruby
|
295
318
|
Hanami::Router.new do
|
296
|
-
get
|
319
|
+
get "/", to: "welcome#index"
|
297
320
|
end
|
298
321
|
```
|
299
322
|
|
@@ -310,7 +333,7 @@ controllers are available under `Bookshelf::Controllers`.
|
|
310
333
|
|
311
334
|
```ruby
|
312
335
|
Hanami::Router.new(namespace: Bookshelf::Controllers) do
|
313
|
-
get
|
336
|
+
get "/", to: "welcome#index"
|
314
337
|
end
|
315
338
|
```
|
316
339
|
|
@@ -319,8 +342,9 @@ In the example above, the router will look for the `Bookshelf::Controllers::Welc
|
|
319
342
|
### RESTful Resource:
|
320
343
|
|
321
344
|
```ruby
|
322
|
-
|
323
|
-
|
345
|
+
Hanami::Router.new do
|
346
|
+
resource "identity"
|
347
|
+
end
|
324
348
|
```
|
325
349
|
|
326
350
|
It will map:
|
@@ -380,41 +404,46 @@ It will map:
|
|
380
404
|
If you don't need all the default endpoints, just do:
|
381
405
|
|
382
406
|
```ruby
|
383
|
-
|
384
|
-
|
407
|
+
Hanami::Router.new do
|
408
|
+
resource "identity", only: [:edit, :update]
|
409
|
+
end
|
385
410
|
|
386
411
|
#### which is equivalent to:
|
387
412
|
|
388
|
-
|
413
|
+
Hanami::Router.new do
|
414
|
+
resource "identity", except: [:show, :new, :create, :destroy]
|
415
|
+
end
|
389
416
|
```
|
390
417
|
|
391
418
|
|
392
419
|
If you need extra endpoints:
|
393
420
|
|
394
421
|
```ruby
|
395
|
-
router = Hanami::Router.new
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
422
|
+
router = Hanami::Router.new do
|
423
|
+
resource "identity" do
|
424
|
+
member do
|
425
|
+
get "avatar" # maps to Identity::Avatar
|
426
|
+
end
|
400
427
|
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
end
|
428
|
+
collection do
|
429
|
+
get "authorizations" # maps to Identity::Authorizations
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|
405
433
|
|
406
|
-
router.path(:avatar_identity) # => /identity/avatar
|
407
|
-
router.path(:authorizations_identity) # => /identity/authorizations
|
434
|
+
router.path(:avatar_identity) # => "/identity/avatar"
|
435
|
+
router.path(:authorizations_identity) # => "/identity/authorizations"
|
408
436
|
```
|
409
437
|
|
410
438
|
|
411
439
|
Configure controller:
|
412
440
|
|
413
441
|
```ruby
|
414
|
-
router = Hanami::Router.new
|
415
|
-
|
442
|
+
router = Hanami::Router.new do
|
443
|
+
resource "profile", controller: "identity"
|
444
|
+
end
|
416
445
|
|
417
|
-
router.path(:profile) # => /profile # Will route to Identity::Show
|
446
|
+
router.path(:profile) # => "/profile" # Will route to Identity::Show
|
418
447
|
```
|
419
448
|
|
420
449
|
#### Nested Resources
|
@@ -422,20 +451,21 @@ router.path(:profile) # => /profile # Will route to Identity::Show
|
|
422
451
|
We can nest resource(s):
|
423
452
|
|
424
453
|
```ruby
|
425
|
-
router = Hanami::Router.new
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
end
|
454
|
+
router = Hanami::Router.new do
|
455
|
+
resource :identity do
|
456
|
+
resource :avatar
|
457
|
+
resources :api_keys
|
458
|
+
end
|
459
|
+
end
|
430
460
|
|
431
|
-
router.path(:identity_avatar) # => /identity/avatar
|
432
|
-
router.path(:new_identity_avatar) # => /identity/avatar/new
|
433
|
-
router.path(:edit_identity_avatar) # => /identity/avatar/new
|
461
|
+
router.path(:identity_avatar) # => "/identity/avatar"
|
462
|
+
router.path(:new_identity_avatar) # => "/identity/avatar/new"
|
463
|
+
router.path(:edit_identity_avatar) # => "/identity/avatar/new"
|
434
464
|
|
435
|
-
router.path(:identity_api_keys) # => /identity/api_keys
|
436
|
-
router.path(:identity_api_key, id: 1) # => /identity/api_keys/:id
|
437
|
-
router.path(:new_identity_api_key) # => /identity/api_keys/new
|
438
|
-
router.path(:edit_identity_api_key, id: 1) # => /identity/api_keys/:id/edit
|
465
|
+
router.path(:identity_api_keys) # => "/identity/api_keys"
|
466
|
+
router.path(:identity_api_key, id: 1) # => "/identity/api_keys/:id"
|
467
|
+
router.path(:new_identity_api_key) # => "/identity/api_keys/new"
|
468
|
+
router.path(:edit_identity_api_key, id: 1) # => "/identity/api_keys/:id/edit"
|
439
469
|
```
|
440
470
|
|
441
471
|
|
@@ -443,8 +473,9 @@ router.path(:edit_identity_api_key, id: 1) # => /identity/api_keys/:id/edit
|
|
443
473
|
### RESTful Resources:
|
444
474
|
|
445
475
|
```ruby
|
446
|
-
|
447
|
-
|
476
|
+
Hanami::Router.new do
|
477
|
+
resources "flowers"
|
478
|
+
end
|
448
479
|
```
|
449
480
|
|
450
481
|
It will map:
|
@@ -510,9 +541,9 @@ It will map:
|
|
510
541
|
|
511
542
|
|
512
543
|
```ruby
|
513
|
-
router.path(:flowers) # => /flowers
|
514
|
-
router.path(:flower, id: 23) # => /flowers/23
|
515
|
-
router.path(:edit_flower, id: 23) # => /flowers/23/edit
|
544
|
+
router.path(:flowers) # => "/flowers"
|
545
|
+
router.path(:flower, id: 23) # => "/flowers/23"
|
546
|
+
router.path(:edit_flower, id: 23) # => "/flowers/23/edit"
|
516
547
|
```
|
517
548
|
|
518
549
|
|
@@ -520,41 +551,46 @@ router.path(:edit_flower, id: 23) # => /flowers/23/edit
|
|
520
551
|
If you don't need all the default endpoints, just do:
|
521
552
|
|
522
553
|
```ruby
|
523
|
-
|
524
|
-
|
554
|
+
Hanami::Router.new do
|
555
|
+
resources "flowers", only: [:new, :create, :show]
|
556
|
+
end
|
525
557
|
|
526
558
|
#### which is equivalent to:
|
527
559
|
|
528
|
-
|
560
|
+
Hanami::Router.new do
|
561
|
+
resources "flowers", except: [:index, :edit, :update, :destroy]
|
562
|
+
end
|
529
563
|
```
|
530
564
|
|
531
565
|
|
532
566
|
If you need extra endpoints:
|
533
567
|
|
534
568
|
```ruby
|
535
|
-
router = Hanami::Router.new
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
569
|
+
router = Hanami::Router.new do
|
570
|
+
resources "flowers" do
|
571
|
+
member do
|
572
|
+
get "toggle" # maps to Flowers::Toggle
|
573
|
+
end
|
540
574
|
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
end
|
575
|
+
collection do
|
576
|
+
get "search" # maps to Flowers::Search
|
577
|
+
end
|
578
|
+
end
|
579
|
+
end
|
545
580
|
|
546
|
-
router.path(:toggle_flower, id: 23)
|
547
|
-
router.path(:search_flowers)
|
581
|
+
router.path(:toggle_flower, id: 23) # => "/flowers/23/toggle"
|
582
|
+
router.path(:search_flowers) # => "/flowers/search"
|
548
583
|
```
|
549
584
|
|
550
585
|
|
551
586
|
Configure controller:
|
552
587
|
|
553
588
|
```ruby
|
554
|
-
router = Hanami::Router.new
|
555
|
-
|
589
|
+
router = Hanami::Router.new do
|
590
|
+
resources "blossoms", controller: "flowers"
|
591
|
+
end
|
556
592
|
|
557
|
-
router.path(:blossom, id: 23) # => /blossoms/23 # Will route to Flowers::Show
|
593
|
+
router.path(:blossom, id: 23) # => "/blossoms/23" # Will route to Flowers::Show
|
558
594
|
```
|
559
595
|
|
560
596
|
#### Nested Resources
|
@@ -562,20 +598,21 @@ router.path(:blossom, id: 23) # => /blossoms/23 # Will route to Flowers::Show
|
|
562
598
|
We can nest resource(s):
|
563
599
|
|
564
600
|
```ruby
|
565
|
-
router = Hanami::Router.new
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
end
|
601
|
+
router = Hanami::Router.new do
|
602
|
+
resources :users do
|
603
|
+
resource :avatar
|
604
|
+
resources :favorites
|
605
|
+
end
|
606
|
+
end
|
570
607
|
|
571
|
-
router.path(:user_avatar, user_id: 1) # => /users/1/avatar
|
572
|
-
router.path(:new_user_avatar, user_id: 1) # => /users/1/avatar/new
|
573
|
-
router.path(:edit_user_avatar, user_id: 1) # => /users/1/avatar/edit
|
608
|
+
router.path(:user_avatar, user_id: 1) # => "/users/1/avatar"
|
609
|
+
router.path(:new_user_avatar, user_id: 1) # => "/users/1/avatar/new"
|
610
|
+
router.path(:edit_user_avatar, user_id: 1) # => "/users/1/avatar/edit"
|
574
611
|
|
575
|
-
router.path(:user_favorites, user_id: 1) # => /users/1/favorites
|
576
|
-
router.path(:user_favorite, user_id: 1, id: 2) # => /users/1/favorites/2
|
577
|
-
router.path(:new_user_favorites, user_id: 1) # => /users/1/favorites/new
|
578
|
-
router.path(:edit_user_favorites, user_id: 1, id: 2) # => /users/1/favorites/2/edit
|
612
|
+
router.path(:user_favorites, user_id: 1) # => "/users/1/favorites"
|
613
|
+
router.path(:user_favorite, user_id: 1, id: 2) # => "/users/1/favorites/2"
|
614
|
+
router.path(:new_user_favorites, user_id: 1) # => "/users/1/favorites/new"
|
615
|
+
router.path(:edit_user_favorites, user_id: 1, id: 2) # => "/users/1/favorites/2/edit"
|
579
616
|
```
|
580
617
|
|
581
618
|
### Body Parsers
|
@@ -593,11 +630,13 @@ It comes with a built-in JSON parser and allows to pass custom parsers.
|
|
593
630
|
#### JSON Parsing
|
594
631
|
|
595
632
|
```ruby
|
596
|
-
|
597
|
-
|
633
|
+
# frozen_string_literal: true
|
634
|
+
|
635
|
+
require "hanami/router"
|
636
|
+
require "hanami/middleware/body_parser"
|
598
637
|
|
599
638
|
app = Hanami::Router.new do
|
600
|
-
patch
|
639
|
+
patch "/books/:id", to: ->(env) { [200, {}, [env["router.params"].inspect]] }
|
601
640
|
end
|
602
641
|
|
603
642
|
use Hanami::Middleware::BodyParser, :json
|
@@ -627,13 +666,15 @@ If you want to use a different JSON backend, include `multi_json` in your `Gemfi
|
|
627
666
|
#### Custom Parsers
|
628
667
|
|
629
668
|
```ruby
|
630
|
-
|
631
|
-
|
669
|
+
# frozen_string_literal: true
|
670
|
+
|
671
|
+
require "hanami/router"
|
672
|
+
require "hanami/middleware/body_parser"
|
632
673
|
|
633
|
-
# See Hanami::
|
634
|
-
class XmlParser < Hanami::
|
674
|
+
# See Hanami::Middleware::BodyParser::Parser
|
675
|
+
class XmlParser < Hanami::Middleware::BodyParser::Parser
|
635
676
|
def mime_types
|
636
|
-
[
|
677
|
+
["application/xml", "text/xml"]
|
637
678
|
end
|
638
679
|
|
639
680
|
# Parse body and return a Hash
|
@@ -645,7 +686,7 @@ class XmlParser < Hanami::Routing::Parsing::Parser
|
|
645
686
|
end
|
646
687
|
|
647
688
|
app = Hanami::Router.new do
|
648
|
-
patch
|
689
|
+
patch "/authors/:id", to: ->(env) { [200, {}, [env["router.params"].inspect]] }
|
649
690
|
end
|
650
691
|
|
651
692
|
use Hanami::Middleware::BodyParser, XmlParser
|
@@ -665,13 +706,15 @@ curl http://localhost:2300/authors/1 \
|
|
665
706
|
## Testing
|
666
707
|
|
667
708
|
```ruby
|
668
|
-
|
709
|
+
# frozen_string_literal: true
|
710
|
+
|
711
|
+
require "hanami/router"
|
669
712
|
|
670
713
|
router = Hanami::Router.new do
|
671
|
-
get
|
714
|
+
get "/books/:id", to: "books#show", as: :book
|
672
715
|
end
|
673
716
|
|
674
|
-
route = router.recognize(
|
717
|
+
route = router.recognize("/books/23")
|
675
718
|
route.verb # "GET"
|
676
719
|
route.action # => "books#show"
|
677
720
|
route.params # => {:id=>"23"}
|
@@ -683,7 +726,7 @@ route.action # => "books#show"
|
|
683
726
|
route.params # => {:id=>"23"}
|
684
727
|
route.routable? # => true
|
685
728
|
|
686
|
-
route = router.recognize(
|
729
|
+
route = router.recognize("/books/23", method: :post)
|
687
730
|
route.verb # "POST"
|
688
731
|
route.routable? # => false
|
689
732
|
```
|
@@ -700,13 +743,8 @@ __Hanami::Router__ uses [Semantic Versioning 2.0.0](http://semver.org)
|
|
700
743
|
4. Push to the branch (`git push origin my-new-feature`)
|
701
744
|
5. Create new Pull Request
|
702
745
|
|
703
|
-
## Acknowledgements
|
704
|
-
|
705
|
-
Thanks to Joshua Hull ([@joshbuddy](https://github.com/joshbuddy)) for his
|
706
|
-
[http_router](http://rubygems.org/gems/http_router).
|
707
|
-
|
708
746
|
## Copyright
|
709
747
|
|
710
|
-
Copyright © 2014-
|
748
|
+
Copyright © 2014-2019 Luca Guidi – Released under MIT License
|
711
749
|
|
712
750
|
This project was formerly known as Lotus (`lotus-router`).
|