Home > Software engineering >  FastAPI, nginx, Docker Explicitly Add Each Endpoint
FastAPI, nginx, Docker Explicitly Add Each Endpoint

Time:07-12

I have a simple FastAPI that returns a string based on a query parameter at the endpoint /day. Trying to deploy using Docker and nginx as a reverse proxy. In order to get http://localhost:3000/api/day?day_num=5 to work, I needed to explicitly add location /api/day to my nginx-setup.conf. I would receive an error if I only had location /api/ and tried to visit http:localhost:3000/api/day.

How can I avoid having to explicitly add each endpoint? Is there a way to make /api/day, /api/docs and any other valid endpoints for localhost:8000 (port Docker exposes for the backend service) work when I visit http:localhost:3000/api/{valid endpoints}?

main.py

from fastapi import FastAPI

app = FastAPI()

@app.get("/day", tags=["Dates"])
async def get_day_of_week(day_num: int = 0):
    """
    Get the current day of week
    """
    days = ['Sun', 'M', 'T', 'W', 'Th', 'F', 'S']
    return days[day_num]

I am trying to use nginx as a reverse proxy.

nginx-setup.conf

upstream api {
    server backend:8000;
}

server {
    listen 8080;

    location /api/ {
        proxy_pass http://api;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    location /api/day {
        proxy_pass http://api/day;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

docker-compose.yml

version: '3'

services:
  backend:
    build:
      context: ./backend
    command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --root-path /api
    ports:
      - "8000:8000"

  nginx:
    image: nginx:latest
    ports:
     - 3000:8080
    volumes:
      - ./nginx/nginx-setup.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - backend

CodePudding user response:

If you don't have a trailing slash in the proxy_pass entry, the path will be included verbatim. So:

location /api/ {
    proxy_pass http://api;
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
}

Will result in the backend seeing /api/day as the request path. Since your application only expects /day, you have to modify your proxy_pass directive to include a trailing slash - this tells nginx to strip the matching part from the location /api/ entry (and you should have a trailing slash here as well).

location /api/ {
    proxy_pass http://api/;  # <- trailing slash
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
}

CodePudding user response:

You should remove the trailing slash in your location configuration:

server {
    listen 8080;

    location /api/ {
-----------------^ remove this one
        proxy_pass http://api;

Nginx replaces the location with a non-trailing-slash uri. So, http://yourserver/api/something will become http://apisometing (note the concatenation).

  • Related