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

Set an url prefix if Django is not mounted under / in production #567

Closed
Wissperwind opened this issue Oct 13, 2021 · 12 comments
Closed

Set an url prefix if Django is not mounted under / in production #567

Wissperwind opened this issue Oct 13, 2021 · 12 comments
Labels
enhancement New feature or request fix confirmation pending issue has been fixed and confirmation from issue reporter is pending

Comments

@Wissperwind
Copy link

Hi,

The plugin identifies all urls correctly from djangos point of view.
But in production django has to be mounted in to a webserver. And under / is usually the folder for static files for the website.
So I mounted django under /backend. So an endpoint that is /getInfo in django is now /backend/getInfo in reality.

Is there an option to tell this to drf spectacular?
If not I would like to request this feature.
Thanks!

@tfranzel
Copy link
Owner

tfranzel commented Oct 13, 2021

Hi,

since Django does not know about this, you need to set SERVERS in the spectacular settings.

'SERVERS': [{'url': 'https://example.com/backend'}]

@Wissperwind
Copy link
Author

Wissperwind commented Oct 13, 2021

Ok, thanks for the anwser, I tried:
I added it to settings.py in the spectacular settings, where I also set title and description and some more.
Unfortunately it doesn't work.
It now diesplays "Could not render n, see the console." under the servers section on the swagger page.
But in the console I cannot finde a usefull message to that problem.
It shows many times "unable to guess serializer". But nothing about the server error.

@ngnpope
Copy link
Contributor

ngnpope commented Oct 13, 2021

I achieved this automatically by adding a post-processing hook:

from urllib.parse import urljoin

def set_request_server(result, generator, request, public):
    if request:
        url = urljoin(request.path, ".").rstrip("/")
        url = request.build_absolute_uri(url)
        result.setdefault("servers", []).append({"url": url})
    return result

This example works where my schema is hosted at, e.g. https://api.example.com/path/to/schema.json and I want the base to be https://api.example.com/path/to/. You can tweak this to suit your needs. Not sure whether you'd like to adopt something like this in the FAQ?

@Wissperwind
Copy link
Author

I dont understand what the preprocessing hook does yet.
I don't need to change anything of the behaviour of django. It ansers the requests well.
Only at the swagger page it shall add a /backend before all requests when running in production.

@tfranzel
Copy link
Owner

tfranzel commented Oct 13, 2021

@Wissperwind, sry I made a mistake there. its a list and not just one dict

    'SERVERS': [
        {
            "url": "https://gigantic-server.com/v1",
            "description": "Production server"
        },
        {
            "url": "https://development.gigantic-server.com/v1",
            "description": "Development server"
        }
    ],

this will not add the backend prefix on the operation entries, but it is used when you use "Try it out" on Swagger UI. The curl command will have the correct full url

@Wissperwind
Copy link
Author

Wissperwind commented Oct 13, 2021

Ah, ok. Now something works.
I can add:

    'SERVERS': [
        {
            "url": "/backend",
        }
    ],

And it adds the prefix to each call and uses still automatic the current host.
The server url can be specified from the customer and I don't know it here.

But there is still a problem. The prefix is not displayed to each URL. So if I show the swagger page to the developers, they will see /api/login and think, OK, let's call localhost:8000/api/login. But that will not work. They have to call localhost:8000/backend/api/login. Sure I can to explain it to them. But some will forget it sometimes. How about a real prefix setting?

@tfranzel
Copy link
Owner

tfranzel commented Oct 14, 2021

added new setting SCHEMA_PATH_PREFIX_INSERT to model theses prefixes.

of course this is hard-coded in comparison to @ngnpope's hook but i suppose this covers the most typical use-cases

@tfranzel tfranzel added enhancement New feature or request fix confirmation pending issue has been fixed and confirmation from issue reporter is pending labels Oct 14, 2021
@Wissperwind Wissperwind changed the title Set a url prefix if Django is not mounted under / in production Set an url prefix if Django is not mounted under / in production Oct 19, 2021
@Wissperwind
Copy link
Author

Wissperwind commented Oct 19, 2021

That works perfectly!
Exactly what I needed. Thanks.

@Wissperwind
Copy link
Author

Wissperwind commented Nov 1, 2021

Ok, so can this issue be closed now?
Is this already in a public release?

@tfranzel
Copy link
Owner

tfranzel commented Nov 1, 2021

yes its released in 0.20.2. it can be closed.

@tfranzel tfranzel closed this as completed Nov 1, 2021
@john-carroll-sw
Copy link

I achieved this automatically by adding a post-processing hook:

from urllib.parse import urljoin

def set_request_server(result, generator, request, public):
    if request:
        url = urljoin(request.path, ".").rstrip("/")
        url = request.build_absolute_uri(url)
        result.setdefault("servers", []).append({"url": url})
    return result

This example works where my schema is hosted at, e.g. https://api.example.com/path/to/schema.json and I want the base to be https://api.example.com/path/to/. You can tweak this to suit your needs. Not sure whether you'd like to adopt something like this in the FAQ?

Hi Nick, where would one place this post-processing hook?

@tfranzel
Copy link
Owner

tfranzel commented Mar 23, 2023

it does not matter where. you just need to set in the import path in the spectacular setting POSTPROCESSING_HOOKS. make sure you don't forget to add the enum postprocessing hook back in to the list.

see doc for more details:

https://drf-spectacular.readthedocs.io/en/latest/customization.html#step-6-postprocessing-hooks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request fix confirmation pending issue has been fixed and confirmation from issue reporter is pending
Projects
None yet
Development

No branches or pull requests

4 participants