Skip to content
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

Helpers for serving swagger.json on server #17

Open
fizruk opened this issue Jan 21, 2016 · 10 comments
Open

Helpers for serving swagger.json on server #17

fizruk opened this issue Jan 21, 2016 · 10 comments

Comments

@fizruk
Copy link
Member

fizruk commented Jan 21, 2016

This is what I've been using:

type WithSwagger api = api :<|> ("swagger.json" :> Get '[JSON] Swagger)

serveWithSwagger :: forall layout. HasServer layout => Swagger -> Proxy layout -> Server layout -> Application
serveWithSwagger spec _ serv = serve (Proxy :: Proxy (WithSwagger layout)) (serv :<|> return spec)

This can be probably generalized so that we won't have to depend on servant-server:

withSwagger :: forall m api application server. Monad m
  => (Proxy (WithSwagger api) -> (server :<|> m Swagger) -> application)  -- serve
  -> Swagger -> Proxy api -> server -> application
withSwagger serve spec _ server =
  serve (Proxy :: Proxy (WithSwagger layout)) (server :<|> return spec)

-- usage example
withSwagger serve (toSwagger api) api server
@fizruk
Copy link
Member Author

fizruk commented Jan 21, 2016

Since some APIs might use Raw, we probably should prepend swagger endpoint.

@simonmichael
Copy link

Would it be possible for toSwagger to ignore a Swagger in the API, making the above unnecessary ?

@jkarni
Copy link
Member

jkarni commented Jan 22, 2016

Would it be possible for toSwagger to ignore a Swagger in the API, making the above unnecessary ?

That sounds like a good idea. The nice thing is that we can actually document the existence of the Swagger endpoint too.

Prior to Verb, this requires 10 new overlapping instances. With Verb, it'll be two.

@fizruk
Copy link
Member Author

fizruk commented Jan 23, 2016

The nice thing is that we can actually document the existence of the Swagger endpoint too.

Do we want instance ToSchema Swagger? And do we want that schema definition polluting the list of definitions? Not sure.

I don't mind adding 10 overlapping instances to ignore endpoints ending in Swagger.

@fizruk
Copy link
Member Author

fizruk commented Feb 4, 2016

Problem

I think this issue actually gives rise to at least these scenarios:

  1. We don't want Swagger endpoint(s) to appear in swagger.json.
  2. We want Swagger endpoint(s) to appear, but don't want to pollute definitions.
  3. We want Swagger endpoint(s) to appear with an accurate schema.

Solutions

Possible solutions to 1:

  1. Introduce WithSwagger helpers as show above.
  2. Always ignore Swagger enpoints (with specific instances of HasSwagger).
  3. Provide a helper type family RemoveEndpoint endpoint api.
  4. Provide a function removeEndpoint and use it to build toSwagger_ which removes Swagger endpoints at term-level.
  5. Provide Ignored a newtype to indicate directly in the API that a type should be ignored by servant-swagger.

Possible solutions to 2:

  1. Provide an incomplete ToSchema instance for Swagger (with externalDocs pointing to the online swagger specification).
  2. Provide a function truncateSchema to truncate any schema to its type and description/docs, use that to build toSwaggerTruncate which would truncate schema for Swagger.
  3. Provide a newtype Truncated a to mark type's schema as truncated in the API.

Possible solutions to 3:

  1. Just provide a complete ToSchema instance for Swagger.

Conclusion

I assume that we want to support all of the scenarios.

I am inclined to this:

  • provide a complete ToSchema instance for Swagger;
  • provide a function truncateSchema to truncate any schema to its type and description/docs, use that to build toSwaggerTruncate which would truncate schema for Swagger;
  • provide a function removeEndpoint and use it to build toSwagger_ which removes Swagger endpoints at term-level.

@jkarni @dmjio what do you think?

Questions to think about:

  • are there any other possible use cases we'd like to support?
  • are there other solutions?
  • what should be the default recommended case?

@soenkehahn
Copy link

I came up with something similar. Some observations:

  • I quickly needed to tweak the Swagger manually, so my function takes a Swagger -> Swagger argument.
  • I think the host and basePath should be set automatically by serveWithSwagger.

@fizruk
Copy link
Member Author

fizruk commented Mar 3, 2016

@soenkehahn Swagger -> Swagger makes sense, yes.

I am not sure though how you expect host and basePath to be filled automatically.
Are you suggesting to take those from the request?

@soenkehahn
Copy link

Yes, as a small Middleware. As long as servant doesn't offer another way of obtaining this information.

@phadej
Copy link
Contributor

phadej commented Feb 1, 2017

There is servant-swagger-ui, which kind of solves this problem (with a little extra stuff though)?

fisx pushed a commit to wireapp/servant-swagger that referenced this issue Jun 1, 2019
Newly added members should also receive a notification
@akhesaCaro
Copy link
Contributor

Hi,
Servant-swagger will be moved into the main Servant repo (see : haskell-servant/servant#1475)
If this issue is still relevant, would it be possible for you to summit it there? : https://github.com/haskell-servant/servant/issues

Thanks in advance!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants