Skip to content
This repository was archived by the owner on Sep 14, 2022. It is now read-only.

Commit 0787941

Browse files
author
François LAROCHE
committed
Allow sub-routes
1 parent 5111816 commit 0787941

6 files changed

Lines changed: 147 additions & 54 deletions

File tree

play-2.5/swagger-play2/app/play/modules/swagger/SwaggerPlugin.scala

Lines changed: 67 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,34 @@
11
/**
2-
* Copyright 2014 Reverb Technologies, Inc.
3-
*
4-
* Licensed under the Apache License, Version 2.0 (the "License");
5-
* you may not use this file except in compliance with the License.
6-
* You may obtain a copy of the License at
7-
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
9-
*
10-
* Unless required by applicable law or agreed to in writing, software
11-
* distributed under the License is distributed on an "AS IS" BASIS,
12-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
* See the License for the specific language governing permissions and
14-
* limitations under the License.
15-
*/
2+
* Copyright 2014 Reverb Technologies, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
1616

1717
package play.modules.swagger
1818

1919
import java.io.File
2020
import javax.inject.Inject
21+
2122
import io.swagger.config.{FilterFactory, ScannerFactory}
22-
import play.modules.swagger.util.SwaggerContext
2323
import io.swagger.core.filter.SwaggerSpecFilter
2424
import play.api.inject.ApplicationLifecycle
25-
import play.api.{Logger, Application}
2625
import play.api.routing.Router
27-
import scala.concurrent.Future
28-
import scala.collection.JavaConversions._
29-
import play.routes.compiler.{Route => PlayRoute, Include => PlayInclude, RoutesFileParser, StaticPart}
26+
import play.api.{Application, Logger}
27+
import play.modules.swagger.util.SwaggerContext
28+
import play.routes.compiler.{RoutesFileParser, StaticPart, Include => PlayInclude, Route => PlayRoute}
3029

30+
import scala.collection.JavaConversions._
31+
import scala.concurrent.Future
3132
import scala.io.Source
3233

