Sinatra: Nested Namespaces worked in 1.4.8, broken in 2.0.0

Created on 10 Jun 2017  路  7Comments  路  Source: sinatra/sinatra

I'm not sure if nested namespaces are actually supported as I don't see any specific mention of them in the docs. Anyhow in Sinatra 1.4.8 I could define an app like:

require 'sinatra'
require 'sinatra/contrib'
require 'json'

BOOKS = {
  1 => {name: 'The Lord of the Rings'},
  2 => {name: 'The Chronicles of Narnia'},
  3 => {name: 'Harry Potter'},
}

namespace '/api' do
  namespace '/v1' do
    namespace '/books' do
      get do
        body JSON.dump(BOOKS)
      end
    end
  end
end

cURLing the endpoint:

$ curl localhost:4567/api/v1/books
{"1":{"name":"The Lord of the Rings"},"2":{"name":"The Chronicles of Narnia"},"3":{"name":"Harry Potter"}}

Now if I define a similar app in Sinatra 2.0.0:

require 'sinatra'
require 'sinatra/contrib'
require 'json'

BOOKS = {
  1 => {name: 'The Lord of the Rings'},
  2 => {name: 'The Chronicles of Narnia'},
  3 => {name: 'Harry Potter'},
}

namespace '/api' do
  namespace '/v1' do
    namespace '/books' do
      get do
        body JSON.dump(BOOKS)
      end
    end
  end
end

And then cURL the same path:

$  curl localhost:4567/api/v1/books
<!DOCTYPE html>
<html>
<head>
  <style type="text/css">
  body { text-align:center;font-family:helvetica,arial;font-size:22px;
    color:#888;margin:20px}
  #c {margin:0 auto;width:500px;text-align:left}
  </style>
</head>
<body>
  <h2>Sinatra doesn鈥檛 know this ditty.</h2>
  <img src='http://localhost:4567/__sinatra__/404.png'>
  <div id="c">
    Try this:
    <pre>get &#x27;&#x2F;api&#x2F;v1&#x2F;books&#x27; do
  &quot;Hello World&quot;
end
</pre>
  </div>
</body>
</html>

With this 2.0.0 Sintra app I decided to list all the GET paths:

Sinatra::Application.routes["GET"].each do |route|
  puts route[0]
end

Which results in:

/api/v1/v1/books

If I cURL that path I get a successful result:

$  curl localhost:4567/api/v1/v1/books
{"1":{"name":"The Lord of the Rings"},"2":{"name":"The Chronicles of Narnia"},"3":{"name":"Harry Potter"}}

The repeated v1/v1 is not expected. Sinatra 1.4.8's /api/v1/books is the behaviour I would have expected.

Is this supposed to work? If there is a better way to define nested namespaces please let me know.

debug regression sinatra-contrib

Most helpful comment

@aren55555 @mencargo @zzak Could you confirm my pull request(#1322)?

All 7 comments

We are experiencing the same problem.
Sinatra 2 introduced Mustermann as a dependency for string matching, the errors are originating from that gem.

An weird behavior is that if the second level namespace is a param like /:version instead of /v1 in the example above, you would get:

lib/mustermann/ast/validation.rb:34:in `check_name': can't use the same capture name twice: "/{version}/{version}/books/?" (Mustermann::CompileError)

@mencargo I've seen that same error too when trying to setup params within namespace; however when I reported the issue I was trying to make it as simple as possible. Both scenarios used to work and now no longer do.

However, I don't see any documentation indicating that they were ever supported and I am just hoping we get some clarification on this issue. It's blocking my upgrade from 1.x to 2.x.

I wonder if this is similar to #1251 or affected in some way.

There is also _some_ coverage for nested namespaces here:
https://github.com/sinatra/sinatra/blob/69a7b8f23321f19c6de02212153f2821c16c25c7/sinatra-contrib/spec/namespace_spec.rb#L468-L478

/cc @mwpastore @namusyaka

I'm going to take a look at this issue in a few days.

@namusyaka 銇婇銇勮嚧銇椼伨銇欙紒 :pray:

@aren55555 @mencargo @zzak Could you confirm my pull request(#1322)?

Was this page helpful?
0 / 5 - 0 ratings