Closed zyv closed 7 years ago
Proposed patch:
diff --git a/plugin/src/main/scala/de/zalando/play/generator/routes/RuleGenerator.scala b/plugin/src/main/scala/de/zalando/play/generator/routes/RuleGenerator.scala
index 2d63658..2acd78d 100644
--- a/plugin/src/main/scala/de/zalando/play/generator/routes/RuleGenerator.scala
+++ b/plugin/src/main/scala/de/zalando/play/generator/routes/RuleGenerator.scala
@@ -75,7 +75,7 @@ object RuleGenerator {
val name = Path.strip(part)
val (constraint, encode) = model.findParameter(Reference(name)) match {
case Some(param) => (param.constraint, param.encode)
- case None => ("""[^/]+""", true)
+ case None => ("""[^/]*""", true)
}
DynamicPart(name, constraint, encode)
} else {
diff --git a/plugin/src/test/scala/de/zalando/play/generator/routes/RuleGeneratorTest.scala b/plugin/src/test/scala/de/zalando/play/generator/routes/RuleGeneratorTest.scala
index 8a34183..c9c9e2b 100644
--- a/plugin/src/test/scala/de/zalando/play/generator/routes/RuleGeneratorTest.scala
+++ b/plugin/src/test/scala/de/zalando/play/generator/routes/RuleGeneratorTest.scala
@@ -14,7 +14,7 @@ class RuleGeneratorTest extends FunSpec with MustMatchers {
implicit val model = StrictModel(Nil, Map.empty, Map.empty, Map.empty, "/base/", None, Map.empty, Map.empty)
val routes = Map(
- "/" -> Nil, "/a/b/c/d" -> List(StaticPart("a/b/c/d")), "/a/b/c/d/" -> List(StaticPart("a/b/c/d/")), "/a/{b}/c/{d}" -> List(StaticPart("a/"), DynamicPart("b", """[^/]+""", true), StaticPart("/c/"), DynamicPart("d", """[^/]+""", true)), "/{a}/{b}/{c}/{d}/" -> List(DynamicPart("a", """[^/]+""", true), StaticPart("/"), DynamicPart("b", """[^/]+""", true), StaticPart("/"), DynamicPart("c", """[^/]+""", true), StaticPart("/"), DynamicPart("d", """[^/]+""", true), StaticPart("/")), "/{a}/b/{c}/d/" -> List(DynamicPart("a", """[^/]+""", true), StaticPart("/b/"), DynamicPart("c", """[^/]+""", true), StaticPart("/d/"))
+ "/" -> Nil, "/a/b/c/d" -> List(StaticPart("a/b/c/d")), "/a/b/c/d/" -> List(StaticPart("a/b/c/d/")), "/a/{b}/c/{d}" -> List(StaticPart("a/"), DynamicPart("b", """[^/]*""", true), StaticPart("/c/"), DynamicPart("d", """[^/]*""", true)), "/{a}/{b}/{c}/{d}/" -> List(DynamicPart("a", """[^/]*""", true), StaticPart("/"), DynamicPart("b", """[^/]*""", true), StaticPart("/"), DynamicPart("c", """[^/]*""", true), StaticPart("/"), DynamicPart("d", """[^/]*""", true), StaticPart("/")), "/{a}/b/{c}/d/" -> List(DynamicPart("a", """[^/]*""", true), StaticPart("/b/"), DynamicPart("c", """[^/]*""", true), StaticPart("/d/"))
)
describe("RuleGeneratorTest") {
New error message showing that at least routing seems now to work correctly:
[info] GET /v1/welcome/{name}
[info] - should discard invalid data *** FAILED ***
[info] Expected true but got false
[info] Contains error: error.pattern in "Bad Request: Illegal character in path at index 1: /\n"
[info] at least one validation failing
[info] given 'Content-Type' [application/json], 'Accept' header [application/json] and URL: [/v1/welcome/\n?] given args: '(\n,None)' did not equal (xxx:290)
Thanks for that suggestion, @zyv.
Hey @slavaschmidt @s12v @gipeshka @stuartmclean, what do you think of this proposed patch?
The reason for us having it like this is a play definition of the path parameters: The default matching strategy for a dynamic part is defined by the regular expression [^/]+
The proposed change might conflict with this rule in some ways or change the semantics of a path parameter to the dynamic part spanning several /
.
I have not tested it, but I have a feeling that calling a play route defined like that
GET /v1/welcome/:name controllers.Welcome.byName(name: String)
with an empty name will end with Play error response about route not found, and not a controller call.
For another framework the proposed change might be a good solution, but I'm not sure about it applied to the Play framework.
Hi Slava,
Thanks for the feedback.
I have not tested it, but I have a feeling that calling a play route defined like that GET /v1/welcome/:name controllers.Welcome.byName(name: String) with an empty name will end with Play error response about route not found, and not a controller call.
I've just checked it and you are right, if the route is defined as /v1/welcome/:name
:
If the route is defined as /v1/welcome/:name/
:
I have to admit that it's consistent and unopinionated in as far as trailing slashes are concerned, but it's still somewhat disappointing to me that Play routing is so bare-bones as compared to RoR / Django, where on top of that you get automatic smart routes canonicalization (redirects to pages with trailing slash, but only if they do exist in the first place) if so you wish:
https://docs.djangoproject.com/en/dev/topics/http/urls/ https://docs.djangoproject.com/en/dev/ref/settings/#append-slash
In Play, apparently the same can only be achieved with a combination of hacks:
https://github.com/mariussoutier/play-trailing-slash/blob/master/app/TrailingSlash.scala https://gist.github.com/NicolaeNMV/3d375ca2e4b43aa6014f
Anyways, this was my first foray into Play, and I can easily agree that my solution is bad / wrong and should be rejected, but the original issue still stands: auto-generated tests are failing, so I think this issue should be then re-purposed towards fixing auto-generated tests such that they correspond to the adopted routing logic, instead of changing how the routing works.
--Yury.
@zyv Yury, thank you very much for the feedback and sorry it took so long for me to react. Unfortunately, currently I can't invest time into further development of the plugin. I appreciate though your contribution and think it will help to address the issue with tests. This is exactly the reason why the issue is still open :)
I agree that other frameworks might be superior to Play, but that's another story altogether :)
Hi Slava, I'm not saying that other frameworks are superior to Play, it's just that coming from around the RoR / Django corner I honestly find it shocking what Scala infrastructure looks like, after all the hype you hear from Java folks. It almost feels like after being waterboarded by Liferay and the like, frameworks like Play are godsend to them, and their creators are to be worshiped :-)
Just the other day I was showing a Scala guy how in Django you write your class for a model, which you can use directly as DAO, and automatically generate database-independent migration code (including automatic merging of successive migrations!), and he was like... oh, we either write DAO and generate schemas from it, or the other way around (and so are coupled to a particular DB), but anyways to do migrations you need either Flyway or Forklift, and then another addon library for Slick and everything has to be written by hand...
See, as a guy who does Haskell after work, I'm completely sold on type safety and actually probably much more fanatical about controlling side effects then the Scala folks, but why everything has to be so immature, and complicated, and badly documented, and abundant of boilerplate... I honestly want to like Scala, but why it is letting me down all the time? Take your clarification from another ticket: sbt 0.13 doesn't support Scala 2.11 you say? WHUT?! It's like saying, well, you know, pip only supports Python 2.6 at the moment...
Anyways, I guess we should discuss this in another setting ;-) let me know if you end up near Köln, we could arrange some drinks.
Closing as resolved
Hi,
Consider the following hello world schema:
I would expect at least requests to
/v1/welcome/
to be routed togetWelcomeByName
and fail validation, because non-empty name is required and result in a BadRequest (400). The auto-generated tests seem to agree with me:In reality, this doesn't happen, because the pattern for parameters expects at least one character. I've patched it to require zero characters or more, and the test for the response code seems to pass, but then fails with a different problem.
I'm not sure that this is the right way to solve the problem and what additional consequences it might have otherwise, therefore I'm not making a pull request, but I will attach my patch to this issue.
Also, I would expect that requests to
/v1/welcome
get redirected to/v1/welcome/
if there is no handler explicitly defined to/v1/welcome
(my understanding is that this is how Django routing works, for instance). Any opinions on that?