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

Commit a664229

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

9 files changed

Lines changed: 207 additions & 109 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+
}

play-2.5/swagger-play2/build.sbt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,6 @@ pomExtra := {
7676
}
7777

7878
lazy val root = (project in file(".")).enablePlugins(PlayScala)
79+
80+
resourceDirectory in Test := baseDirectory.value / "test-resources"
81+
parallelExecution in Test := false
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

play-2.5/swagger-play2/test/PlayApiListingCacheSpec.scala

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,28 @@
11
import java.io.File
22

33
import io.swagger.config.ScannerFactory
4-
import io.swagger.models.{ModelImpl, HttpMethod}
5-
import io.swagger.models.parameters.{QueryParameter, BodyParameter, PathParameter}
6-
import io.swagger.models.properties.{RefProperty, ArrayProperty}
7-
import play.modules.swagger._
8-
import org.specs2.mutable._
4+
import io.swagger.models.parameters.{BodyParameter, PathParameter, QueryParameter}
5+
import io.swagger.models.properties.{ArrayProperty, RefProperty}
6+
import io.swagger.models.{HttpMethod, ModelImpl}
7+
import io.swagger.util.Json
98
import org.specs2.mock.Mockito
9+
import org.specs2.mutable._
10+
import org.specs2.specification.BeforeAfterAll
1011
import play.api.Logger
11-
import io.swagger.util.Json
12+
import play.modules.swagger._
13+
import play.routes.compiler.{Route => PlayRoute}
14+
1215
import scala.collection.JavaConversions._
1316
import scala.collection.JavaConverters._
14-
import play.routes.compiler.{ Route => PlayRoute }
1517

