tornado-swagger icon indicating copy to clipboard operation
tornado-swagger copied to clipboard

Remove common prefix from endpoints (api_base_url)

Open jdmansour opened this issue 1 year ago • 0 comments

Is your feature request related to a problem? Please describe. My API as a whole is located under a certain prefix, e.g. /services/gradingtool-service/..., and all the individual endpoints are relative to this. For this case, OpenAPI has the property basePath, which gets prepended to each endpoint. However, even when I set api_base_url, the endpoints in swagger still show the full path and not only the relative path:

With prefix:

grafik

Without prefix:

grafik

I can leave out the prefix in my application routes. When I call setup_swagger, the routes look correct in swagger UI. However, they are now served at the wrong paths, so using the APIs gets a 404.

What I'm doing now is ugly, but works: I define the routes without prefix, call setup_swagger, and then add back the prefix to my own routes, but not the swagger ones:

Details
def main():
    prefix = '/services/gradingtool-service/"
    routes = [
        tornado.web.url('/', GradingHandler),
        tornado.web.url('/submit_sync', SubmitWorkHandler),
        # ...
    ]
    setup_swagger(
        routes,
        api_base_url=prefix,
        # ...
    )
    app = Application(prefix_routes(routes, prefix),
        cookie_secret=os.urandom(32)
    )
    http_server = HTTPServer(app)
    http_server.listen(7890, 'localhost')
    IOLoop.current().start()


def prefix_routes(routes, prefix):
    """
    Add a prefix in front of all routes, except the swagger routes.
    We do it this way, so the API definitions come out nicely.
    """
    new_routes = []
    for r in routes:
         # If the classname from r.target starts with tornado_swagger._handlers, skip
        if r.target.__module__ == 'tornado_swagger._handlers':
            new_routes.append(r)
            continue
        pattern = url_path_join(prefix, r.matcher.regex.pattern)
        new_route = tornado.web.url(pattern, r.target, r.target_kwargs, r.name)
        new_routes.append(new_route)
    return new_routes

Describe the solution you'd like It would be nice if tornado-swagger could strip the common prefix from the endpoints that it emits to the OpenAPI definition. I think just stripping api_base_url might break existing code, so it might be useful to add a new strip_prefix argument to setup_swagger. Example:

    prefix = '/services/gradingtool-service"
    routes = [
        tornado.web.url(f'{prefix}/', GradingHandler),
        tornado.web.url(f'{prefix}/submit_sync', SubmitWorkHandler),
        # ...
    ]
    setup_swagger(
        routes,
        api_base_url=prefix,
        strip_prefix=prefix,
        # ...
    )

Other considerations:

  • OpenAPI 3.0 doesn't use basePath, but servers. I think this is also in favor of adding a strip_prefix argument.
  • What if the whole application is behind a proxy that rewrites the URLs? I think you should already be able to handle this with the api_base_url, but I'm not sure.
  • One could probably make api_base_url default to the value of strip_prefix, if not set.

Describe alternatives you've considered Instead of stripping the prefix from the routes, one could define the routes without the prefix and have setup_swagger prepend it (like in my workaround). However, I think that is not very elegant, since the routes defined do not match the routes that are served by tornado.

What do you think? If you think the feature is sensible I could work on a pull request.

jdmansour avatar Sep 19 '23 16:09 jdmansour