apiflask icon indicating copy to clipboard operation
apiflask copied to clipboard

Serving openapi.json from subpath

Open Real-Gecko opened this issue 7 months ago • 3 comments

My backend is served from subpath /api, so urls look like this:

/api/search
/apu/users
/api/audit

So if I open /api/openapi.json I get the OpenAPI spec. And if I open /api/docs I get the swagger UI but it shows error:

Image

Because it tries to load /openapi.json which is served by frontend.

Settings spec_path to something like /api/openapi.json does not help, because then spec url becomes /api/api/openapi.json and swagger tries to get it from /api/openapi.json which is 404 in my app.

Any way to serve spec from subpath?

Real-Gecko avatar May 23 '25 10:05 Real-Gecko

So, what I've achieved so far:

app = APIFlask(__name__, instance_relative_config=True, spec_path="/api/spec")
app.config["LOCAL_SPEC_PATH"] = "openapi.json"
app.config["SYNC_LOCAL_SPEC"] = True

@app.route("/spec")
def spec():
    with open("openapi.json", "r") as f:
        return f.read(), 200, {"content-type": "application/json"}

Now I can open swagger UI without errors, however all request from swagger to backend are also not prefixed i.e. /audit and not /api/audit.

Real-Gecko avatar May 23 '25 12:05 Real-Gecko

Can you provide a minimal case?

FarmerChillax avatar Jun 13 '25 07:06 FarmerChillax

My current solution for now that works:

application = APIFlask(
    __name__,
    instance_relative_config=True,
    spec_path="/api/spec",
    enable_openapi=settings.DEBUG,
    docs_ui="rapidoc"
)

@application.route("/spec")
def spec():
    return redirect("/api/api/spec")

So, I'm redirecting requests from /api/spec to /api/api/spec so that swagger can reach openapi.json. Looks hacky but works.

Real-Gecko avatar Jun 13 '25 14:06 Real-Gecko