3334
trait SwaggerPlugin
@@ -54,33 +55,33 @@ class SwaggerPluginImpl @Inject()(lifecycle: ApplicationLifecycle, router: Route
5455

5556
val title = config.getString("swagger.api.info.title") match {
5657
case None => ""
57-
case Some(value)=> value
58+
case Some(value) => value
5859
}
5960

6061
val description = config.getString("swagger.api.info.description") match {
6162
case None => ""
62-
case Some(value)=> value
63+
case Some(value) => value
6364
}
6465

6566
val termsOfServiceUrl = config.getString("swagger.api.info.termsOfServiceUrl") match {
6667
case None => ""
67-
case Some(value)=> value
68+
case Some(value) => value
6869
}
6970

7071
val contact = config.getString("swagger.api.info.contact") match {
7172
case None => ""
72-
case Some(value)=> value
73+
case Some(value) => value
7374
}
7475

7576
val license = config.getString("swagger.api.info.license") match {
7677
case None => ""
77-
case Some(value)=> value
78+
case Some(value) => value
7879
}
7980

8081
val licenseUrl = config.getString("swagger.api.info.licenseUrl") match {
8182
// licenceUrl needs to be a valid URL to validate against schema
8283
case None => "http://licenseUrl"
83-
case Some(value)=> value
84+
case Some(value) => value
8485
}
8586

8687
SwaggerContext.registerClassLoader(app.classloader)
@@ -106,44 +107,23 @@ class SwaggerPluginImpl @Inject()(lifecycle: ApplicationLifecycle, router: Route
106107
val routes = parseRoutes
107108

108109
def parseRoutes: List[PlayRoute] = {
109-
def playRoutesClassNameToFileName(className: String) = className.replace(".Routes", ".routes")
110110

111111
val routesFile = config.underlying.hasPath("play.http.router") match {
112112
case false => "routes"
113113
case true => config.getString("play.http.router") match {
114114
case None => "routes"
115-
case Some(value)=> playRoutesClassNameToFileName(value)
115+
case Some(value) => SwaggerPluginHelper.playRoutesClassNameToFileName(value)
116116
}
117117
}
118-
//Parses multiple route files recursively
119-
def parseRoutesHelper(routesFile: String, prefix: String): List[PlayRoute] = {
120-
logger.debug(s"Processing route file '$routesFile' with prefix '$prefix'")
121-
122-
val routesContent = Source.fromInputStream(app.classloader.getResourceAsStream(routesFile)).mkString
123-
val parsedRoutes = RoutesFileParser.parseContent(routesContent,new File(routesFile))
124-
val routes = parsedRoutes.right.get.collect {
125-
case (route: PlayRoute) => {
126-
logger.debug(s"Adding route '$route'")
127-
Seq(route.copy(path = route.path.copy(parts = StaticPart(prefix) +: route.path.parts)))
128-
}
129-
case (include: PlayInclude) => {
130-
logger.debug(s"Processing route include $include")
131-
parseRoutesHelper(playRoutesClassNameToFileName(include.router), include.prefix)
132-
}
133-
}.flatten
134-
logger.debug(s"Finished processing route file '$routesFile'")
135-
routes
136-
}
137-
parseRoutesHelper(routesFile, "")
118+
119+
SwaggerPluginHelper.parseRoutes(routesFile, "", logger.debug(_), app.classloader)
138120
}
139121

140-
val routesRules = Map(routes map
141-
{ route =>
142-
{
143-
val routeName = s"${route.call.packageName}.${route.call.controller}$$.${route.call.method}"
144-
(routeName -> route)
145-
}
146-
} : _*)
122+
val routesRules = Map(routes map { route => {
123+
val routeName = s"${route.call.packageName}.${route.call.controller}$$.${route.call.method}"
124+
(routeName -> route)
125+
}
126+
}: _*)
147127

148128
val route = new RouteWrapper(routesRules)
149129
RouteFactory.setRoute(route)
@@ -174,3 +154,36 @@ class SwaggerPluginImpl @Inject()(lifecycle: ApplicationLifecycle, router: Route
174154
}
175155

176156
}
157+
158+
object SwaggerPluginHelper {
159+
def playRoutesClassNameToFileName(className: String): String = className.replace(".Routes", ".routes")
160+
161+
//Parses multiple route files recursively
162+
def parseRoutes(routesFile: String, prefix: String, debug: String => Unit, classLoader: ClassLoader): List[PlayRoute] = {
163+
debug(s"Processing route file '$routesFile' with prefix '$prefix'")
164+
165+
val routesContent = Source.fromInputStream(classLoader.getResourceAsStream(routesFile)).mkString
166+
val parsedRoutes = RoutesFileParser.parseContent(routesContent, new File(routesFile))
167+
val routes = parsedRoutes.right.get.collect {
168+
case (route: PlayRoute) =>
169+
debug(s"Adding route '$route'")
170+
(prefix, route.path.parts) match {
171+
case ("", _) => Seq(route)
172+
case (_, Seq()) => Seq(route.copy(path = route.path.copy(parts = StaticPart(prefix) +: route.path.parts)))
173+
case (_, Seq(StaticPart(""))) => Seq(route.copy(path = route.path.copy(parts = StaticPart(prefix) +: route.path.parts)))
174+
case (_, Seq(StaticPart("/"))) => Seq(route.copy(path = route.path.copy(parts = StaticPart(prefix) +: route.path.parts)))
175+
case (_, _) => Seq(route.copy(path = route.path.copy(parts = StaticPart(prefix) +: StaticPart("/") +: route.path.parts)))
176+
}
177+
case (include: PlayInclude) =>
178+
debug(s"Processing route include $include")
179+
val newPrefix = if(prefix == "") {
180+
include.prefix
181+
} else {
182+
s"$prefix/${include.prefix}"
183+
}
184+
parseRoutes(playRoutesClassNameToFileName(include.router), newPrefix, debug, classLoader)
185+
}.flatten
186+
debug(s"Finished processing route file '$routesFile'")
187+
routes
188+
}
189+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import io.swagger.config.ScannerFactory
2+
import org.specs2.mock.Mockito
3+
import org.specs2.mutable._
4+
import play.modules.swagger._
5+
import play.routes.compiler.Route
6+
7+
import scala.collection.JavaConverters._
8+
9+
class PlayDelegatedApiScannerSpec extends Specification with Mockito {
10+
11+
val routes: List[Route] = play.modules.swagger.SwaggerPluginHelper.parseRoutes(
12+
"delegation",
13+
"",
14+
_ => {},
15+
Thread.currentThread().getContextClassLoader)
16+
17+
18+
val routesRules: Map[String, Route] = Map(routes.map { route: Route =>
19+
s"${route.call.packageName}.${route.call.controller}$$.${route.call.method}" -> route
20+
}: _*)
21+
22+
23+
val swaggerConfig = new PlaySwaggerConfig()
24+
swaggerConfig.setBasePath("")
25+
swaggerConfig.setHost("127.0.0.1")
26+
27+
PlayConfigFactory.setConfig(swaggerConfig)
28+
29+
var scanner = new PlayApiScanner()
30+
ScannerFactory.setScanner(scanner)
31+
val route = new RouteWrapper(routesRules.asJava)
32+
RouteFactory.setRoute(route)
33+
34+
35+
"route parsing" should {
36+
"separate delegated paths correctly" in {
37+
38+
val urls = ApiListingCache.listing("", "127.0.0.1").get.getPaths.keySet().asScala
39+
40+
urls must contain("/api/all")
41+
urls must contain("/api/my/action")
42+
urls must contain("/api/subdelegated/all")
43+
urls must contain("/api/subdelegated/my/action")
44+
urls must contain("/api/subdelegated")
45+
}
46+
}
47+
48+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-> /subdelegated subdelegated.Routes
2+
3+
GET /my/action testdata.DelegatedController.list
4+
GET /all testdata.DelegatedController.list2
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-> /api delegated.Routes
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
GET /my/action testdata.DelegatedController.list3
2+
GET /all testdata.DelegatedController.list4
3+
GET / testdata.DelegatedController.list5
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package testdata
2+
3+
import io.swagger.annotations.{Api, ApiOperation}
4+
import play.api.mvc.{Action, Controller}
5+
6+
@Api
7+
object DelegatedController extends Controller {
8+
9+
@ApiOperation(value = "list")
10+
def list = Action { _ => Ok("test case")}
11+
12+
@ApiOperation(value = "list2")
13+
def list2 = Action { _ => Ok("test case")}
14+
15+
@ApiOperation(value = "list3")
16+
def list3 = Action { _ => Ok("test case")}
17+
18+
@ApiOperation(value = "list4")
19+
def list4 = Action { _ => Ok("test case")}
20+
21+
@ApiOperation(value = "list5")
22+
def list5 = Action { _ => Ok("test case")}
23+
24+
}

0 commit comments

Comments
 (0)