feat: Added relationship support to all API endpoints (#5496) · feast-dev/feast@bea83e7

@@ -5,21 +5,42 @@

55

from feast.api.registry.rest.rest_utils import (

66

create_grpc_pagination_params,

77

create_grpc_sorting_params,

8+

get_object_relationships,

89

get_pagination_params,

10+

get_relationships_for_objects,

911

get_sorting_params,

1012

grpc_call,

1113

parse_tags,

1214

)

1315

from feast.registry_server import RegistryServer_pb2

1416151718+

def _extract_feature_view_from_any(any_feature_view: dict) -> dict:

19+

"""Extract the specific feature view type and data from an AnyFeatureView object.

20+21+

Args:

22+

any_feature_view: Dictionary containing the AnyFeatureView data

23+24+

Returns:

25+

Dictionary with 'type' and feature view data, or empty dict if no valid type found

26+

"""

27+

for key, value in any_feature_view.items():

28+

if value:

29+

return {"type": key, **value}

30+31+

return {}

32+33+1634

def get_feature_view_router(grpc_handler) -> APIRouter:

1735

router = APIRouter()

18361937

@router.get("/feature_views/{name}")

2038

def get_any_feature_view(

2139

name: str,

2240

project: str = Query(...),

41+

include_relationships: bool = Query(

42+

False, description="Include relationships for this feature view"

43+

),

2344

allow_cache: bool = Query(True),

2445

):

2546

req = RegistryServer_pb2.GetAnyFeatureViewRequest(

@@ -29,18 +50,24 @@ def get_any_feature_view(

2950

)

3051

response = grpc_call(grpc_handler.GetAnyFeatureView, req)

3152

any_feature_view = response.get("anyFeatureView", {})

32-

feature_view = (

33-

any_feature_view.get("featureView")

34-

or any_feature_view.get("onDemandFeatureView")

35-

or any_feature_view.get("streamFeatureView")

36-

or {}

37-

)

38-

return {"featureView": feature_view}

53+54+

result = _extract_feature_view_from_any(any_feature_view)

55+56+

if include_relationships:

57+

relationships = get_object_relationships(

58+

grpc_handler, "featureView", name, project, allow_cache

59+

)

60+

result["relationships"] = relationships

61+62+

return result

39634064

@router.get("/feature_views")

4165

def list_all_feature_views(

4266

project: str = Query(...),

4367

allow_cache: bool = Query(default=True),

68+

include_relationships: bool = Query(

69+

False, description="Include relationships for each feature view"

70+

),

4471

tags: Dict[str, str] = Depends(parse_tags),

4572

pagination_params: dict = Depends(get_pagination_params),

4673

sorting_params: dict = Depends(get_sorting_params),

@@ -52,6 +79,27 @@ def list_all_feature_views(

5279

pagination=create_grpc_pagination_params(pagination_params),

5380

sorting=create_grpc_sorting_params(sorting_params),

5481

)

55-

return grpc_call(grpc_handler.ListAllFeatureViews, req)

82+

response = grpc_call(grpc_handler.ListAllFeatureViews, req)

83+

any_feature_views = response.get("featureViews", [])

84+85+

# Extract the specific type of feature view from each AnyFeatureView

86+

feature_views = []

87+

for any_feature_view in any_feature_views:

88+

feature_view = _extract_feature_view_from_any(any_feature_view)

89+

if feature_view:

90+

feature_views.append(feature_view)

91+92+

result = {

93+

"featureViews": feature_views,

94+

"pagination": response.get("pagination", {}),

95+

}

96+97+

if include_relationships:

98+

relationships = get_relationships_for_objects(

99+

grpc_handler, feature_views, "featureView", project, allow_cache

100+

)

101+

result["relationships"] = relationships

102+103+

return result

5610457105

return router