Skip to content

refactor: init fastapi#32348

Draft
asukaminato0721 wants to merge 4 commits intolanggenius:mainfrom
asukaminato0721:fastapi-init
Draft

refactor: init fastapi#32348
asukaminato0721 wants to merge 4 commits intolanggenius:mainfrom
asukaminato0721:fastapi-init

Conversation

@asukaminato0721
Copy link
Copy Markdown
Contributor

@asukaminato0721 asukaminato0721 commented Feb 15, 2026

Important

  1. Make sure you have read our contribution guidelines
  2. Ensure there is an associated issue and you have been assigned to it
  3. Use the correct syntax to link this PR: Fixes #<issue number>.

Summary

just skip to fastapi lol

begin #30269

Screenshots

fastapi has redoc

Before After
... ...

Checklist

  • This change requires a documentation update, included: Dify Document
  • I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
  • I've updated the documentation accordingly.
  • I ran make lint and make type-check (backend) and cd web && npx lint-staged (frontend) to appease the lint gods

Copilot AI review requested due to automatic review settings February 15, 2026 19:17
@asukaminato0721 asukaminato0721 marked this pull request as ready for review February 15, 2026 19:17
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. refactor labels Feb 15, 2026
gemini-code-assist[bot]

This comment was marked as outdated.

This comment was marked as outdated.

@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Feb 15, 2026
Copilot AI review requested due to automatic review settings February 15, 2026 19:29
@asukaminato0721
Copy link
Copy Markdown
Contributor Author

use

DEBUG=true DEPLOY_ENV=DEVELOPMENT STORAGE_TYPE=opendal OPENDAL_SCHEME=fs OPENDAL_FS_ROOT=storage SWAGGER_UI_ENABLED=true uv run --project api --directory api uvicorn asgi:app --host 0.0.0.0 --port 5001 --reload

to test.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 21 out of 22 changed files in this pull request and generated 7 comments.

Comments suppressed due to low confidence (3)

api/controllers/console/init_validate.py:76

  • Like setup.py, this module calls synchronous, Flask-SQLAlchemy-backed services (TenantService.get_tenant_count() and the Session(db.engine) fallback). In an async def FastAPI handler this will both (1) block the event loop and (2) fail without an active Flask app context. Consider making these handlers sync (def) until the underlying DB layer is async, and ensure ASGI requests enter a Flask app context (or migrate to the standalone SQLAlchemy session factory).
async def get_init_status(request: Request) -> InitStatusResponse:
    """Get initialization validation status."""
    init_status = get_init_validate_status(request)
    if init_status:
        return InitStatusResponse(status="finished")
    return InitStatusResponse(status="not_started")


@console_async_router.post(
    "/init",
    response_model=InitValidateResponse,
    tags=["console"],
    status_code=201,
)
async def validate_init_password(
    payload: InitValidatePayload,
    request: Request,
    _: Annotated[None, Depends(require_self_hosted_edition)],
) -> InitValidateResponse:
    """Validate initialization password."""
    tenant_count = TenantService.get_tenant_count()
    if tenant_count > 0:
        raise AlreadySetupError()

    if payload.password != os.environ.get("INIT_PASSWORD"):
        request.session["is_init_validated"] = False
        raise InitValidateFailedError()

    request.session["is_init_validated"] = True
    return InitValidateResponse(result="success")


def get_init_validate_status(request: Request) -> bool:
    if dify_config.EDITION == "SELF_HOSTED":
        if os.environ.get("INIT_PASSWORD"):
            if request.session.get("is_init_validated"):
                return True

            with Session(db.engine) as db_session:
                return db_session.execute(select(DifySetup)).scalar_one_or_none() is not None

api/tests/unit_tests/controllers/console/test_fastapi_setup.py:8

  • DIFY_ASGI_MOUNT_FLASK is set with setdefault() at import time; if the variable is already set (e.g., by another test), importing asgi may still mount the Flask app via the module-level app = create_asgi_app(), making this test order-dependent. Prefer setting the env var unconditionally or configuring it once in a conftest before importing asgi anywhere.
    api/controllers/console/setup.py:101
  • These endpoints are declared async def but call synchronous services/DB access (e.g., TenantService.get_tenant_count(), RegisterService.setup(), and get_setup_status() which uses db.session). In FastAPI, blocking work inside async def will block the event loop; until the DB/services are async, prefer def endpoints (threadpool) or explicitly offload blocking calls to a threadpool.
async def get_setup_status_api() -> SetupStatusResponse:
    """Get system setup status.

    NOTE: This endpoint is unauthenticated by design.

    During first-time bootstrap there is no admin account yet, so frontend initialization must be
    able to query setup progress before any login flow exists.

    Only bootstrap-safe status information should be returned by this endpoint.
    """
    if dify_config.EDITION == "SELF_HOSTED":
        setup_status = get_setup_status()
        if setup_status and not isinstance(setup_status, bool):
            return SetupStatusResponse(step="finished", setup_at=setup_status.setup_at.isoformat())
        if setup_status:
            return SetupStatusResponse(step="finished")
        return SetupStatusResponse(step="not_started")
    return SetupStatusResponse(step="finished")


@console_async_router.post(
    "/setup",
    response_model=SetupResponse,
    tags=["console"],
    status_code=201,
)
async def setup_system(
    payload: SetupRequestPayload,
    request: Request,
    _: Annotated[None, Depends(require_self_hosted_edition)],
) -> SetupResponse:
    """Initialize system setup with admin account.

    NOTE: This endpoint is unauthenticated by design for first-time bootstrap.
    Access is restricted by deployment mode (`SELF_HOSTED`), one-time setup guards,
    and init-password validation rather than user session authentication.
    """
    if get_setup_status():
        raise AlreadySetupError()

    tenant_count = TenantService.get_tenant_count()
    if tenant_count > 0:
        raise AlreadySetupError()

    if not get_init_validate_status(request):
        raise NotInitValidateError()

    normalized_email = payload.email.lower()

    RegisterService.setup(
        email=normalized_email,
        name=payload.name,
        password=payload.password,
        ip_address=extract_remote_ip(request),
        language=payload.language,
    )

    return SetupResponse(result="success")

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread api/asgi.py Outdated
Comment thread api/tests/unit_tests/controllers/console/test_fastapi_version.py Outdated
Comment thread api/asgi.py Outdated
Comment thread api/controllers/console/setup.py
Comment thread api/pyrightconfig.json Outdated
Comment thread api/tests/unit_tests/controllers/console/test_fastapi_init_validate.py Outdated
Comment thread api/tests/unit_tests/controllers/console/test_fastapi_ping.py Outdated
Copilot AI review requested due to automatic review settings February 15, 2026 19:47
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 22 out of 23 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

api/pyproject.toml:1

  • FastAPI version 0.122.0 does not exist. As of January 2025, the latest FastAPI version is 0.115.x. Please verify and use an existing version number.
[project]

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Makefile Outdated
crazywoola
crazywoola previously approved these changes Feb 16, 2026
@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Feb 16, 2026
Copilot AI review requested due to automatic review settings February 17, 2026 07:55
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 22 out of 23 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings February 17, 2026 08:06
@asukaminato0721 asukaminato0721 review requested due to automatic review settings February 17, 2026 08:06
@asukaminato0721 asukaminato0721 marked this pull request as draft February 17, 2026 22:05
@asukaminato0721
Copy link
Copy Markdown
Contributor Author

this need some redesign...

Discussed with gemini 3 pro, get a new plan. Will update later.

Copilot AI review requested due to automatic review settings February 19, 2026 19:47
@langgenius langgenius deleted a comment from gemini-code-assist Bot Feb 19, 2026
@asukaminato0721 asukaminato0721 force-pushed the fastapi-init branch 2 times, most recently from 01bdec2 to 6d9ca2a Compare February 19, 2026 19:52
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 27 out of 28 changed files in this pull request and generated 8 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread api/controllers/console/init_validate.py Outdated
Comment thread docker/docker-compose.yaml Outdated
Comment thread docker/docker-compose-template.yaml Outdated
server_name ${NGINX_SERVER_NAME};

