-
Notifications
You must be signed in to change notification settings - Fork 596
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support REST API doc generation #201
Comments
Hi there, I agree this would be a really really good feature. Thanks for making it an issue so we don't forget about it! Question being if it isn't better to be taken up as an community effort – as we currently do not have enough man-power to tackle this one. |
I put the label on it, and see what happens ;) |
https://github.com/gettyimages/spray-swagger |
@hepin1989 As mentioned in the first post, spray-swagger looks good but IMHO, it sometimes hurts the conciseness of the routing DSL with verbose annotations. This thread is to discuss various approaches from scratch in a bigger community. |
As already discussed several times on the spray ML automatically producing documentation for the current server-side routing DSL is close to impossible to do robustly. As a simply example, think about how you would want to automatically document this snippet: path("order" / IntNumber) { orderId =>
if (orderId < 10000) // legacy orders only support GET
get {
parameters('foo, 'bar) { (foo, bar) =>
// ...
}
}
else
get {
parameters('baz) { baz =>
// ...
}
} ~
post {
// ...
}
} In its current form the routing DSL is simply too powerful to allow for robust automatic inspection. |
Possible idea: instead of trying to analyze and interpret the route definition, why not observe its execution while running the test suite (that every app surely must have)? The added benefit is that only those parts are documented that are also exercised in the tests. Another component here would be to provide test fixtures for certain RESTful resource patterns to make this task easier. |
+1 Using the tests to produce documentation for a REST API sounds like a good idea. For Spring MVC there is https://github.com/spring-projects/spring-restdocs I specifically like the integration with asciidoctor. |
interesting idea. If this is ever implemented then it would be nice to have an intermediate format emitted so that it can be used in various other ways. |
One more idea: instead of generating documentation by API it possible would be better generate an interface of API from other format like swagger. |
Any progress or recommendation on this? |
The akka team does not have enough people/time to tackle this problem (shipping stable 1.0 releases takes priority over this extra feature). External contributions are more than welcome! |
A couple of weeks ago I've done a proof-of-concept, that tried to provide something similar to Spring Restdocs (https://github.com/spring-projects/spring-restdocs) for akka-http. The project can be found here: https://github.com/kodemaniak/akka-http-restdoc (I hope the README is accurate and does not only work on my computer) That POC is far from being complete. But currently I use a spray port of it to document our main microservice at work. My conclusion after a couple of weeks is that following such an approach (i.e. using asciidoctor for the bulk of documentation and extracting request/reply information from the tests) feels like the right way to go. It fits very well together. It is much easier to keep the docs in sync with the actual behaviour, at least the request/response headers and bodies are generated from tested code, and you save some work since you don't have to write down JSON bodies or HTTP requests by hand. I thought I throw that POC into this dicsussion to get some more feedback. Our spray port is a bit more advanced already, but adding the missing bits and pieces also to the akka-http version would be rather simple. |
@kodemaniak awesome approach, would love to see this developed further! |
Thanks @kodemaniak for pushing this, looks like a good starting point! |
I have recently started to know about akka-http and scala and started off to build my first microservice in this technology. I humbly accept that I am not qualified to make points in this space, but would like to seek guidance on the following points:
By following the above two points, we may avoid large portions of the annotations and the annotations we will be left with would be the routes! As mentioned earlier by @sirthias automating this portion of annotations might be difficult, and if we can avoid rest of the clutter may be we can live with this one! I know, I might be sounding stupid, but I just want to get your expert opinion on my lame thoughts. |
My not-so-pretty attempt at allowing to write separate endpoints that are automatically documented in swagger. This is ugly and very likely has errors, e.g. I have a problem with merging parameter directives with (my own) SwaggerPathMatcher. I can't compile
But the general idea is to give an interface for writing simple auto-documented API endpoints that generate akka-http directives and to allow extending and wrapping them with normal akka-http directives, what do you think? |
Note for interested parties, I currently believe to be more efficient and powerful: generating the structure from tests, similar to: http://docs.spring.io/spring-restdocs/docs/1.0.x/reference/html5/#getting-started-documentation-snippets-invoking-the-service |
Guys-guys-guys. Automatic docs generators is the only one part of problem. What about me - I'm strictly need API schemas. It's impossible to generate schema during the test. Akka-http is definitely needs directives tree introspection. And it's not so hard to implement this. I may try to start this project, but I need to be sure that it will be accepted to upstream. |
I suggest starting out as separate project and if it makes sense to be pulled into Akka HTTP we can do so later on. I agree it's a really awesome thing to have, but I also think it's best if we start incubating it outside the project and pull in once mature and you're willing to contribute (and there actually is a need to be pulled in – it could be a separate lib and do it's job well :-)) |
Ok, I have to possible ways to implement this:
I prefer second option. I already have partial implementation of (1) and it requires a lot of work until completion. |
Keep method parity and it's a drop-in replacement for pure Akka HTTP then. I don't see why it has to be "break into Akka's directives" right away. It can be a library, exposing same methods. If it works out, everyone is happy, and if you'd like to contribute then we have a place to start from. |
Ok, got it. Will try to implement own directives hierarchy keeping same interfaces. |
Hi, |
@FeiWongReed have you made any progress around the |
Unfortunately I still have not enough time to finish it. I have my own subset, working for my services, but its dirty and can't be used in arbitrary project. |
You may use implicit macros and construct not only pathmatchers but also additional introspection data. Anyway its hard to do that in general way. Proper solution is to make scaladsl introspectable. |
It's safe to say with the current DSL this will never be possible in an arbitrary way. I think the most reasonable approach is to have some kind of library that's much more opinionated about your route structure, build an intro-spectable view of what it's created, and then spits out something that conforms to I have something similar to @pshirshov, but it's just a proof of concept and requires some hairy shapeless magic for deriving JSON encoders/validators. Here's what I have for PathMatchers specifically: trait ApiPath[L] { left =>
val pathSegmentDescriptions: Seq[String]
val matcher: PathMatcher[L]
def /[R](other: ApiPath[R])(implicit join: Join[L, R]): ApiPath[join.Out] = {
new ApiPath[join.Out] {
override val pathSegmentDescriptions: Seq[String] =
left.pathSegmentDescriptions ++ other.pathSegmentDescriptions
override val matcher: PathMatcher[join.Out] = left.matcher / other.matcher
}
}
def /[R : DocumentedUrlParameter](other: PathMatcher1[R])(implicit join: AppendOne[L, R]): ApiPath[join.Out] = {
new ApiPath[join.Out] {
override val pathSegmentDescriptions: Seq[String] =
left.pathSegmentDescriptions ++ Seq("<" ++ implicitly[DocumentedUrlParameter[R]].name ++ ">")
override val matcher: PathMatcher[join.Out] = left.matcher / other
}
}
}
trait DocumentedUrlParameter[T] {
def name: String
}
object DocumentedUrlParameter {
// implicit impls here
}
object ApiPath {
implicit def stringToApiPath(s: String): ApiPath[Unit] = new ApiPath[Unit] {
override val pathSegmentDescriptions: Seq[String] = Seq(s)
override val matcher: PathMatcher[Unit] = s : PathMatcher0
}
def /(s: String): ApiPath[Unit] = stringToApiPath(s)
}
can then be generated with case class ApiFormats[BasePathType, InstPathType](basePath: ApiPath[BasePathType], instancePath: ApiPath[InstPathType])
val apiFormats = new ApiFormats(
ApiPath / "v1" / accountIdMatcher / "foos",
ApiPath / "v1" / accountIdMatcher / "foos" / otherMatcher
)
println(apiFormats.basePath) // "/v1/<account>/foos" |
Yup-yup. Unfortunately, all the wrappers around current scaladsl are "just a proof of concept" because, as @ktoso said scaladsl is too powerful and/or we don't have enough time to make a small revolution here. scaladsl definitely needs to evolve into something simpler and better introspectable. Or we may try to implement a "simplescaladsl" which would be based on scaladsl and provide a functional subset enough for real world purposes. And yes, it should compose routing tree statically and expose it in a traversable form. I really wish to do that, but I have no time unfortunately. An yup, I agree that the initial idea with adding some kind of metainformation into the each directive would not work because of dynamic nature of scaladsl. |
I have created a library that provides a workable solution. There is a post about it on Akka-Users at https://groups.google.com/forum/#!searchin/akka-user/townson%7Csort:relevance/akka-user/Pet2WaavbJA/AW66zyEGAQAJ At the moment, it's on bitbucket at https://bitbucket.org/jtownson/swakka. The approach I took is to provide a set of case classes that can be instantiated to represent an OpenApi (e.g. the petstore example). The swakka library then generates akka routes and swagger.json. If you're interested to read more, the project does have a fairly extensive readme given that it's an early release. I've been returning periodically to this ticket for what seems like an eternity, so I'd really like to try and get swakka fully functional in the next few months -- so this ticket might finally be closed. If you care about swagger support for akka-http, I'd really appreciate your feedback. |
Saturday Dec 20, 2014 at 23:05 GMT
Originally opened as akka/akka#16591
Related ML thread: https://groups.google.com/forum/#!topic/akka-user/d18_smRGeoE
The text was updated successfully, but these errors were encountered: