-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
24 changed files
with
663 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
.idea | ||
target | ||
drafter |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# Redwiggler API.md Blueprint support | ||
|
||
# API.md parsers | ||
## Protagonist | ||
To use the [protagonist](https://github.com/apiaryio/protagonist) parser, it must be installed first via npm: | ||
|
||
```shell | ||
npm install protagonist | ||
``` | ||
|
||
```scala | ||
import com.nike.redwiggler.core._ | ||
import com.nike.redwiggler.blueprint._ | ||
import com.nike.redwiggler.html._ | ||
|
||
val blueprint = BlueprintSpecificationProvider( | ||
""" | ||
| # My Api Api | ||
| | ||
| ## Overview | ||
| **MyAPI** is a sample. | ||
| | ||
| ### Search [GET /my/api/v1{?anchor,count,filter}] | ||
""".stripMargin, parser.ProtagonistBlueprintParser()) | ||
|
||
import java.io._ | ||
val requestDir = File.createTempFile("redwiggler", "requests") | ||
requestDir.delete() | ||
requestDir.mkdir() | ||
val requests = GlobEndpointCallProvider(requestDir, ".*.json") | ||
|
||
val htmlReportFile = File.createTempFile("redwiggler", ".html") | ||
val htmlRender = HtmlReportProcessor(htmlReportFile) | ||
|
||
Redwiggler(callProvider = requests, specificationProvider = blueprint , reportProcessor = htmlRender) | ||
|
||
htmlReportFile.exists() should be(true) | ||
``` | ||
|
||
## Drafter | ||
The [drafter](https://github.com/apiaryio/drafter) cli can also be used. This must be installed as well and available on the PATH. | ||
|
||
```scala | ||
import com.nike.redwiggler.core._ | ||
import com.nike.redwiggler.blueprint._ | ||
import com.nike.redwiggler.html._ | ||
|
||
val blueprint = BlueprintSpecificationProvider( | ||
""" | ||
| # My Api Api | ||
| | ||
| ## Overview | ||
| **MyAPI** is a sample. | ||
| | ||
| ### Search [GET /my/api/v1{?anchor,count,filter}] | ||
""".stripMargin, parser.DrafterBlueprintParser) | ||
|
||
import java.io._ | ||
val requestDir = File.createTempFile("redwiggler", "requests") | ||
requestDir.delete() | ||
requestDir.mkdir() | ||
val requests = GlobEndpointCallProvider(requestDir, ".*.json") | ||
|
||
val htmlReportFile = File.createTempFile("redwiggler", ".html") | ||
val htmlRender = HtmlReportProcessor(htmlReportFile) | ||
|
||
Redwiggler(callProvider = requests, specificationProvider = blueprint , reportProcessor = htmlRender) | ||
|
||
htmlReportFile.exists() should be(true) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
#!/bin/sh | ||
|
||
git clone --branch v3.2.2 --recursive git://github.com/apiaryio/drafter.git | ||
cd drafter | ||
./configure | ||
make test | ||
make drafter |
28 changes: 28 additions & 0 deletions
28
blueprint/src/main/scala/com/nike/redwiggler/blueprint/Ast.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package com.nike.redwiggler.blueprint | ||
|
||
import spray.json.DefaultJsonProtocol | ||
|
||
case class Action(attributes: Attributes, method : String, examples : Seq[Example], parameters : Seq[Parameter]) | ||
case class Ast(name : String, description: String, resourceGroups : Seq[ResourceGroup]) | ||
case class AstHolder(ast : Ast) | ||
case class Attributes(uriTemplate : String) | ||
case class Example(name : String, requests : Seq[Request], responses : Seq[Response]) | ||
case class Parameter(name : String, `type` : String, required : Boolean) | ||
case class Request(schema : String) | ||
case class Resource(uriTemplate : String, actions : Seq[Action]) | ||
case class ResourceGroup(resources : Seq[Resource]) | ||
case class Response(name : String, schema : String) | ||
|
||
|
||
trait AstProtocol extends DefaultJsonProtocol { | ||
implicit val response = jsonFormat2(Response.apply) | ||
implicit val request = jsonFormat1(Request.apply) | ||
implicit val parameter = jsonFormat3(Parameter.apply) | ||
implicit val example = jsonFormat3(Example.apply) | ||
implicit val attributes = jsonFormat1(Attributes.apply) | ||
implicit val action = jsonFormat4(Action.apply) | ||
implicit val resource = jsonFormat2(Resource.apply) | ||
implicit val resourceGroup = jsonFormat1(ResourceGroup.apply) | ||
implicit val ast = jsonFormat3(Ast.apply) | ||
implicit val astHolder = jsonFormat1(AstHolder.apply) | ||
} |
19 changes: 19 additions & 0 deletions
19
blueprint/src/main/scala/com/nike/redwiggler/blueprint/BlueprintPathParser.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package com.nike.redwiggler.blueprint | ||
|
||
import com.nike.redwiggler.core.models.{LiteralPathComponent, Path, PathComponent, PlaceHolderPathComponent} | ||
|
||
object BlueprintPathParser { | ||
|
||
def apply(path : String) : Path = { | ||
if (path.contains("{?")) { | ||
apply(path.substring(0, path.indexOf("{?"))) | ||
} else { | ||
Path(Path(path).components.map(parseComponent)) | ||
} | ||
} | ||
|
||
private def parseComponent(component : PathComponent) : PathComponent = component match { | ||
case LiteralPathComponent(c) if c.startsWith(":") => PlaceHolderPathComponent(c.substring(1)) | ||
case _ => component | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
blueprint/src/main/scala/com/nike/redwiggler/blueprint/BlueprintSpecificationProvider.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package com.nike.redwiggler.blueprint | ||
|
||
import java.io.File | ||
import java.util | ||
|
||
import com.nike.redwiggler.blueprint.parser.BlueprintParser | ||
import com.nike.redwiggler.core.EndpointSpecificationProvider | ||
import com.nike.redwiggler.core.models._ | ||
|
||
import collection.JavaConverters._ | ||
import scala.io.Source | ||
|
||
case class BlueprintSpecificationProvider(blueprint : String, blueprintParser: BlueprintParser) extends EndpointSpecificationProvider { | ||
|
||
private lazy val ast = blueprintParser.parse(blueprint) | ||
|
||
override def getEndPointSpecs: util.List[EndpointSpecification] = (for { | ||
resourceGroup <- ast.resourceGroups | ||
resource <- resourceGroup.resources | ||
action <- resource.actions | ||
example <- action.examples | ||
response <- example.responses | ||
} yield { | ||
EndpointSpecification( | ||
verb = HttpVerb.from(action.method), | ||
path = BlueprintPathParser(action.attributes.uriTemplate), | ||
code = Integer.parseInt(response.name), | ||
responseSchema = Option(response.schema).flatMap(parseSchema), | ||
requestSchema = example.requests.headOption.map(_.schema).flatMap(parseSchema) | ||
) | ||
}).asJava | ||
|
||
private def parseSchema(schema : String) = if (schema.trim.isEmpty) { | ||
None | ||
} else { | ||
import org.everit.json.schema.loader.SchemaLoader | ||
import org.json.JSONObject | ||
import org.json.JSONTokener | ||
val rawSchema = new JSONObject(new JSONTokener(schema)) | ||
Some(JsonSchema(SchemaLoader.load(rawSchema))) | ||
} | ||
} | ||
|
||
object BlueprintSpecificationProvider { | ||
def apply(apiMd: File, blueprintParser: BlueprintParser) : BlueprintSpecificationProvider = { | ||
BlueprintSpecificationProvider(Source.fromFile(apiMd).mkString, blueprintParser) | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
blueprint/src/main/scala/com/nike/redwiggler/blueprint/parser/BlueprintParser.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.nike.redwiggler.blueprint.parser | ||
|
||
import com.nike.redwiggler.blueprint.Ast | ||
|
||
trait BlueprintParser { | ||
def parse(blueprint : String) : Ast | ||
|
||
def name : String | ||
} |
57 changes: 57 additions & 0 deletions
57
blueprint/src/main/scala/com/nike/redwiggler/blueprint/parser/DrafterBlueprintParser.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package com.nike.redwiggler.blueprint.parser | ||
|
||
import java.io.{File, FileOutputStream, PrintWriter} | ||
import java.util.concurrent.TimeUnit | ||
|
||
import com.nike.redwiggler.blueprint.{Ast, AstHolder, AstProtocol} | ||
import spray.json.JsonParser | ||
|
||
import scala.io.Source | ||
|
||
object DrafterBlueprintParser extends BlueprintParser with AstProtocol { | ||
|
||
private val LOGGER = org.slf4j.LoggerFactory.getLogger(getClass) | ||
|
||
override def name: String = "drafter" | ||
|
||
override def parse(blueprint: String): Ast = JsonParser(invokeDrafter(blueprint)).convertTo[AstHolder].ast | ||
|
||
private def invokeDrafter(blueprint: String): String = { | ||
val inputFile = File.createTempFile("redwiggler_drafter", ".js") | ||
val inputFileOut = new PrintWriter(new FileOutputStream(inputFile)) | ||
inputFileOut.write(blueprint) | ||
inputFileOut.close() | ||
|
||
val outputFile = File.createTempFile("redwiggler_drafter", ".js") | ||
val process = Runtime.getRuntime.exec(Array(script, | ||
"-o", outputFile.getAbsolutePath, | ||
"-f", "json", | ||
"-t", "ast", | ||
inputFile.getAbsolutePath | ||
)) | ||
process.waitFor(10, TimeUnit.SECONDS) | ||
if (process.exitValue() == 0) { | ||
val x = Source.fromInputStream(process.getInputStream).mkString | ||
LOGGER.debug(x) | ||
Source.fromFile(outputFile).mkString | ||
} else { | ||
LOGGER.error("drafter exit value: " + process.exitValue()) | ||
val x = Source.fromInputStream(process.getInputStream).mkString | ||
LOGGER.error(x) | ||
val error = Source.fromInputStream(process.getErrorStream).mkString | ||
LOGGER.error(error) | ||
throw new RuntimeException("Unable to execute drafter: " + error) | ||
} | ||
} | ||
|
||
private lazy val script = { | ||
val drafter = new File("drafter/bin/drafter") | ||
if (drafter.exists()) { | ||
LOGGER.info("using local drafter: " + drafter.getAbsolutePath) | ||
drafter.getAbsolutePath | ||
} else { | ||
LOGGER.info("using drafter in path") | ||
"drafter" | ||
} | ||
} | ||
} |
78 changes: 78 additions & 0 deletions
78
...rint/src/main/scala/com/nike/redwiggler/blueprint/parser/ProtagonistBlueprintParser.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package com.nike.redwiggler.blueprint.parser | ||
|
||
import java.io.{File, FileOutputStream, PrintWriter} | ||
import java.util.concurrent.TimeUnit | ||
|
||
import com.nike.redwiggler.blueprint.{Ast, AstHolder, AstProtocol} | ||
import spray.json._ | ||
|
||
import scala.io.Source | ||
|
||
case class ProtagonistBlueprintParser(nodePath : Seq[String]) extends BlueprintParser with AstProtocol { | ||
|
||
import ProtagonistBlueprintParser.LOGGER | ||
override def name: String = "protagonist" | ||
|
||
private def invokeNode(blueprint: String): String = { | ||
val script = | ||
""" | ||
|var protagonist = require('protagonist'); | ||
|var options = { | ||
| generateSourceMap: false, | ||
| type: 'ast' | ||
|} | ||
|var blueprint = process.argv[2] | ||
|var fs = require('fs'); | ||
|var blueprintData = fs.readFileSync(blueprint).toString() | ||
|protagonist.parse(blueprintData, options, function(error, result) { | ||
| if (error) { | ||
| console.log(error); | ||
| return; | ||
| } | ||
| | ||
| console.log(JSON.stringify(result)); | ||
|}); | ||
""".stripMargin | ||
|
||
val inputFile = File.createTempFile("redwiggler_protagonist", ".js") | ||
val inputFileOut = new PrintWriter(new FileOutputStream(inputFile)) | ||
inputFileOut.write(blueprint) | ||
inputFileOut.close() | ||
|
||
val sourceFile = File.createTempFile("redwiggler_protagonist", ".js") | ||
val out = new PrintWriter(new FileOutputStream(sourceFile)) | ||
out.write(script) | ||
out.close() | ||
|
||
LOGGER.info("using node path: " + nodePath.mkString(";")) | ||
val process = Runtime.getRuntime.exec(Array("node", sourceFile.getAbsolutePath, inputFile.getAbsolutePath), Array("NODE_PATH=" + nodePath.mkString(";"))) | ||
process.waitFor(10, TimeUnit.SECONDS) | ||
if (process.exitValue() == 0) { | ||
Source.fromInputStream(process.getInputStream).mkString | ||
} else { | ||
LOGGER.error("protagonist exit value: " + process.exitValue()) | ||
val x = Source.fromInputStream(process.getInputStream).mkString | ||
LOGGER.error(x) | ||
val error = Source.fromInputStream(process.getErrorStream).mkString | ||
LOGGER.error(error) | ||
throw new RuntimeException("Unable to execute protagonist: " + error) | ||
} | ||
} | ||
|
||
|
||
override def parse(blueprint : String) : Ast = { | ||
JsonParser(invokeNode(blueprint)).convertTo[AstHolder].ast | ||
} | ||
} | ||
|
||
object ProtagonistBlueprintParser { | ||
private val LOGGER = org.slf4j.LoggerFactory.getLogger(getClass) | ||
|
||
def apply() : ProtagonistBlueprintParser = this( | ||
Seq(System.getProperty("user.home") + "/node_modules", "node_modules") | ||
.map(f => new File(f)) | ||
.filter(_.exists()) | ||
.map(_.getAbsolutePath) | ||
) | ||
} | ||
|
Oops, something went wrong.