16-
class PlayApiListingCacheSpec extends Specification with Mockito {
18+
class PlayApiListingCacheSpec extends Specification with Mockito with BeforeAfterAll {
19+
20+
override def afterAll(): Unit = {}
1721

1822
// set up mock for Play Router
19-
val routesList = {
20-
play.routes.compiler.RoutesFileParser.parseContent("""
23+
val routesList: List[PlayRoute] = {
24+
play.routes.compiler.RoutesFileParser.parseContent(
25+
"""
2126
POST /api/document/:settlementId/files/:fileId/accept testdata.DocumentController.accept(settlementId:String,fileId:String)
2227
GET /api/search testdata.SettlementsSearcherController.search(personalNumber:String,propertyId:String)
2328
GET /api/pointsofinterest testdata.PointOfInterestController.list(eastingMin:Double,northingMin:Double,eastingMax:Double,northingMax:Double)
@@ -36,19 +41,17 @@ PUT /api/dog/:id testdata.DogController.add0(id:String)
3641
}
3742
}
3843

39-
val routesRules = Map(routesList map
40-
{ route =>
41-
{
42-
val routeName = s"${route.call.packageName}.${route.call.controller}$$.${route.call.method}"
43-
routeName -> route
44-
}
45-
} : _*)
44+
val routesRules = Map(routesList map { route => {
45+
val routeName = s"${route.call.packageName}.${route.call.controller}$$.${route.call.method}"
46+
routeName -> route
47+
}
48+
}: _*)
49+
4650

4751
val apiVersion = "test1"
4852
val basePath = "/api"
4953

50-
var swaggerConfig = new PlaySwaggerConfig()
51-
54+
val swaggerConfig = new PlaySwaggerConfig()
5255
swaggerConfig setDescription "description"
5356
swaggerConfig setBasePath basePath
5457
swaggerConfig setContact "contact"
@@ -59,12 +62,13 @@ PUT /api/dog/:id testdata.DogController.add0(id:String)
5962
swaggerConfig setLicense "license"
6063
swaggerConfig setLicenseUrl "http://licenseUrl"
6164

62-
PlayConfigFactory.setConfig(swaggerConfig)
65+
override def beforeAll(): Unit = {
66+
ApiListingCache.cache = None
67+
PlayConfigFactory.setConfig(swaggerConfig)
68+
ScannerFactory.setScanner(new PlayApiScanner())
69+
RouteFactory.setRoute(new RouteWrapper(routesRules))
70+
}
6371

64-
var scanner = new PlayApiScanner()
65-
ScannerFactory.setScanner(scanner)
66-
val route = new RouteWrapper(routesRules)
67-
RouteFactory.setRoute(route)
6872

6973
"ApiListingCache" should {
7074

@@ -73,7 +77,7 @@ PUT /api/dog/:id testdata.DogController.add0(id:String)
7377
val docRoot = ""
7478
val swagger = ApiListingCache.listing(docRoot, "127.0.0.1")
7579

76-
Logger.debug ("swagger: " + toJsonString(swagger))
80+
Logger.debug("swagger: " + toJsonString(swagger))
7781
swagger must beSome
7882

7983
swagger must beSome
@@ -157,18 +161,18 @@ PUT /api/dog/:id testdata.DogController.add0(id:String)
157161
val opDogGet = pathDog.getOperationMap.get(HttpMethod.GET)
158162
opDogGet.getOperationId must beEqualTo("listDogs")
159163
opDogGet.getParameters must beEmpty
160-
opDogGet.getConsumes.asScala.toList must beEqualTo(List("application/json","application/xml"))
164+
opDogGet.getConsumes.asScala.toList must beEqualTo(List("application/json", "application/xml"))
161165
opDogGet.getResponses.get("200").getSchema.asInstanceOf[ArrayProperty].getItems.asInstanceOf[RefProperty].getSimpleRef must beEqualTo("Dog")
162-
opDogGet.getProduces.asScala.toList must beEqualTo(List("application/json","application/xml"))
166+
opDogGet.getProduces.asScala.toList must beEqualTo(List("application/json", "application/xml"))
163167

164168
val opDogPut = pathDog.getOperationMap.get(HttpMethod.PUT)
165169
opDogPut.getOperationId must beEqualTo("add1")
166170
opDogPut.getParameters.head.getName must beEqualTo("dog")
167171
opDogPut.getParameters.head.getIn must beEqualTo("body")
168172
opDogPut.getParameters.head.asInstanceOf[BodyParameter].getSchema.getReference must beEqualTo("#/definitions/Dog")
169-
opDogPut.getConsumes.asScala.toList must beEqualTo(List("application/json","application/xml"))
173+
opDogPut.getConsumes.asScala.toList must beEqualTo(List("application/json", "application/xml"))
170174
opDogPut.getResponses.get("200").getSchema.asInstanceOf[RefProperty].getSimpleRef must beEqualTo("ActionAnyContent")
171-
opDogPut.getProduces.asScala.toList must beEqualTo(List("application/json","application/xml"))
175+
opDogPut.getProduces.asScala.toList must beEqualTo(List("application/json", "application/xml"))
172176

173177
val pathDogParam = swagger.get.getPaths.get("/dog/{id}")
174178
pathDogParam.getOperations.size must beEqualTo(1)
@@ -178,8 +182,8 @@ PUT /api/dog/:id testdata.DogController.add0(id:String)
178182
opDogParamPut.getParameters.head.getName must beEqualTo("id")
179183
opDogParamPut.getParameters.head.getIn must beEqualTo("path")
180184
opDogParamPut.getParameters.head.asInstanceOf[PathParameter].getType must beEqualTo("string")
181-
opDogParamPut.getConsumes.asScala.toList must beEqualTo(List("application/json","application/xml"))
182-
opDogParamPut.getProduces.asScala.toList must beEqualTo(List("application/json","application/xml"))
185+
opDogParamPut.getConsumes.asScala.toList must beEqualTo(List("application/json", "application/xml"))
186+
opDogParamPut.getProduces.asScala.toList must beEqualTo(List("application/json", "application/xml"))
183187
opDogParamPut.getResponses.get("200").getSchema.asInstanceOf[RefProperty].getSimpleRef must beEqualTo("ActionAnyContent")
184188

185189
val catDef = swagger.get.getDefinitions.get("Cat").asInstanceOf[ModelImpl]

0 commit comments

Comments
 (0)