Skip to content

Conversation

@chiuinggum
Copy link
Contributor

Why

How

Some differences from original implementation:

  • Data model: normalize created_on/changed_on to UTC tz-aware on output to avoid mixed-aware states. This intentionally differs from the old marshmallow behavior (which validates timezone and may reject naive datetimes unless configured) and aligns with Airflow’s “store in UTC” policy; implemented via a pydantic field_validator (default after parsing).
  • Service: explicitly raises 500 if the registration role is missing, instead of silently appending None.

^ Add meaningful description above
Read the Pull Request Guidelines for more information.
In case of fundamental code changes, an Airflow Improvement Proposal (AIP) is needed.
In case of a new dependency, check compliance with the ASF 3rd Party License Policy.
In case of backwards incompatible changes please leave a note in a newsfragment file, named {pr_number}.significant.rst or {issue_number}.significant.rst, in airflow-core/newsfragments.

Copy link
Contributor

@vincbeck vincbeck left a comment

Choose a reason for hiding this comment

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

One question as well: what about the old APIs we are replacing? Are you planning to delete them once all the APIs are implemented?

resource: ResourceResponse


class RoleRef(BaseModel):
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
class RoleRef(BaseModel):
class Role(BaseModel):

Copy link
Contributor

Choose a reason for hiding this comment

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

I also realized in this file we have models such as ActionResourceResponse that is used in responses but requests as well. In that case could you rename them ActionResource. Same for ActionResponse and ResourceResponse

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I also realized in this file we have models such as ActionResourceResponse that is used in responses but requests as well. In that case could you rename them ActionResource. Same for ActionResponse and ResourceResponse

may i fix this in the next PR? I want to keep the scope of this PR to /users API

Copy link
Contributor

Choose a reason for hiding this comment

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

For sure 👌 Please do not forget, that's the only thing :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

here's the PR: #58069

@chiuinggum
Copy link
Contributor Author

One question as well: what about the old APIs we are replacing? Are you planning to delete them once all the APIs are implemented?

@vincbeck, yes that's the plan!

Copy link
Contributor Author

@chiuinggum chiuinggum Nov 7, 2025

Choose a reason for hiding this comment

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

The latest commit fixes a MyPy error:

Run mypy for dev.................................................................Failed
- hook id: mypy-dev
- exit code: 1
  Using 'uv' to install Airflow


  Using airflow version from current sources

  scripts/in_container/install_airflow_and_providers.py:438: error: Item "None"
  of "Match[str] | None" has no attribute "groups"  [union-attr]
                  owner, repo, branch = repo_match.groups()
                                        ^~~~~~~~~~~~~~~~~
  Found 1 error in 1 file (checked 45 source files)

Copy link
Member

Choose a reason for hiding this comment

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

Thanks for the fix! Although this is a small change but it would be better to split it into another PR.
Since it will be much more easier to backport. Thanks!

@vincbeck
Copy link
Contributor

vincbeck commented Nov 7, 2025

Some conflicts

@chiuinggum chiuinggum force-pushed the feat/fab-fastapi-users-post branch from c8da155 to 7549439 Compare November 8, 2025 03:23
Copy link
Member

@jason810496 jason810496 left a comment

Choose a reason for hiding this comment

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

Nice! LGTM overall.

Comment on lines +27 to +28
if TYPE_CHECKING:
from airflow.providers.fab.auth_manager.api_fastapi.datamodels.roles import Role
Copy link
Member

Choose a reason for hiding this comment

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

It seems we don't need the TYPE_CHECKING as we already imported in line 25.

Suggested change
if TYPE_CHECKING:
from airflow.providers.fab.auth_manager.api_fastapi.datamodels.roles import Role

Comment on lines +54 to +62
created_on: datetime | None = None
changed_on: datetime | None = None

@field_validator("created_on", "changed_on")
@classmethod
def _coerce_tzaware(cls, v: datetime | None) -> datetime | None:
if v is None:
return None
return v if (v.tzinfo and v.utcoffset() is not None) else v.replace(tzinfo=timezone.utc)
Copy link
Member

Choose a reason for hiding this comment

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

Would it be possible to leverage UtcDateTime ? Then we don't need to handle the common timezone validation for this case.

Comment on lines +31 to +32
if TYPE_CHECKING:
from airflow.providers.fab.auth_manager.api_fastapi.datamodels.users import UserBody, UserResponse
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if TYPE_CHECKING:
from airflow.providers.fab.auth_manager.api_fastapi.datamodels.users import UserBody, UserResponse

if TYPE_CHECKING:
from airflow.providers.fab.auth_manager.api_fastapi.datamodels.users import UserBody, UserResponse

users_router = AirflowRouter(prefix="/fab/v1", tags=["FabAuthManager"])
Copy link
Member

Choose a reason for hiding this comment

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

Non-blocking nit, can be done in follow-up PR:
How about adding a common root router for all providers/fab/src/airflow/providers/fab/auth_manager/api_fastapi/routes/<entity>.py? Then we could specified the prefix and tags in single source.

Copy link
Member

Choose a reason for hiding this comment

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

Thanks for the fix! Although this is a small change but it would be better to split it into another PR.
Since it will be much more easier to backport. Thanks!

@vincbeck
Copy link
Contributor

vincbeck commented Dec 1, 2025

Are you planning to update this PR?

@vincbeck
Copy link
Contributor

Completed in #60523

@vincbeck vincbeck closed this Jan 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants