dockernext.jsdocker-composefastapi

Next.js uses different URLs for fetch depending if in client or server component with FastApi when dockerized


I have a dockerized app using Next.js and FastApi. Depending if fetch is called from client or server component different URLs need to be used.

Currently client components use http://localhost:8000/ and server components http://server:8000

How can this be fixed so the same URL can be used?

services:
  db:
    container_name: weatherdb
    image: postgres
    volumes:
      - ./db_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    ports:
      - 5432:5432
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: pass

  client:
    container_name: client
    build:
      context: ./client
      dockerfile: ./Dockerfile
    volumes:
      - ./client:/app
    ports:
      - 3000:3000
    environment:
      - NEXT_PUBLIC_PYTHON_API=http://server:8000

  server:
    container_name: server
    build:
      context: ./server
      dockerfile: ./Dockerfile
    volumes:
      - ./server:/usr/src/app
    ports:
      - "8000:8000"
    environment:
      DB_NAME: weatherdb
      DB_HOST: weatherdb
      DB_PORT: 5432
      DB_USER: postgres
      DB_PASS: pass
    depends_on:
      - db

volumes:
  db_data:

Client Dockerfile

FROM node:18-alpine
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable

WORKDIR /app
EXPOSE 3000

CMD ["pnpm", "run", "dev"]

Server Dockerfile

FROM python:3

WORKDIR /usr/src/app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]

I have tried to use same URL for both server and client components. http://server/ in client component causes ERR_NAME_NOT_RESOLVED.

http://localhost/ in client component results in the following stack trace

TypeError: fetch failed
    at node:internal/deps/undici/undici:12625:11
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Debug (/app/.next/server/chunks/ssr/_85a404._.js:55:21)

Solution

  • How about selecting the right url dynamically within your application. Sample say.

    export const getApiUrl = () => {
      if (typeof window === 'undefined') {
        // Server
        return process.env.SERVER_PYTHON_API;
      } else {
        // Client
        return process.env.NEXT_PUBLIC_PYTHON_API;
      }
    };
    

    Then when making API calls, use the function to get the correct URL. Sample like

    const fetchData = async () => {
      const apiUrl = getApiUrl();
      const response = await fetch(`${apiUrl}/your-endpoint`);
      const data = await response.json();
      return data;
    };
    

    With this you can work with both URL's. And update docker compose env with both url

     environment:
          - NEXT_PUBLIC_PYTHON_API=http://localhost:8000
          - SERVER_PYTHON_API=http://server:8000