delete("/foo/1/bar/#:value") { "value="+params("value")+"\n" }
Result:
% curl -X DELETE 'http://localhost:8080/foo/1/bar/%23baz'
value=baz
What's going on:
- The fragment is not submitted to the server, so you need to percent
encode it in the request.
- The URL is percent decoded before matching, so the '#' is correct in
the route.
- [the missing piece] Parameters always need a leading colon.
--
Ross A. Baker
ba...@alumni.indiana.edu
Indianapolis, IN, USA
On Thu, Apr 14, 2011 at 5:43 AM, Ivan Porto Carrero <iv...@mojolly.com> wrote:
> That is against the HTTP spec though
> a fragment is a client thing only, I'm surprised they even get to the server
> http://stackoverflow.com/questions/2286402/url-fragment-and-302-redirects
>
Parameters get translated into the regular expression: ([^/?#]+) That
is, they match every character except '/', '?', and '#'. That's why
/foo/bar/#:thing works and /foo/bar/:thing doesn't. This behavior is
copied from Sinatra, but I'm not sure why they made '#' special.
For use cases where the string routing fails, you can use a regular
expression instead.
Yes, if you wanted to match with and without the # prefix, you'd need
two routes. Parameters won't ever match a #, so embedded in the
middle of a word is tough. All of this behavior should be 100%
compatible with Sinatra, but it's sure ugly in this particular use
case.
> Maybe using some sort of splat thing would work.
> I'll have to creak out the code and check it out.
> Keith
You can also interactively test from the console:
scala> SinatraPathPatternParser("/foo/bar/:thing")
res3: org.scalatra.PathPattern = PathPattern(^/foo/bar/([^/?#]+)$,List(thing))
scala> SinatraPathPatternParser("/foo/bar/:thing")("/foo/bar/#thing")
res4: Option[org.scalatra.ScalatraKernel.MultiParams] = None
scala> SinatraPathPatternParser("/foo/bar/:thing")("/foo/bar/thing")
res5: Option[org.scalatra.ScalatraKernel.MultiParams] = Some(Map(thing
-> ListBuffer(thing)))
There are cases where we want to encode, and cases where you don't.
See this Sinatra test:
it "allows using unicode" do
mock_app do
get('/föö') { }
end
get '/f%C3%B6%C3%B6'
assert_equal 200, status
end
There's nothing ambiguous about 'ö'. The route is made more readable
because of the decoding.
The use case that Keith brings up is a pain. Another tough one is
where slash characters are encoded (%2F) so they are part of a path
segment instead of delimiting a path segment. Under the current
implementation, that distinction is lost.
One possible compromise is to leave reserved characters encoded, but
decode everything else. I don't know of a library function offhand
that does this. We'd also have to start trimming context paths and
servlet paths ourselves, because the path info as provided by the
Servlet API is already decoded.
http://en.wikipedia.org/wiki/Percent_encoding#Percent-encoding_reserved_characters
-- the whole article is a good background on this subject.
What surprises me is that encoding path elements between the / delimiters does NOT work with Scalatra. Isn't this what encoding is for? (By principle of least surprise, I'd expect encoding path elements solves the problem.)I expected the route matching to happen before the encoding, then the decoding to happen just before the params and multiParams are bound.But I see it's a thorny problem for an API.In my particular case, I want to do something like:delete /app/user/<id>/company/<code>which expresses EXACTLY what it does, which is to delete that company code (which is provided by users). They seem to like those twitteresque hash marks.I can work around this by doing my own encoding (s/#/.hash./g, but it feels like I'm working around a wart in the otherwise life-saving Scalatra, rather than just a painful design choice on my part. I can live with it, though.Good luck!KeithOn Friday, April 15, 2011 at 6:30 AM, Ross A. Baker wrote:
On Fri, Apr 15, 2011 at 6:35 AM, Ivan Porto Carrero <iv...@mojolly.com> wrote:
There are cases where we want to encode, and cases where you don't.
See this Sinatra test:
it "allows using unicode" do
mock_app do
get('/fรถรถ') { }
end
get '/f%C3%B6%C3%B6'
assert_equal 200, status
end
There's nothing ambiguous about 'รรถ'. The route is made more readable