location = /console/api/ping {
proxy_pass http://fastapi:5004;
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The nginx configuration routes /console/api/ping specifically to the fastapi service (port 5004), while all other /console/api/* routes go to the api service (port 5001). This creates inconsistent routing where one endpoint goes to a different service. This could lead to confusion, especially since the tests expect the ping endpoint to be available in the ASGI app. Consider whether this separation is intentional or if all /console/api/* routes should go to the same service.

Suggested change
proxy_pass http://fastapi:5004;
proxy_pass http://api:5001;

Copilot uses AI. Check for mistakes.
Comment thread api/asgi.py Outdated
Comment thread api/pyproject.toml
Comment thread api/pyproject.toml Outdated
Comment thread api/controllers/console/setup.py
Copilot AI review requested due to automatic review settings February 19, 2026 20:03
@asukaminato0721 asukaminato0721 review requested due to automatic review settings February 19, 2026 20:03
@asukaminato0721
Copy link
Copy Markdown
Contributor Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces FastAPI into the project by adding a new fastapi service and migrating the /console/api/ping endpoint as a first step. The changes are well-structured, using a new fastapi run mode and updating the Docker and Nginx configurations to route traffic appropriately for the new endpoint. I have two main points of feedback: one regarding the API documentation for the new FastAPI app, and another about the lack of tests for the new endpoint after the old ones were removed.

Comment thread api/fastapi_app.py
Comment thread api/fastapi_app.py
[autofix.ci] apply automated fixes
@asukaminato0721
Copy link
Copy Markdown
Contributor Author

first migrate easy part. and the doc will be better.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread api/docker/entrypoint.sh
--host "${DIFY_BIND_ADDRESS:-0.0.0.0}" \
--port "${DIFY_PORT:-5004}"

else
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The FastAPI service uses the same image (langgenius/dify-api:1.13.0) as the main API service, but there's no error handling for the MODE environment variable in the entrypoint script. If MODE is set to an unsupported value, the service will fall through to the default Flask behavior without clear indication that FastAPI mode was intended. Consider adding validation or logging for the MODE value.

Suggested change
else
else
# If MODE is set but not one of the recognized values, log a warning before falling back.
if [[ -n "${MODE}" && "${MODE}" != "worker" && "${MODE}" != "beat" && "${MODE}" != "job" && "${MODE}" != "fastapi" && "${MODE}" != "migration" ]]; then
echo "Warning: Unsupported MODE '${MODE}', falling back to default Flask API mode."
fi

Copilot uses AI. Check for mistakes.
Comment on lines 6 to +11

location = /console/api/ping {
proxy_pass http://fastapi:5004;
include proxy.conf;
}

Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The nginx configuration routes /console/api/ping specifically to the FastAPI service, but all other /console/api requests continue to go to the Flask service. This creates a split-brain scenario where clients cannot rely on consistent behavior for all /console/api endpoints. Consider documenting this routing split or ensuring that the FastAPI service can handle all /console/api requests to avoid confusion.

Suggested change
location = /console/api/ping {
proxy_pass http://fastapi:5004;
include proxy.conf;
}
# NOTE:
# The `/console/api/ping` endpoint is intentionally routed to the FastAPI service.
# This is typically used as a health-check or a FastAPI-specific endpoint.
location = /console/api/ping {
proxy_pass http://fastapi:5004;
include proxy.conf;
}
# NOTE:
# All other `/console/api` endpoints are intentionally routed to the Flask API service.
# This split routing means `/console/api/ping` is served by FastAPI while the rest of
# `/console/api/*` continues to be served by the Flask backend at `api:5001`.

Copilot uses AI. Check for mistakes.
Comment thread api/fastapi_app.py
result: str = Field(description="Health check result", examples=["pong"])


@app.get("/console/api/ping", response_model=PingResponse, tags=["console"])
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test file for the ping endpoint was deleted, but no equivalent test for the new FastAPI ping endpoint was created. The codebase has test coverage for other console endpoints (e.g., test_fastopenapi_init_validate.py, test_fastopenapi_setup.py). A corresponding test should be added to maintain test coverage consistency for the FastAPI ping endpoint.

Copilot uses AI. Check for mistakes.
@crazywoola crazywoola removed the lgtm This PR has been approved by a maintainer label Mar 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refactor size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants