Skip to content
This repository has been archived by the owner on Feb 24, 2024. It is now read-only.

Add Swagger Support to API #220

Open
philipithomas opened this issue Feb 3, 2017 · 5 comments
Open

Add Swagger Support to API #220

philipithomas opened this issue Feb 3, 2017 · 5 comments
Labels
help wanted Feel free to contribute! proposal A suggestion for a change, feature, enhancement, etc
Milestone

Comments

@philipithomas
Copy link
Contributor

Opening this for tracking. I don't yet have a proposed solution or data architecture yet.

When I've used the grpc-gateway project in the past, on of my favorite features was the auto-swagger generator. With strongly-typed requests and responses coming from Protocol Buffers, the gateway had all the information it needed to generate the API definition.

I think that an auto-documentation tool built into Buffalo would make it more developer friendly.

The most radical way we could do this would be to use grpc-gateway, use protocol buffers to generate the API definitions, and simultaneously support gRPC with REST. However, I think this seems heavy-handed.

@markbates Do you have any thoughts or opinions on this?

@markbates
Copy link
Member

That definitely seems a bit heavy handed, but I'm open to the idea of figuring out a good way to work with swagger.

I've thought about it in the past. I would love to be able to do several things with swagger:

  • generate handlers, models, etc... based on swagger
  • generate swagger - i've done this sort of thing before in ruby by using my tests to generate api docs. it's a surprising nice way of doing that sort thing, capturing request/response info and generating docs
  • drive app tests using swagger

those are my initial thoughts.

@arschles
Copy link
Contributor

maybe a go start is to just generate just the routes and stub handlers with go-swagger? the work would be to create a new generation template for buffalo routes & stub handlers.

I'm interested to hear thoughts

@squarism
Copy link

squarism commented Feb 26, 2018

I've been thinking about this and ran into this Github issue discussion. Just posting my thoughts as @arschles asked for. 😄

I think having api doc and generation harmonizes with the rapid nature of buffalo. Of course everyone wants to just "build their app" and work faster. I guess this isn't a revelation ... but instead it seems to come up when you start another JSON API and are wondering why am I doing this again. The problem of the tool though is in the details. (spooky dramatic comment music)

You likely already know this but I think the idea behind these tools is to create docs that are executable (like specs) but also have wiring between the client and the server. And initial generation is all fine and well but you'd really want continuing enforcement in CI or something to ensure that API docs don't just bit-rot. Using swagger or RAML isn't super rapid in initial spec generation imho, I think the real win is when your API exists for a long time and you constantly have to manage a README of curl commands or resort to giving up and say "just read the source luke" which is essentially saying "there are no docs for our API".

Buffalo has it's own Go source generation. So you couldn't like just generate a swagger server off a yaml file and then move that code into a buffalo project. It wouldn't sync up with the migrations anyway. So there's not a direct integration point even for the generators. But since buffalo doesn't want to be like goa where generation and commands are continually updating code, you wouldn't want that.

What if you did sort of spec first development?

  1. Use go-swagger to generate a client off a YAML spec.
  2. Use go-swagger to generate a server off of a spec.
  3. Run the mock server and run the client against the mock server. (I think you'd have to write this code)
    => Great but that runs in a vacuum and doesn't solve the problem of the actual app bit-rotting. Go-swagger can generate a server but that won't be used by buffalo unless you moved or wired the code over somehow. I think this whole strategy is flawed.

Ok, what if you generated the client, watched it fail against a non-existent server?

  1. Use go-swagger to generate a client off of a YAML spec.
  2. Wrote client using code to hit a server. (integration spec)
  3. Implemented the API in Buffalo.
  4. Develop loop until integration spec passes.
    => Great but there's still no auto-wiring and you're relying on developer discipline. Any changes to the API require you to change YAML, regen the client, update the integration spec and then implement the change in the Buffalo app.

No, I think the real value of swagger (as a concept, including RAML etc) is its ability to be an executable link between the client / server and documentation. If you have a generated client and server passing tests of any kind and being used within an app, you are very confident in the API docs because they are "bit fresh". 🎈

But how do you reconcile regeneration (swagger) and no regeneration (buffalo)? Seems like it's a dead idea unless there's a proxy / handoff / option / pass-through or something where the router goes to a set of code that is not hand written by a Buffalo app dev. The two projects have an impasse on code (re)generation.

Some more details:

  • The go-swagger package and CLI requires the project root and YAML doc to be in the GOPATH. I believe gobuffalo used to have the same limitation but then was made more flexible with Fixed issue #203: multiple GOPATH are not supported by buffalo new. #205 I think? Using go-swagger would re-introduce this limitation concept if there was some CLI flag to generate or use a package that is coming from go-swagger in the router. I can imagine some hack where you could rewrite the package or something. Bleh.

Anyway, sorry to ramble without implementation work. I guess in summary, I wonder if the router is the best glue spot?

@arschles
Copy link
Contributor

@squarism I've been following this thread pretty loosely, so some really late comments:

No, I think the real value of swagger (as a concept, including RAML etc) is its ability to be an executable link between the client / server and documentation

💯% agree!

I wonder if the router is the best glue spot?

Can you expand on this? Do you mean a router that sits in front of the buffalo app?

@squarism
Copy link

@arschles Yeah, I'm just not sure on where the glue points would sit. What I mean is, swagger server (the thing that serves the docs so a client could play with the API) is just a net/http server and gorilla/mux would work with that? I'm just not sure how you would route with a buffalo.Context to a swagger handler. Maybe there would be a Translator or middleware or something that would do that? I'm just not spun up on either of these packages to know.

What I mean is:

g := a.Group("/api")
g.Use(SwaggerUI)
g.GET("/api", func (c buffalo.Context) error {
   SwaggerUI.handle(c)  // ?? how would this work
})

This also doesn't know the difference between HTML requests and JSON for example. You'd need a separate path for the Swagger UI or inspect the request and route based on MIME type. It'd be neat if there was an assumption or option to route HTML requests to Swagger and JSON requests to Buffalo.

@stanislas-m stanislas-m added enhancement New feature or request help wanted Feel free to contribute! and removed Feature Request labels Apr 16, 2018
@sio4 sio4 added proposal A suggestion for a change, feature, enhancement, etc and removed enhancement New feature or request labels Sep 27, 2022
@sio4 sio4 added this to the Proposal milestone Sep 27, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
help wanted Feel free to contribute! proposal A suggestion for a change, feature, enhancement, etc
Projects
None yet
Development

No branches or pull requests

7 participants