hanami / router Goto Github PK
View Code? Open in Web Editor NEWRuby/Rack HTTP router
Home Page: http://hanamirb.org
License: MIT License
Ruby/Rack HTTP router
Home Page: http://hanamirb.org
License: MIT License
I'm trying to execute code from your last post.
require 'rubygems'
require 'bundler/setup'
require 'lotus/router'
Application = Rack::Builder.new do
app = Lotus::Router.new do
get '/' do
[200, {}, ['Hello, World!']]
end
end
run app
end.to_app
but it doesn't work with this trace:
2.0.0-p247/lib/ruby/gems/2.0.0/gems/lotus-router-0.1.0/lib/lotus/routing/http_router.rb:119:in `add_with_request_method': undefined method `generate' for #<HttpRouter::Route:0x007fa5f353c6b8> (NoMethodError)
2.0.0-p247/lib/ruby/gems/2.0.0/gems/http_router-0.10.2/lib/http_router.rb:80:in `get'
When I setup Sidekiq with Hanami I ran into an issue when mounting the Sidekiq web interface within an applications route or the container. All URLs for links and assets in Sidekiq were broken because they pointed to the root of my Hanami application even if I mounted it at /sidekiq
for example.
Turns out Sidekiq uses SCRIPT_NAME
to build its URLs and it seems that Hanami only sets it for Hanami apps and not Rack apps in general.
Reading the Rack specification I think Hanami should set SCRIPT_NAME
accordingly. Rack::URLMap
does it too for example.
The initial portion of the request URL's “path” that corresponds to the application object, so that the application knows its virtual “location”. This may be an empty string, if the application corresponds to the “root” of the server.
What do you think?
So Lotus router lets you do this, and doesn't complain:
router = Lotus::Router.new do
resources :groups do
member do
resources :activities
end
end
end
But if we do puts router.inspector
...
/groups/:id/activities GET, HEAD /groups/:id/activities /groups/:id/activities::Index
new_/groups/:id/activities GET, HEAD /groups/:id/activities/new /groups/:id/activities::New
/groups/:id/activities POST /groups/:id/activities /groups/:id/activities::Create
/groups/:id/activities GET, HEAD /groups/:id/activities/:id /groups/:id/activities::Show
edit_/groups/:id/activities GET, HEAD /groups/:id/activities/:id/edit /groups/:id/activities::Edit
/groups/:id/activities PATCH /groups/:id/activities/:id /groups/:id/activities::Update
/groups/:id/activities DELETE /groups/:id/activities/:id /groups/:id/activities::Destroy
groups GET, HEAD /groups Groups::Index
new_groups GET, HEAD /groups/new Groups::New
groups POST /groups Groups::Create
groups GET, HEAD /groups/:id Groups::Show
edit_groups GET, HEAD /groups/:id/edit Groups::Edit
groups PATCH /groups/:id Groups::Update
groups DELETE /groups/:id Groups::Destroy
...it gives us complete nonsense.
Same thing for:
router = Lotus::Router.new do
resources :users do
member do
resource :avatar
end
end
end
new_/users/:id/avatar GET, HEAD /users/:id/avatar/new /users/:id/avatar::New
/users/:id/avatar POST /users/:id/avatar /users/:id/avatar::Create
/users/:id/avatar GET, HEAD /users/:id/avatar /users/:id/avatar::Show
edit_/users/:id/avatar GET, HEAD /users/:id/avatar/edit /users/:id/avatar::Edit
/users/:id/avatar PATCH /users/:id/avatar /users/:id/avatar::Update
/users/:id/avatar DELETE /users/:id/avatar /users/:id/avatar::Destroy
users GET, HEAD /users Users::Index
new_users GET, HEAD /users/new Users::New
users POST /users Users::Create
users GET, HEAD /users/:id Users::Show
edit_users GET, HEAD /users/:id/edit Users::Edit
users PATCH /users/:id Users::Update
users DELETE /users/:id Users::Destroy
So from here I see two options:
If nested resources were explicitly disallowed, I think there'd be some utility from the users/:id/avatar
case that would be lost. As such, I think option two is probably the better option.
If option two works, I'd be happy to put together a pull request (though it may take me a while, since it looks like it would be a significant set of changes to the internals here).
When calling router.url
when running on a non-standard port, the port number is not included in the URL.
Example Code
require 'lotus/router'
app = Lotus::Router.new do
get '/', to: ->(env) { [200, {}, [app.url(:home)]] }, as: :home
end
Rack::Server.start app: app, Port: 2300
If you then visit http://localhost:2300/
it returns http://localhost/
It would be nice if Lotus router checked the port against the protocol and included the port in the URL if it was not the standard for the protocol.
Hey all 👍
Just picked up this one today..
when doing something like this in the routes.rb
file:
resources :horses
will result in this:
hors GET, HEAD /horses Routertest::Controllers::Horses::Index
new_hors GET, HEAD /horses/new Routertest::Controllers::Horses::New
hors POST /horses Routertest::Controllers::Horses::Create
hors GET, HEAD /horses/:id Routertest::Controllers::Horses::Show
edit_hors GET, HEAD /horses/:id/edit Routertest::Controllers::Horses::Edit
hors PATCH /horses/:id Routertest::Controllers::Horses::Update
hors DELETE /horses/:id Routertest::Controllers::Horses::Destroy
Thinking it was something related to it ending in 'es' (which i'm still not 100% convinced it isn't) i tried other words such as :moustaches
and :stones
and they worked fine. Intriguing huh? ;-)
This is on 0.5.0 and has been around for quite sometime as far as I can tell.. I know that :horses
is not the most common name in the world for a resource and this may very well be a super-duper edge case.. But it shouldn't happen anyways ;-)
I'll try to look into it in the next few days and report back or send PR this way.
Cheers
Say we have an app called awards within a container arch mounted at: '/awards'
If we add resources :awards
to routes
when running lotus routes
the inspector does not output the right thing.
awards GET, HEAD /awards Awards::Controllers::Awards::Index
new_award GET, HEAD /awards/awards/new Awards::Controllers::Awards::New
awards POST /awards Awards::Controllers::Awards::Create
award GET, HEAD /awards/awards/:id Awards::Controllers::Awards::Show
edit_award GET, HEAD /awards/awards/:id/edit Awards::Controllers::Awards::Edit
award PATCH /awards/awards/:id Awards::Controllers::Awards::Update
award DELETE /awards/awards/:id Awards::Controllers::Awards::Destroy
when it should be:
awards GET, HEAD /awards/awards Awards::Controllers::Awards::Index
new_award GET, HEAD /awards/awards/new Awards::Controllers::Awards::New
awards POST /awards/awards Awards::Controllers::Awards::Create
award GET, HEAD /awards/awards/:id Awards::Controllers::Awards::Show
edit_award GET, HEAD /awards/awards/:id/edit Awards::Controllers::Awards::Edit
award PATCH /awards/awards/:id Awards::Controllers::Awards::Update
award DELETE /awards/awards/:id Awards::Controllers::Awards::Destroy
Here's a setup with the issue and a failing test.
https://github.com/theocodes/routertest
Note: Using master
Thanks
I don't know if it's expected to behave like this, but the following script
require 'rubygems'
require 'lotus/router'
Lotus::Router.draw do
get '/', to: ->(env) { [200, {}, ['Welcome to Lotus::Router!']] }
end
fails because it can't load lotus/utils/string. Nowhere in the gemspec router depends from utils though.
Hi,
Since I've upgraded from Lotus 0.5.0 to Hanami 0.7.0 I'm getting the failure below for my feature tests:
Expected: "/customers/4/edit"
Actual: "//customers/4/edit"
I haven't changed my tests, I have the same routes setup and under Lotus 0.5.0 I still don't get these failures.
This is the feature test I have:
it 'updates customer data' do
create_action.call(create_params)
create_action.customer.id.wont_be_nil
visit "/customers/#{customer_id}/edit"
current_path.must_equal("/customers/#{customer_id}/edit")
fill_in('customer[vat_id]', with: var)
click_button('Update customer')
current_path.must_equal("/customers/#{customer_id}")
assert page.has_content?(var), "The updated customer vat id should be #{var}."
end
Here are my routes:
resources :projects
resources :persons
resources :languages
resources :customers
resources :services
get '/', to: 'home#index', as: :home
get '/configuration', to: 'configuration#index', as: :configuration
The current_path from the above block as printed in the terminal is
//customers/38/edit.
When I go through the app manually and update some data, everything works. I'm going through the code if I've missed something when upgrading, but I can't find anything.
regards,
Seba
When running tests in router and in Hanami, there are two warnings for assigned but unused variables.
/.rvm/gems/ruby-2.3.1/gems/http_router-0.11.2/lib/http_router/generator.rb:58: warning: assigned but unused variable - generator
and
/.rvm/gems/ruby-2.3.1/gems/http_router-0.11.2/lib/http_router/route_helper.rb:99: warning: assigned but unused variable - params
Could definitely easily fix this if there is no reasoning for having the variables. Let me know!
$ lotus new force_ssl_test
# config/routes.rb
get '/', to: ->(env) { [200, {}, ['OK']] }
# apps/web/application.rb
force_ssl true
$ bundle exec rackup
[2015-11-04 17:54:21] INFO WEBrick 1.3.1
[2015-11-04 17:54:21] INFO ruby 2.2.3 (2015-08-18) [x86_64-darwin15]
[2015-11-04 17:54:21] INFO WEBrick::HTTPServer#start: pid=70829 port=9292
::1 - - [04/Nov/2015:17:54:31 +0300] "GET / HTTP/1.1" 301 - 0.0048
[2015-11-04 17:54:31] ERROR NoMethodError: undefined method `each' for "":String
/Users/vlazar/.rvm/gems/ruby-2.2.3@force_ssl_test/gems/rack-1.6.4/lib/rack/body_proxy.rb:31:in `each'
/Users/vlazar/.rvm/gems/ruby-2.2.3@force_ssl_test/gems/rack-1.6.4/lib/rack/lint.rb:708:in `each'
/Users/vlazar/.rvm/gems/ruby-2.2.3@force_ssl_test/gems/rack-1.6.4/lib/rack/body_proxy.rb:31:in `each'
/Users/vlazar/.rvm/gems/ruby-2.2.3@force_ssl_test/gems/rack-1.6.4/lib/rack/chunked.rb:23:in `each'
/Users/vlazar/.rvm/gems/ruby-2.2.3@force_ssl_test/gems/rack-1.6.4/lib/rack/handler/webrick.rb:112:in `service'
/Users/vlazar/.rvm/rubies/ruby-2.2.3/lib/ruby/2.2.0/webrick/httpserver.rb:138:in `service'
/Users/vlazar/.rvm/rubies/ruby-2.2.3/lib/ruby/2.2.0/webrick/httpserver.rb:94:in `run'
/Users/vlazar/.rvm/rubies/ruby-2.2.3/lib/ruby/2.2.0/webrick/server.rb:294:in `block in start_thread'
$ http http://localhost:9292/
HTTP/1.1 500 Internal Server Error
Connection: close
Content-Type: text/html; charset=ISO-8859-1
Date: Wed, 04 Nov 2015 14:04:16 GMT
Location: https://localhost:2300/
Server: WEBrick/1.3.1 (Ruby/2.2.3/2015-08-18)
Transfer-Encoding: chunked
http: error: ChunkedEncodingError: ('Connection broken: IncompleteRead(0 bytes read)', IncompleteRead(0 bytes read))
I was able to reproduce the error here.
1) Error:
Body parsing#test_0002_is successful (JSON) with an array:
TypeError: no implicit conversion of Array into Hash
/Users/weppos/Mirrors/hanami--router/lib/hanami/routing/parsers.rb:49:in `merge!'
/Users/weppos/Mirrors/hanami--router/lib/hanami/routing/parsers.rb:49:in `block in _redefine_call'
/Users/weppos/Mirrors/hanami--router/lib/hanami/routing/http_router.rb:135:in `raw_call'
/Users/weppos/.rvm/gems/ruby-2.3.0/gems/http_router-0.11.2/lib/http_router.rb:142:in `call'
/Users/weppos/Mirrors/hanami--router/lib/hanami/router.rb:931:in `call'
/Users/weppos/.rvm/gems/ruby-2.3.0/gems/rack-1.6.4/lib/rack/lint.rb:49:in `_call'
/Users/weppos/.rvm/gems/ruby-2.3.0/gems/rack-1.6.4/lib/rack/lint.rb:37:in `call'
/Users/weppos/.rvm/gems/ruby-2.3.0/gems/rack-1.6.4/lib/rack/mock.rb:74:in `request'
/Users/weppos/.rvm/gems/ruby-2.3.0/gems/rack-1.6.4/lib/rack/mock.rb:59:in `patch'
/Users/weppos/Mirrors/hanami--router/test/integration/body_parsing_test.rb:27:in `block (2 levels) in <top (required)>'
it 'is successful (JSON) with an array' do
body = StringIO.new( %(["alpha", "beta"]).encode(Encoding::ASCII_8BIT) )
response = @app.patch('/books/23', 'CONTENT_TYPE' => 'application/json', 'rack.input' => body, lint: true)
response.status.must_equal 200
response.body.must_equal %(["alpha", "beta"])
end
This is an example of a request
$ curl http://example.com/path -X POST -d '["alpha", "beta"]' -H "Content-Type: application/json"
Of course, the tricky part is how this case should be handled in the params
as it implies the params
can also be an Array
, instead of always a Hash
.
It's possible to use a constant key, for example _
, which is also the same approach Rails is following.
{"_json"=>["ns1.example.com", "ns2.example.com"], "controller"=>"something", "action"=>"create", "something"=>{"_json"=>["ns1.example.com", "ns2.example.com"]}}
In this case, Rails uses the _json
key.
FYI, Lotus crashes at this point, because merge!
can't handle an input which is not a Hash
.
env[ROUTER_PARAMS].merge!(
@parsers[
media_type(env)
].parse(body)
)
Hanami::Routing::HttpRouter#rewrite_partial_path_info
is using URI.escape
, which is deprecated. We need to update the implementation of that method.
When body parsers are activated, they "merge" the params inside the payload of a non-GET request with the params passed in the URI.
The problem with the actual implementation is that the params from the payload have higher priority than the ones interpolated from the URI.
Example: Given the following route:
PATCH /books/:id
If we pass :id
in the payload of the PATCH request, it takes precedence.
curl -H "Content-Type: application/json" \
-H "Accept: application/json" \
-X PATCH \
-d '{"id":999}' \
https://api.example.com/books/1
In the example above, params[:id]
will equal to 999
instead of 1
, which is wrong and confusing.
After updating Lotus to 0.3.1 (lotus-router to 0.4.0) I am getting Lotus::Routing::InvalidRouteException: HttpRouter::TooManyParametersException in all my routes
This is the configuration of my current routes:
Introduce a new option for Lotus::Router
constructor: force_ssl
. It accepts a boolean. When it's true and the router receives a non-encrypted request (http
), it redirects to the secure equivalent resource (https
). It should use a 301
HTTP status code.
I posted a question but do not have the 1500 reputation to create the tag... Here is my question: http://stackoverflow.com/questions/22367474/how-to-use-lotus-router-with-rackbuildermap
I like the idea of so for questions, but hopefully someone with 1500+ can create the tag!
1) API::V2 routing POST [REDACTED]
Failure/Error: router.__send__(:api_from_registry, actual.action) ==
NoMethodError:
undefined method `__getobj__' for nil:NilClass
# /Users/luca/.gem/ruby/2.3.1/gems/hanami-router-0.6.2/lib/hanami/routing/recognized_route.rb:143:in `destination'
# /Users/luca/.gem/ruby/2.3.1/gems/hanami-router-0.6.2/lib/hanami/routing/recognized_route.rb:104:in `action'
# [REDACTED]:318:in `block (2 levels) in <module:Matchers>'
# [REDACTED]:669:in `block (3 levels) in <top (required)>'
# /Users/luca/.gem/ruby/2.3.1/gems/bundler-1.12.5/lib/bundler/cli/exec.rb:63:in `load'
# /Users/luca/.gem/ruby/2.3.1/gems/bundler-1.12.5/lib/bundler/cli/exec.rb:63:in `kernel_load'
# /Users/luca/.gem/ruby/2.3.1/gems/bundler-1.12.5/lib/bundler/cli/exec.rb:24:in `run'
# /Users/luca/.gem/ruby/2.3.1/gems/bundler-1.12.5/lib/bundler/cli.rb:304:in `exec'
# /Users/luca/.gem/ruby/2.3.1/gems/bundler-1.12.5/lib/bundler/cli.rb:11:in `start'
# /Users/luca/.gem/ruby/2.3.1/gems/bundler-1.12.5/exe/bundle:27:in `block in <top (required)>'
# /Users/luca/.gem/ruby/2.3.1/gems/bundler-1.12.5/lib/bundler/friendly_errors.rb:98:in `with_friendly_errors'
# /Users/luca/.gem/ruby/2.3.1/gems/bundler-1.12.5/exe/bundle:19:in `<top (required)>'
Hi all,
My title is terrible, sorry, can't figure out how to name it, but anyway, here's the thing:
I'm currently switching an app from rails to hanami. No changes in urls are possible.
Urls are of the following form: (/:locale)/rest/of-the/url
, so, for example: /en/admin/users
would go to Admin::Users::Index with locale en in its params.
What I've tried so far:
mount Admin::Application, at: '(/:locale)/admin'
which kinda almost work, except that all urls generated are screwed up with a nasty (/:locale)
at the beginning (including asset urls)mount Admin::Application.new(locale: 'fr'), at: '/fr/admin'
just to see if it was possible... let's just say it's not...Questions:
Hi. When you plan make release with new changes? I really need some router functional in main lotus repo =) Maybe I can provide some help to do this?
I have Admin namespace for actions in my application.
namespace 'admin' do
get 'coupons', to: 'admin/coupons#index'
end
expected to open Web::Controllers::Admin::Coupons::Index
but fails with Lotus::Routing::EndpointNotFound: wrong constant name Admin/coupons
.
Rack::Utils::String#constantize
does not support namespaces like ActiveSupport do. Would it be right way to implement namespacing support in Rack::Utils?
I've been using Lotus::Router (with Lotus::Controller) in building an API, and I find the ability to specify JSON parsing via Lotus::Router.new parsers: [:json]
very convenient. However, the router responds with a very verbose message and stacktrace when a parsing error is encountered:
HTTP/1.1 500 Internal Server Error
Content-Length: 2372
Content-Type: text/plain
JSON::ParserError: 757: unexpected token at '{
"fruit": "Apple"
"vegetable": "Cabbage"
}
'
/Users/Erol/.gem/ruby/2.2.0/gems/json-1.8.2/lib/json/common.rb:155:in `parse'
/Users/Erol/.gem/ruby/2.2.0/gems/json-1.8.2/lib/json/common.rb:155:in `parse'
/Users/Erol/.gem/ruby/2.2.0/gems/lotus-router-0.2.1/lib/lotus/routing/parsing/json_parser.rb:12:in `parse'
/Users/Erol/.gem/ruby/2.2.0/gems/lotus-router-0.2.1/lib/lotus/routing/parsers.rb:52:in `block in _redefine_call'
/Users/Erol/.gem/ruby/2.2.0/gems/lotus-router-0.2.1/lib/lotus/routing/http_router.rb:112:in `raw_call'
/Users/Erol/.gem/ruby/2.2.0/gems/http_router-0.11.1/lib/http_router.rb:142:in `call'
/Users/Erol/.gem/ruby/2.2.0/gems/lotus-router-0.2.1/lib/lotus/router.rb:879:in `call'
/Users/Erol/.gem/ruby/2.2.0/gems/rack-1.6.0/lib/rack/session/abstract/id.rb:225:in `context'
/Users/Erol/.gem/ruby/2.2.0/gems/rack-1.6.0/lib/rack/session/abstract/id.rb:220:in `call'
/Users/Erol/.gem/ruby/2.2.0/gems/rack-1.6.0/lib/rack/lint.rb:49:in `_call'
/Users/Erol/.gem/ruby/2.2.0/gems/rack-1.6.0/lib/rack/lint.rb:37:in `call'
/Users/Erol/.gem/ruby/2.2.0/gems/rack-1.6.0/lib/rack/showexceptions.rb:24:in `call'
/Users/Erol/.gem/ruby/2.2.0/gems/puma-2.11.0/lib/puma/rack_patch.rb:13:in `call'
/Users/Erol/.gem/ruby/2.2.0/gems/shotgun-0.9.1/lib/shotgun/loader.rb:86:in `proceed_as_child'
/Users/Erol/.gem/ruby/2.2.0/gems/shotgun-0.9.1/lib/shotgun/loader.rb:31:in `call!'
/Users/Erol/.gem/ruby/2.2.0/gems/shotgun-0.9.1/lib/shotgun/loader.rb:18:in `call'
/Users/Erol/.gem/ruby/2.2.0/gems/shotgun-0.9.1/lib/shotgun/favicon.rb:12:in `call'
/Users/Erol/.gem/ruby/2.2.0/gems/rack-1.6.0/lib/rack/urlmap.rb:66:in `block in call'
/Users/Erol/.gem/ruby/2.2.0/gems/rack-1.6.0/lib/rack/urlmap.rb:50:in `each'
/Users/Erol/.gem/ruby/2.2.0/gems/rack-1.6.0/lib/rack/urlmap.rb:50:in `call'
/Users/Erol/.gem/ruby/2.2.0/gems/rack-1.6.0/lib/rack/builder.rb:153:in `call'
/Users/Erol/.gem/ruby/2.2.0/gems/puma-2.11.0/lib/puma/server.rb:507:in `handle_request'
/Users/Erol/.gem/ruby/2.2.0/gems/puma-2.11.0/lib/puma/server.rb:375:in `process_client'
/Users/Erol/.gem/ruby/2.2.0/gems/puma-2.11.0/lib/puma/server.rb:262:in `block in run'
/Users/Erol/.gem/ruby/2.2.0/gems/puma-2.11.0/lib/puma/thread_pool.rb:104:in `call'
/Users/Erol/.gem/ruby/2.2.0/gems/puma-2.11.0/lib/puma/thread_pool.rb:104:in `block in spawn_thread'
Is there a way to silence or customize the error response when running on production? I'm willing to submit a PR if there is no facility yet to do this and if you feel this is a worthy feature. :)
See this gist.
Going to /episodes/download_info
seems to be hitting the episodes show route with an id
of download_info
.
The following example shows a simple config about lotus router, two cases:
This scenario mount an app with it's routes
require 'lotus/router'
class AdminLotusApp
def call(env)
end
def routes
Lotus::Router.new do
get '/home', to: 'home#index', as: 'admin_home'
end
end
end
@router = Lotus::Router.new do
mount AdminLotusApp, at: '/admin'
end
puts @router.inspector
# => admin_home GET, HEAD /admin/home Home::Index
@router.path(:admin_home)
# => HttpRouter::InvalidRouteException: No route (path) could be generated for :admin_home
This scenario is the normal case.
require 'lotus/router'
@router = Lotus::Router.new do
get '/home', to: 'home#index', as: 'home'
end
puts @router.inspector
# => home GET, HEAD /home Home::Index
@router.path(:home) # => works
When I declare resources like: resources :prices
the result is:
price GET, HEAD /dashboard/prices Dashboard::Controllers::Prices::Index
new_price GET, HEAD /dashboard/prices/new Dashboard::Controllers::Prices::New
price POST /dashboard/prices Dashboard::Controllers::Prices::Create
price GET, HEAD /dashboard/prices/:id Dashboard::Controllers::Prices::Show
edit_price GET, HEAD /dashboard/prices/:id/edit Dashboard::Controllers::Prices::Edit
price PATCH /dashboard/prices/:id Dashboard::Controllers::Prices::Update
price DELETE /dashboard/prices/:id Dashboard::Controllers::Prices::Destroy
I expected get the price pluralized on Index
and Create
actions.
Researching about plurals in words ending up with ice I could not realized why such words are losing the last s
in hanami-router.
Is there any reason for it?
Note: I'm not an english lang expert grammatically talking ;).
When multiple applications are present in a Lotus project, the output of lotus routes
is cluttered because the lack of extra blank line between groups of routes:
Steps to reproduce:
➜ lotus new bookshelf && cd bookshelf && bundle
➜ bundle exec lotus generate app admin
➜ bundle exec lotus generate action web books#index --url=/books
➜ bundle exec lotus generate action admin users#index --url=/users
➜ bundle exec lotus routes
Name Method Path Action
GET, HEAD /admin/users Admin::Controllers::Users::Index
Name Method Path Action
GET, HEAD /books Web::Controllers::Books::Index
Expected would be:
➜ bundle exec lotus routes
Name Method Path Action
GET, HEAD /admin/users Admin::Controllers::Users::Index
Name Method Path Action
GET, HEAD /books Web::Controllers::Books::Index
Ref #78
/cc @davydovanton
Is there a technique I'm unaware of for injecting dependencies into the controllers. Or with lotus/lotus
I might want to inject dependencies into view classes as well, can't figure out how I would go about that either.
I was looking through endpoint_resolver.rb
and it occurred to me that with the way it makes instances of the action class, I don't have a clear way to inject dependencies into them. Maybe you know a way? Please tell me.
Let's say I have an action, and I want it to be set with an instance of the redcarpet markdown parser and not have to make an instance of it in line. (Because injecting dependencies makes things easier to test and more loosely coupled).
require 'redcarpet'
module Blog
module Controllers
module Posts
class Show
include Lotus::Action
expose :markup
attr_writer :markdown
def call(params)
contents = File.open("posts/#{params[:slug]}.md") { |f| f.read }
@markup = @markdown.render(contents)
end
end
end
end
With that markdown as a settable, easily mocked dependency this class is easier to test and has the added benefit of not being coupled to the HTML renderer, it could have been set with any type. As you can see the action below only renders HTML, but the one above doesn't have that constraint.
def call(params)
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML);
contents = File.open("posts/#{params[:slug]}.md") { |f| f.read }
@markup = markdown.render(contents)
end
Lotus::Router has a Lotus::Controller integration for controller/action naming.
If we define an endpoint with the 'welcome#index'
syntax, it creates the following pattern by default: Welcome(::Controller::|Controller::)Index
. With this in mind, it looks for Welcome::Controller::Index
or WelcomeController::Index
, otherwise it raises a NameError
for the missing constant.
In Lotus (lotus/lotus), we're encouraging controllers namespacing by default. In the case above default search pattern should be 'Controllers::Welcome::Index'
. The default Ruby namespace should still be Object
, so in case of standalone usage of Lotus::Router, that Controllers::Welcome::Index
naming structure is compatible with full stack Lotus applications.
Hi, I am trying to user your router in a stand alone app (without the Hanami framework) and I am wondering if there is any documentation around how to handle errors before the request gets to a controller. For instance, how should I handle parsing errors?
Lets say I have this router implementation:
$router = Hanami::Router.new(parsers: [:json]) do
patch '/books', to: ->(env) { [200, {},[env['router.params'].inspect]] }
end
And in my config.ru I have something like this:
map "/" do
run $router
end
If I pass invalid JSON to /books, a Hanami::Routing::Parsing::BodyParsingError will be raised. But, if I want to handle that in a custom way, how would I implement that?
Given a :patch
request to /myfoo/:id
with some data
{
_method: "PATCH",
foo: { bar: 'foobar' }
}
With params
validations
params do
param :foo do
param: :bar, type: String
end
end
Accessing the params
in a controller:
params[:foo] # {bar: 'foobar'}
params[:id] # nil
But router.params
does report
{:id=>"1"}
Adding
param :id`
[...]
Solves the problem. I don't think I should explicitly add router params to my form params validation.
First, thank you for this great framework.
The issue I have is when nesting resources, I can't restrict the routes available by using :only
resources :categories, only: :show do
member do
resources :posts, only: :show
end
end
I have the following output when running bundle exec lotus routes
:
/categories/:id/posts GET, HEAD /categories/:id/posts Web::Controllers::::Categories:::id::Posts::Index
new_/categories/:id/posts GET, HEAD /categories/:id/posts/new Web::Controllers::::Categories:::id::Posts::New
/categories/:id/posts POST /categories/:id/posts Web::Controllers::::Categories:::id::Posts::Create
/categories/:id/posts GET, HEAD /categories/:id/posts/:id Web::Controllers::::Categories:::id::Posts::Show
edit_/categories/:id/posts GET, HEAD /categories/:id/posts/:id/edit Web::Controllers::::Categories:::id::Posts::Edit
/categories/:id/posts PATCH /categories/:id/posts/:id Web::Controllers::::Categories:::id::Posts::Update
/categories/:id/posts DELETE /categories/:id/posts/:id Web::Controllers::::Categories:::id::Posts::Destroy
categories GET, HEAD /categories/:id Web::Controllers::Categories::Show
While I was expecting to only have this:
/categories/:id/posts GET, HEAD /categories/:id/posts/:id Web::Controllers::::Categories:::id::Posts::Show
categories GET, HEAD /categories/:id Web::Controllers::Categories::Show
How would lotus router handle routing based on domains and/or subdomains?
I want to be able to call a url like this:
and also
to be able to add relations to my post. In my use case it is possible to handle both, the comment and the tag routes in one controller/action. So, it would be great to have this as a optional dynamic part of the router.
Something like this:
resources :tags do
resources :relationships, url: "/relationships/:type"
end
I'm hoping to add or help add support to Hanami for resolving endpoints for dasherized routes in a manner consistent with underscored routes. That is:
# from this:
'test-resource' => Web::Controllers::Test::Resource
'test_resource' => Web::Controllers::TestResource
# to this:
'test-resource' => Web::Controllers::TestResource
'test_resource' => Web::Controllers::TestResource
I previously attempted this in hanami/utils#168 but it was rightly pointed out that my solution breaks the Ruby naming convention. @cllns suggested adding an option to the router to support this so that's what I've investigated next:
diff --git a/lib/hanami/routing/endpoint_resolver.rb b/lib/hanami/routing/endpoint_resolver.rb
index 50b8527..1923ded 100644
--- a/lib/hanami/routing/endpoint_resolver.rb
+++ b/lib/hanami/routing/endpoint_resolver.rb
@@ -98,10 +98,11 @@ module Hanami
# router.get('/', to: 'articles@show')
# # => Will look for: Articles::Show
def initialize(options = {})
- @endpoint_class = options[:endpoint] || Endpoint
- @namespace = options[:namespace] || Object
- @action_separator = options[:action_separator] || ACTION_SEPARATOR
- @pattern = options[:pattern] || NAMING_PATTERN
+ @endpoint_class = options[:endpoint] || Endpoint
+ @namespace = options[:namespace] || Object
+ @action_separator = options[:action_separator] || ACTION_SEPARATOR
+ @pattern = options[:pattern] || NAMING_PATTERN
+ @dasherized_routes = !!options[:dasherized_routes]
end
# Resolve the given set of HTTP verb, path, endpoint and options.
@@ -198,7 +199,8 @@ module Hanami
end
def classify(string)
- Utils::String.new(string).classify
+ to_classify = @dasherized_routes ? Utils::String.new(string).underscore : string
+ Utils::String.new(to_classify).classify
end
private
This does appear to work but before following through with a complete PR (and corresponding PR to hanami/hanami for configuration), I wanted to get some feedback on this approach. Thanks in advance for your consideration!
While I think the current set of routes generated by resources
is a reasonable default, the inability to customize, or reuse chunks of routes is somewhat cumbersome when an app deviates from that particular set of routes.
For instance, http://jsonapi.org/ requires supporting PUT for updates, and allows APIs to optionally support PATCH (with a very specific format). When building an API that conforms to that specification (and the same goes for many other specs), it is a pain to have to be specifying things like:
resources 'widgets' do
member do
put '', to: 'widgets#update'
end
end
It is also very visually noisy. It'd be nice if either the set of routes that resources
creates were configurable, or if it were possible to simply configure extra methods that behaved similarly to resources
that define a different set of routes, e.g.
json_api_resources 'widgets'
Or perhaps something that behaves a bit like Rails's routing concerns, e.g.
resources :widgets do
concerns :json_api_resource # adds in the handful of extra routes
end
My favorite is probably allowing resources
to be configured, or the resources
like method approach. I'd be happy to put together a PR for one of them, especially if it can be slipped in before support for < ruby 2.2 is dropped (as I'm likely stuck using 2.1 for several months).
Hi,
Given this two routes:
get '/oauth', to: 'oauth#init'
post '/oauth', to: 'oauth#init'
$ lotus routes shows that:
GET, HEAD / Web::Controllers::Home::Index
POST / Web::Controllers::Home::Index
But when the last route is used, a 405 is returned.
More details:
2.2.1 :001 > router = Web::Application.new.routes.instance_variable_get(:@router)
=> #<HttpRouter:0x3ff1918f056c number of routes (2) ignore_trailing_slash? (true) redirect_trailing_slash? (false)>
============================================================================
Root (1 matchers)
HttpRouter::Node::Lookup
when "oauth":
RequestMethod ["GET", "HEAD"] (1 matchers)
Path: "/oauth" for route unnamed route to Web::Controllers::Oauth::Init
RequestMethod ["POST"] (1 matchers)
Path: "/oauth" for route unnamed route to Web::Controllers::Oauth::Init
2.2.1 :002 > result = router.recognize(Rack::MockRequest.env_for('/oauth', method: :post))
=> [[#<struct HttpRouter::Response request=#<HttpRouter::Request:0x007fe3233daf50 @rack_request=#<Rack::Request:0x007fe3233daf78 @env={"rack.version"=>[1, 3], "rack.input"=>#<StringIO:0x007fe3233db090>, "rack.errors"=>#<StringIO:0x007fe3233db130>, "rack.multithread"=>true, "rack.multiprocess"=>true, "rack.run_once"=>false, "REQUEST_METHOD"=>"POST", "SERVER_NAME"=>"example.org", "SERVER_PORT"=>"80", "QUERY_STRING"=>"", "PATH_INFO"=>"/oauth", "rack.url_scheme"=>"http", "HTTPS"=>"off", "SCRIPT_NAME"=>"", "CONTENT_LENGTH"=>"0"}>, @path=["oauth"], @extra_env={}, @params=[], @acceptable_methods=#<Set: {"GET", "HEAD", "POST"}>, @called=true>, path= Path: "/oauth" for route unnamed route to Web::Controllers::Oauth::Init>], #<Set: {"GET", "HEAD", "POST"}>]
2.2.1 :003 > result.last.inspect
=> "#<Set: {\"GET\", \"HEAD\", \"POST\"}>"
I have something like this:
Hanami::Router.new do
get "/:id", id: /[0-9a-f]{32}/, to: "stuff#show"
get "/:id/foos", id: /[0-9a-f]{32}/, to: "foos#index"
get "/:id/bars", id: /[0-9a-f]{32}/, to: "bars#index"
post "/:id/bars/", id: /[0-9a-f]{32}/, to: "bars#create"
end
Is it possible to somehow wrap all routes that starts with /:id
into a block. Something like this:
Hanami::Router.new do
namespace "/:id", id: /[0-9a-f]{32}/ do
get "/", to: "stuff#show"
get "/foos", to: "foos#index"
get "/bars", to: "bars#index"
post "/bars/", to: "bars#create"
end
end
Thanks.
Please point me in the right direction if I am doing this wrong.
To reproduce, I created a new lotus application
lotus new test
I changed the mount point for the 'Web' app from '/' to '/test', and added a resource to app/web/config/routes.rb
➜ test git:(master) ✗ bundle exec lotus routes
GET, HEAD /test/page Web::Controllers::Home::Index
pigs GET, HEAD /test/pigs Web::Controllers::Pigs::Index
new_pigs GET, HEAD /test/pigs/new Web::Controllers::Pigs::New
pigs POST /test/pigs Web::Controllers::Pigs::Create
pigs GET, HEAD /test/pigs/:id Web::Controllers::Pigs::Show
edit_pigs GET, HEAD /test/pigs/:id/edit Web::Controllers::Pigs::Edit
pigs PATCH /test/pigs/:id Web::Controllers::Pigs::Update
pigs DELETE /test/pigs/:id Web::Controllers::Pigs::Destroy
in apps/web/templates/home/index.html.erb
I added <%= Web::Routes.path(:pigs) %>
Started the server and looked at the page, the path rendered is /pigs
, but would expect it to be /test/pigs
The rake task is aware of the mount point, but within the view context, the apps routes object does not seem to be aware of its own mount point?
I've spent a lot of time looking into the routing code, and haven't really found anything obvious.
$ lotus new sampleapp --arch=app
create sampleapp/.lotusrc
create sampleapp/.env
create sampleapp/.env.development
create sampleapp/.env.test
create sampleapp/Gemfile
create sampleapp/config.ru
create sampleapp/config/environment.rb
create sampleapp/lib/sampleapp.rb
create sampleapp/lib/config/mapping.rb
create sampleapp/config/application.rb
create sampleapp/config/routes.rb
create sampleapp/app/views/application_layout.rb
create sampleapp/app/templates/application.html.erb
create sampleapp/Rakefile
create sampleapp/spec/spec_helper.rb
create sampleapp/spec/features_helper.rb
create sampleapp/app/controllers/.gitkeep
create sampleapp/app/views/.gitkeep
create sampleapp/lib/sampleapp/entities/.gitkeep
create sampleapp/lib/sampleapp/repositories/.gitkeep
create sampleapp/public/javascripts/.gitkeep
create sampleapp/public/stylesheets/.gitkeep
create sampleapp/db/.gitkeep
create sampleapp/spec/features/.gitkeep
create sampleapp/spec/controllers/.gitkeep
create sampleapp/spec/views/.gitkeep
create sampleapp/spec/sampleapp/entities/.gitkeep
create sampleapp/spec/sampleapp/repositories/.gitkeep
create sampleapp/spec/support/.gitkeep
create sampleapp/.gitignore
run git init /mypath/sampleapp from "."
$ cd sampleapp
$ bundle exec lotus generate action home#index
insert config/routes.rb
create spec/controllers/home/index_spec.rb
create app/controllers/home/index.rb
create app/views/home/index.rb
create app/templates/home/index.html.erb
create spec/views/home/index_spec.rb
$ cat config/routes.rb
get '/home', to: 'home#index'
# Configure your routes here
# See: http://www.rubydoc.info/gems/lotus-router/#Usage
$ lotus routes
.rvm/gems/ruby-2.2.2@sampleapp/gems/lotusrb-0.4.0/lib/lotus/container.rb:42:in `assert_configuration_presence!': Lotus::Container doesn't have any application mounted. (ArgumentError)
from .rvm/gems/ruby-2.2.2@drpet/gems/lotusrb-0.4.0/lib/lotus/container.rb:30:in `block in initialize'
from .rvm/gems/ruby-2.2.2@drpet/gems/lotusrb-0.4.0/lib/lotus/container.rb:29:in `synchronize'
from .rvm/gems/ruby-2.2.2@drpet/gems/lotusrb-0.4.0/lib/lotus/container.rb:29:in `initialize'
from .rvm/gems/ruby-2.2.2@drpet/gems/lotusrb-0.4.0/lib/lotus/commands/routes.rb:9:in `new'
from .rvm/gems/ruby-2.2.2@drpet/gems/lotusrb-0.4.0/lib/lotus/commands/routes.rb:9:in `start'
from .rvm/gems/ruby-2.2.2@drpet/gems/lotusrb-0.4.0/lib/lotus/cli.rb:59:in `routes'
from .rvm/gems/ruby-2.2.2@drpet/gems/thor-0.19.1/lib/thor/command.rb:27:in `run'
from .rvm/gems/ruby-2.2.2@drpet/gems/thor-0.19.1/lib/thor/invocation.rb:126:in `invoke_command'
from .rvm/gems/ruby-2.2.2@drpet/gems/thor-0.19.1/lib/thor.rb:359:in `dispatch'
from .rvm/gems/ruby-2.2.2@drpet/gems/thor-0.19.1/lib/thor/base.rb:440:in `start'
from .rvm/gems/ruby-2.2.2@drpet/gems/lotusrb-0.4.0/bin/lotus:4:in `<top (required)>'
from .rvm/gems/ruby-2.2.2@drpet/bin/lotus:23:in `load'
from .rvm/gems/ruby-2.2.2@drpet/bin/lotus:23:in `<main>'
from .rvm/gems/ruby-2.2.2@drpet/bin/ruby_executable_hooks:15:in `eval'
from .rvm/gems/ruby-2.2.2@drpet/bin/ruby_executable_hooks:15:in `<main>'
First time lotus user, hope this is in the right place.
First thing that tripped me up was in environment.rb
- if you set it up like:
Lotus::Container.configure do
mount Web::Application, at: '/'
mount Api::Application, at: '/api/'
end
The /api
will never get exposed. If you change it to:
Lotus::Container.configure do
mount Api::Application, at: '/api/'
mount Web::Application, at: '/'
end
Then it works as expected.
Without looking into the internals of lotus, I'm guessing that in the first example Web::Application
is taking over all routing.
When I try the get started sample code, and run it with rackup
, I encountered this error
/Users/allenlsy/.rvm/gems/ruby-2.0.0-p247/gems/lotus-router-0.1.1/lib/lotus/routing/http_router.rb:110:in `reset!': undefined local variable or method `uncompile' for #<Lotus::Routing::HttpRouter:0x007fea8aa1fe38> (NameError)
from /Users/allenlsy/.rvm/gems/ruby-2.0.0-p247/gems/http_router-0.10.2/lib/http_router.rb:45:in `initialize'
from /Users/allenlsy/.rvm/gems/ruby-2.0.0-p247/gems/lotus-router-0.1.1/lib/lotus/routing/http_router.rb:37:in `initialize'
from /Users/allenlsy/.rvm/gems/ruby-2.0.0-p247/gems/lotus-router-0.1.1/lib/lotus/router.rb:122:in `new'
from /Users/allenlsy/.rvm/gems/ruby-2.0.0-p247/gems/lotus-router-0.1.1/lib/lotus/router.rb:122:in `initialize'
from /Users/allenlsy/projects/lotus/demo1/router.rb:3:in `new'
from /Users/allenlsy/projects/lotus/demo1/router.rb:3:in `<top (required)>'
It seems in the scenario where you have a Container architecture hanami app and have a Sinatra app mounted it blows up with an exception because the inspector assumes a Hanami::Router
instance. I discovered this because I was mounting Sidekiq's web interface into my hanami container application as follows:
Hanami::Container.configure do
mount Sidekiq::Web, at: '/sidekiq'
end
The following is the traceback. I believe it would potentially be as simple as checking if the router responds to inspector
and if it doesn't ignore it.
/Users/adeponte/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/hanami-router-0.6.2/lib/hanami/routing/routes_inspector.rb:213:in `inspect_router': undefined method `inspector' for #<Hash:0x007ff13b607780> (NoMethodError)
Did you mean? inspect
from /Users/adeponte/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/hanami-router-0.6.2/lib/hanami/routing/routes_inspector.rb:163:in `block in inspect_routes'
from /Users/adeponte/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/hanami-router-0.6.2/lib/hanami/routing/routes_inspector.rb:161:in `each'
from /Users/adeponte/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/hanami-router-0.6.2/lib/hanami/routing/routes_inspector.rb:161:in `inspect_routes'
from /Users/adeponte/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/hanami-router-0.6.2/lib/hanami/routing/routes_inspector.rb:139:in `to_s'
from /Users/adeponte/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/hanami-0.7.2/lib/hanami/commands/routes.rb:25:in `start'
from /Users/adeponte/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/hanami-0.7.2/lib/hanami/cli.rb:103:in `routes'
from /Users/adeponte/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/thor-0.19.1/lib/thor/command.rb:27:in `run'
from /Users/adeponte/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/thor-0.19.1/lib/thor/invocation.rb:126:in `invoke_command'
from /Users/adeponte/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/thor-0.19.1/lib/thor.rb:359:in `dispatch'
from /Users/adeponte/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/thor-0.19.1/lib/thor/base.rb:440:in `start'
from /Users/adeponte/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/hanami-0.7.2/bin/hanami:5:in `<top (required)>'
from /Users/adeponte/.rbenv/versions/2.3.0/bin/hanami:23:in `load'
from /Users/adeponte/.rbenv/versions/2.3.0/bin/hanami:23:in `<main>'
Currently the path for an action can be generated using a method that follows an implicit naming convention:
routes.flowers
routes.flower id: 23
routes.new_flower
I think that might be a Rails reminiscence and find it unintuitive (that is manifested by the fact of needing to use a 'routes' command to see the named paths of the routes).
A more intuitive and direct approach might be to allow to generate the paths using the same DSL used to define the routes and that makes an explicit reference to the route action:
get '/', to: 'welcome#index'
path_to 'welcome#index'
and for REST resources
path_to 'flowers#index'
path_to 'flowers#show', id: 23
path_to 'flowers#edit', id: 23
# etc
and for nested resources
#/users/1/favorites/2
path_to 'users::favorites#show', user_id: 1, id: 2
Making a hanami
app and defining a route at '/'
, I expected I'd have access to a routes.root_path
helper, but I had to add as: :root
in order to get it.
This could that I'm accustomed to Rails, and that hanami
prefers to be explicit, but automatically adding a root
path for '/'
seems like a nice feature :)
I used a container with two apps:
But the routes' behaviour is very strange.
# config/environment.rb
Lotus::Container.configure do
mount Api::Application, at: '/api'
mount Web::Application, at: '/'
end
# apps/web/config/routes.rb
get '/', to: 'pets#index', as: :root
# apps/api/config/routes.rb
resources :pets, only: :index
I get this results for lotus routes
command:
pets GET, HEAD /api/api/pets Api::Controllers::Pets::Index
root GET, HEAD / Web::Controllers::Pets::Index
To get the expected behaviour I changed my source as follows:
# config/environment.rb
Lotus::Container.configure do
namespace :api do
mount Api::Application, at: '/'
end
mount Web::Application, at: '/'
end
# apps/web/config/routes.rb
get '/', to: 'pets#index', as: :root
# apps/api/config/routes.rb
namespace :api do
resources :pets, only: :index
end
Results:
api_pets GET, HEAD /api/pets Api::Controllers::Pets::Index
root GET, HEAD / Web::Controllers::Pets::Index
When I consume the http://localhost:2300/api/pets
endpoint it works:
curl http://localhost:2300/api/pets
[]
But, when I try to reach http://localhost:2300/
I got a 404 Not found
:
curl -I http://localhost:2300/
HTTP/1.1 404 Not Found
Content-Type: application/octet-stream
I found it quite strange or am I doing some mistake?
This may or may not be problem with the Hanami Router but since I have isolated this part as the trigger for the problem when testing I am opening the issue here but if could turn out to be an issue within Hanami Controller.
While developing a Hanami application (in the container architecture) I experienced a strange issue in production where the contents of a cookie would only be set once until ruby server was restarted.
What this means is the first request after the server was started would get the cookie set/contents updated, but any subsequent requests to update or set that cookie (from any client) would do nothing. Restarting the server only repeated the same behaviour over again.
After much tinkering the cause of this appears to be related to specifying the route endpoint as a class instead of a string.
get '/', to: 'homepage#index' # This works
get '/', to: ->(env) { Web::Controllers::Homepage::Index.new.call(env) } # This also appears to work
get '/', to: Web::Controllers::Homepage::Index # This does not work
get '/', to: Web::Controllers::Homepage::Index.new # This does not work
An important factor when testing this is --no-code-reloading
.
I've created a repo to help others to experience the issue createdbypete/hanami_cookie_issue.
While investigating this issue I noticed a couple of things that may or may not be significant.
puts
in the #initialize
method only shows up when the endpoint is used. This all seems correct.#initialize
when the application loaded (again noticed with some puts
debugging) perhaps these could also be lazy like string? The curious thing is however that this puts
value is output twice when the app loads.puts
output. I'm not sure why this would be called twice.def set_cookie(key, value)
puts "Before: #{@_headers}"
::Rack::Utils.set_cookie_header!(@_headers, key, value)
puts "After: #{@_headers}"
end
Running in my test repo (above) the output is as follows:
$ bundle exec hanami server --no-code-reloading
[2016-10-09 15:27:29] INFO WEBrick 1.3.1
[2016-10-09 15:27:29] INFO ruby 2.3.1 (2016-04-26) [x86_64-darwin16]
[2016-10-09 15:27:29] INFO WEBrick::HTTPServer#start: pid=41491 port=2300
Before: {"Location"=>"/", "Content-Type"=>"text/html; charset=utf-8"}
After: {"Location"=>"/", "Content-Type"=>"text/html; charset=utf-8", "Set-Cookie"=>"foo=2016-10-09+15%3A27%3A31+%2B1100; HttpOnly"}
127.0.0.1 - - [09/Oct/2016:15:27:31 +1100] "GET HTTP/1.1" 302 - 0.0221
127.0.0.1 - - [09/Oct/2016:15:27:31 +1100] "GET HTTP/1.1" 200 - 0.0123
Before: {"Location"=>"/", "Content-Type"=>"text/html; charset=utf-8", "Set-Cookie"=>"foo=2016-10-09+15%3A27%3A31+%2B1100; HttpOnly"}
After: {"Location"=>"/", "Content-Type"=>"text/html; charset=utf-8", "Set-Cookie"=>"foo=2016-10-09+15%3A27%3A31+%2B1100; HttpOnly\nfoo=2016-10-09+15%3A27%3A38+%2B1100; HttpOnly"}
127.0.0.1 - - [09/Oct/2016:15:27:38 +1100] "GET HTTP/1.1" 302 - 0.0047
127.0.0.1 - - [09/Oct/2016:15:27:38 +1100] "GET HTTP/1.1" 200 - 0.0048
Overall it's all expected output until the last After: where the cookie is repeated in the Set-Cookie
value. It has the first value set and then following it the value we actually want to set:
"Set-Cookie"=>"foo=2016-10-09+15%3A27%3A31+%2B1100; HttpOnly\nfoo=2016-10-09+15%3A27%3A38+%2B1100; HttpOnly"
Perhaps the most interesting part is when opening another browser and trying to set the cookie we see the following output:
127.0.0.1 - - [09/Oct/2016:15:27:59 +1100] "GET HTTP/1.1" 200 - 0.0054
Before: {"Location"=>"/", "Content-Type"=>"text/html; charset=utf-8", "Set-Cookie"=>"foo=2016-10-09+15%3A27%3A31+%2B1100; HttpOnly\nfoo=2016-10-09+15%3A27%3A38+%2B1100; HttpOnly"}
After: {"Location"=>"/", "Content-Type"=>"text/html; charset=utf-8", "Set-Cookie"=>"foo=2016-10-09+15%3A27%3A31+%2B1100; HttpOnly\nfoo=2016-10-09+15%3A27%3A38+%2B1100; HttpOnly\nfoo=2016-10-09+15%3A28%3A05+%2B1100; HttpOnly"}
127.0.0.1 - - [09/Oct/2016:15:28:05 +1100] "GET HTTP/1.1" 302 - 0.0038
127.0.0.1 - - [09/Oct/2016:15:28:05 +1100] "GET HTTP/1.1" 200 - 0.0075
As you can see the foo
cookie now appears 3 times under the Set-Cookie
key. Each request adds one more reference.
Hi.
We use Hanami Router for our internal JSON microservices. The default response cannot be controlled at the moment from I could get from the structure of
I tried monkey patching the class and even in that case it won't work. This is problematic in our use case because we can break clients very easily if we fail to deliver JSON responses in every case and also because we could use this to give a more detailed reply hinting a possibly correct route.
We know this can be done with a wildcard get but if we use namespaces we have to put the wildcard at the end of all the routes and at the end of every namespace. Maybe this could be passed if the options when building a router, something like this:
DefaultController = -> env {
[ 404, {'Content-Type' => 'application/json'}, {error: :not_found}.to_json ]
}
Router = Hanami::Router.new(namespace: Controllers, default: DefaultController) # ....
Does this make sense? This is so far our only issue with Hanami Router, we like it a lot because if easy to begin with and simple to jump from if you already know Rails :)
It would be useful to be able to take a Lotus::Router
instance and serialise it either into a string in order to allow for a command like lotus routes
(or rake routes
) or into an array of intermediate objects which could be easily transformed into a different format (like text).
Support for this (I think) should be added to the router and then we can very quickly implement something like described in hanami/hanami#35 in the main lotus library.
I've been playing around with this but I noticed there's another branch where @jodosha has been changing things. Is this a feature I should go ahead and work on, or are there large changes in the works for the router?
Right now when we create routes directly in the router, the inspector works fine.
puts Lotus::Router.new {
get '/', to: # ...
}.inspector
When we use it with mounted routers or full stack Lotus apps, it doesn't return the expected output.
puts Lotus::Router.new {
mount Lotus::Router.new { ... }, at: '/api'
mount FullStackLotus::Application.new, at: '/'
}.inspector
Hint: Lotus::Application
responds to #routes
, we should make Lotus::Router
to respond to the same method as well. So Inspector
can internally do something like.
if route.respond_to?(:routes)
# we can safely assume it's a mounted Lotus::Router or Lotus application
route.routes.inspector.to_s
else
# actual inspection logic
end
Hi there!
I am look that rubocop
not used in this project.
Used settings from hanami
repository with --auto-correct
get result is:
66 files inspected, 995 offenses detected, 902 offenses corrected
It may be worth adding it?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.