Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions docs/reference/feature-servers/registry-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,10 @@ Most endpoints support these common query parameters:
- `include_relationships` (optional): Include relationships for each feature view
- `allow_cache` (optional): Whether to allow cached data
- `tags` (optional): Filter by tags
- `entity` (optional): Filter feature views by entity name
- `feature` (optional): Filter feature views by feature name
- `feature_service` (optional): Filter feature views by feature service name
- `data_source` (optional): Filter feature views by data source name
- `page` (optional): Page number for pagination
- `limit` (optional): Number of items per page
- `sort_by` (optional): Field to sort by
Expand All @@ -223,6 +227,26 @@ Most endpoints support these common query parameters:
# With pagination and relationships
curl -H "Authorization: Bearer <token>" \
"http://localhost:6572/api/v1/feature_views?project=my_project&include_relationships=true&page=1&limit=5&sort_by=name"

# Filter by entity
curl -H "Authorization: Bearer <token>" \
"http://localhost:6572/api/v1/feature_views?project=my_project&entity=user"

# Filter by feature
curl -H "Authorization: Bearer <token>" \
"http://localhost:6572/api/v1/feature_views?project=my_project&feature=age"

# Filter by data source
curl -H "Authorization: Bearer <token>" \
"http://localhost:6572/api/v1/feature_views?project=my_project&data_source=user_profile_source"

# Filter by feature service
curl -H "Authorization: Bearer <token>" \
"http://localhost:6572/api/v1/feature_views?project=my_project&feature_service=user_service"

# Multiple filters combined
curl -H "Authorization: Bearer <token>" \
"http://localhost:6572/api/v1/feature_views?project=my_project&entity=user&feature=age"
```

#### Get Feature View
Expand Down Expand Up @@ -415,6 +439,7 @@ Most endpoints support these common query parameters:
- `include_relationships` (optional): Include relationships for each feature service
- `allow_cache` (optional): Whether to allow cached data
- `tags` (optional): Filter by tags
- `feature_view` (optional): Filter feature services by feature view name
- `page` (optional): Page number for pagination
- `limit` (optional): Number of items per page
- `sort_by` (optional): Field to sort by
Expand All @@ -428,6 +453,10 @@ Most endpoints support these common query parameters:
# With pagination and relationships
curl -H "Authorization: Bearer <token>" \
"http://localhost:6572/api/v1/feature_services?project=my_project&include_relationships=true&page=1&limit=10"

# Filter by feature view
curl -H "Authorization: Bearer <token>" \
"http://localhost:6572/api/v1/feature_services?project=my_project&feature_view=user_profile"
```

#### Get Feature Service
Expand Down
18 changes: 13 additions & 5 deletions protos/feast/registry/RegistryServer.proto
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,12 @@ message ListAllFeatureViewsRequest {
string project = 1;
bool allow_cache = 2;
map<string,string> tags = 3;
PaginationParams pagination = 4;
SortingParams sorting = 5;
string entity = 4;
string feature = 5;
string feature_service = 6;
string data_source = 7;
PaginationParams pagination = 8;
SortingParams sorting = 9;
}

message ListAllFeatureViewsResponse {
Expand Down Expand Up @@ -342,8 +346,9 @@ message ListFeatureServicesRequest {
string project = 1;
bool allow_cache = 2;
map<string,string> tags = 3;
PaginationParams pagination = 4;
SortingParams sorting = 5;
string feature_view = 4;
PaginationParams pagination = 5;
SortingParams sorting = 6;
}

message ListFeatureServicesResponse {
Expand Down Expand Up @@ -534,7 +539,10 @@ message Feature {
string feature_view = 2;
string type = 3;
string description = 4;
map<string, string> tags = 7;
string owner = 5;
google.protobuf.Timestamp created_timestamp = 6;
google.protobuf.Timestamp last_updated_timestamp = 7;
map<string, string> tags = 8;
}

message ListFeaturesRequest {
Expand Down
4 changes: 4 additions & 0 deletions sdk/python/feast/api/registry/rest/feature_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ def list_feature_services(
False, description="Include relationships for each feature service"
),
allow_cache: bool = Query(default=True),
feature_view: str = Query(
None, description="Filter feature services by feature view name"
),
tags: Dict[str, str] = Depends(parse_tags),
pagination_params: dict = Depends(get_pagination_params),
sorting_params: dict = Depends(get_sorting_params),
Expand All @@ -35,6 +38,7 @@ def list_feature_services(
project=project,
allow_cache=allow_cache,
tags=tags,
feature_view=feature_view,
pagination=create_grpc_pagination_params(pagination_params),
sorting=create_grpc_sorting_params(sorting_params),
)
Expand Down
12 changes: 12 additions & 0 deletions sdk/python/feast/api/registry/rest/feature_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,14 @@ def list_all_feature_views(
include_relationships: bool = Query(
False, description="Include relationships for each feature view"
),
entity: str = Query(None, description="Filter feature views by entity name"),
feature: str = Query(None, description="Filter feature views by feature name"),
feature_service: str = Query(
None, description="Filter feature views by feature service name"
),
data_source: str = Query(
None, description="Filter feature views by data source name"
),
tags: Dict[str, str] = Depends(parse_tags),
pagination_params: dict = Depends(get_pagination_params),
sorting_params: dict = Depends(get_sorting_params),
Expand All @@ -237,6 +245,10 @@ def list_all_feature_views(
project=project,
allow_cache=allow_cache,
tags=tags,
entity=entity,
feature=feature,
feature_service=feature_service,
data_source=data_source,
pagination=create_grpc_pagination_params(pagination_params),
sorting=create_grpc_sorting_params(sorting_params),
)
Expand Down
73 changes: 47 additions & 26 deletions sdk/python/feast/api/registry/rest/features.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from fastapi import APIRouter, Depends, Query
from fastapi import APIRouter, Depends, HTTPException, Query

from feast.api.registry.rest.codegen_utils import render_feature_code
from feast.api.registry.rest.rest_utils import (
Expand Down Expand Up @@ -69,32 +69,53 @@ def get_feature(
feature_view=feature_view,
name=name,
)
response = grpc_call(grpc_handler.GetFeature, req)
if include_relationships:
response["relationships"] = get_object_relationships(
grpc_handler, "feature", name, project
)
if response:
dtype_str = response.get("type") or response.get("dtype")
value_type_enum = (
_convert_value_type_str_to_value_type(dtype_str.upper())
if dtype_str
else None
)
feast_type = from_value_type(value_type_enum) if value_type_enum else None
dtype = (
feast_type.__name__
if feast_type and hasattr(feast_type, "__name__")
else "String"
)
context = dict(
name=response.get("name", name),
dtype=dtype,
description=response.get("description", ""),
tags=response.get("tags", response.get("labels", {})) or {},

try:
try:
response = grpc_call(grpc_handler.GetFeature, req)
except Exception as e:
raise HTTPException(
status_code=404,
detail=f"Feature '{name}' not found in feature view '{feature_view}' in project '{project}'",
) from e

if include_relationships:
response["relationships"] = get_object_relationships(
grpc_handler, "feature", name, project
)

if response:
dtype_str = response.get("type") or response.get("dtype")
value_type_enum = (
_convert_value_type_str_to_value_type(dtype_str.upper())
if dtype_str
else None
)
feast_type = (
from_value_type(value_type_enum) if value_type_enum else None
)
dtype = (
feast_type.__name__
if feast_type and hasattr(feast_type, "__name__")
else "String"
)
context = dict(
name=response.get("name", name),
dtype=dtype,
description=response.get("description", ""),
tags=response.get("tags", response.get("labels", {})) or {},
)
response["featureDefinition"] = render_feature_code(context)

return response

except HTTPException:
raise
except Exception as e:
raise HTTPException(
status_code=500,
detail=f"Internal server error while retrieving feature '{name}' from feature view '{feature_view}' in project '{project}': {str(e)}",
)
response["featureDefinition"] = render_feature_code(context)
return response

@router.get("/features/all")
def list_features_all(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ async def dispatch(self, request: Request, call_next):
user = "anonymous"
project = request.query_params.get("project") or self.project
key = f"recently_visited_{user}"
logger.info(f"[LoggingMiddleware] Project: {project}, Key: {key}")
path = str(request.url.path)
method = request.method

Expand Down
176 changes: 88 additions & 88 deletions sdk/python/feast/protos/feast/registry/RegistryServer_pb2.py

Large diffs are not rendered by default.

33 changes: 30 additions & 3 deletions sdk/python/feast/protos/feast/registry/RegistryServer_pb2.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -689,12 +689,20 @@ class ListAllFeatureViewsRequest(google.protobuf.message.Message):
PROJECT_FIELD_NUMBER: builtins.int
ALLOW_CACHE_FIELD_NUMBER: builtins.int
TAGS_FIELD_NUMBER: builtins.int
ENTITY_FIELD_NUMBER: builtins.int
FEATURE_FIELD_NUMBER: builtins.int
FEATURE_SERVICE_FIELD_NUMBER: builtins.int
DATA_SOURCE_FIELD_NUMBER: builtins.int
PAGINATION_FIELD_NUMBER: builtins.int
SORTING_FIELD_NUMBER: builtins.int
project: builtins.str
allow_cache: builtins.bool
@property
def tags(self) -> google.protobuf.internal.containers.ScalarMap[builtins.str, builtins.str]: ...
entity: builtins.str
feature: builtins.str
feature_service: builtins.str
data_source: builtins.str
@property
def pagination(self) -> global___PaginationParams: ...
@property
Expand All @@ -705,11 +713,15 @@ class ListAllFeatureViewsRequest(google.protobuf.message.Message):
project: builtins.str = ...,
allow_cache: builtins.bool = ...,
tags: collections.abc.Mapping[builtins.str, builtins.str] | None = ...,
entity: builtins.str = ...,
feature: builtins.str = ...,
feature_service: builtins.str = ...,
data_source: builtins.str = ...,
pagination: global___PaginationParams | None = ...,
sorting: global___SortingParams | None = ...,
) -> None: ...
def HasField(self, field_name: typing_extensions.Literal["pagination", b"pagination", "sorting", b"sorting"]) -> builtins.bool: ...
def ClearField(self, field_name: typing_extensions.Literal["allow_cache", b"allow_cache", "pagination", b"pagination", "project", b"project", "sorting", b"sorting", "tags", b"tags"]) -> None: ...
def ClearField(self, field_name: typing_extensions.Literal["allow_cache", b"allow_cache", "data_source", b"data_source", "entity", b"entity", "feature", b"feature", "feature_service", b"feature_service", "pagination", b"pagination", "project", b"project", "sorting", b"sorting", "tags", b"tags"]) -> None: ...

global___ListAllFeatureViewsRequest = ListAllFeatureViewsRequest

Expand Down Expand Up @@ -972,12 +984,14 @@ class ListFeatureServicesRequest(google.protobuf.message.Message):
PROJECT_FIELD_NUMBER: builtins.int
ALLOW_CACHE_FIELD_NUMBER: builtins.int
TAGS_FIELD_NUMBER: builtins.int
FEATURE_VIEW_FIELD_NUMBER: builtins.int
PAGINATION_FIELD_NUMBER: builtins.int
SORTING_FIELD_NUMBER: builtins.int
project: builtins.str
allow_cache: builtins.bool
@property
def tags(self) -> google.protobuf.internal.containers.ScalarMap[builtins.str, builtins.str]: ...
feature_view: builtins.str
@property
def pagination(self) -> global___PaginationParams: ...
@property
Expand All @@ -988,11 +1002,12 @@ class ListFeatureServicesRequest(google.protobuf.message.Message):
project: builtins.str = ...,
allow_cache: builtins.bool = ...,
tags: collections.abc.Mapping[builtins.str, builtins.str] | None = ...,
feature_view: builtins.str = ...,
pagination: global___PaginationParams | None = ...,
sorting: global___SortingParams | None = ...,
) -> None: ...
def HasField(self, field_name: typing_extensions.Literal["pagination", b"pagination", "sorting", b"sorting"]) -> builtins.bool: ...
def ClearField(self, field_name: typing_extensions.Literal["allow_cache", b"allow_cache", "pagination", b"pagination", "project", b"project", "sorting", b"sorting", "tags", b"tags"]) -> None: ...
def ClearField(self, field_name: typing_extensions.Literal["allow_cache", b"allow_cache", "feature_view", b"feature_view", "pagination", b"pagination", "project", b"project", "sorting", b"sorting", "tags", b"tags"]) -> None: ...

global___ListFeatureServicesRequest = ListFeatureServicesRequest

Expand Down Expand Up @@ -1719,11 +1734,19 @@ class Feature(google.protobuf.message.Message):
FEATURE_VIEW_FIELD_NUMBER: builtins.int
TYPE_FIELD_NUMBER: builtins.int
DESCRIPTION_FIELD_NUMBER: builtins.int
OWNER_FIELD_NUMBER: builtins.int
CREATED_TIMESTAMP_FIELD_NUMBER: builtins.int
LAST_UPDATED_TIMESTAMP_FIELD_NUMBER: builtins.int
TAGS_FIELD_NUMBER: builtins.int
name: builtins.str
feature_view: builtins.str
type: builtins.str
description: builtins.str
owner: builtins.str
@property
def created_timestamp(self) -> google.protobuf.timestamp_pb2.Timestamp: ...
@property
def last_updated_timestamp(self) -> google.protobuf.timestamp_pb2.Timestamp: ...
@property
def tags(self) -> google.protobuf.internal.containers.ScalarMap[builtins.str, builtins.str]: ...
def __init__(
Expand All @@ -1733,9 +1756,13 @@ class Feature(google.protobuf.message.Message):
feature_view: builtins.str = ...,
type: builtins.str = ...,
description: builtins.str = ...,
owner: builtins.str = ...,
created_timestamp: google.protobuf.timestamp_pb2.Timestamp | None = ...,
last_updated_timestamp: google.protobuf.timestamp_pb2.Timestamp | None = ...,
tags: collections.abc.Mapping[builtins.str, builtins.str] | None = ...,
) -> None: ...
def ClearField(self, field_name: typing_extensions.Literal["description", b"description", "feature_view", b"feature_view", "name", b"name", "tags", b"tags", "type", b"type"]) -> None: ...
def HasField(self, field_name: typing_extensions.Literal["created_timestamp", b"created_timestamp", "last_updated_timestamp", b"last_updated_timestamp"]) -> builtins.bool: ...
def ClearField(self, field_name: typing_extensions.Literal["created_timestamp", b"created_timestamp", "description", b"description", "feature_view", b"feature_view", "last_updated_timestamp", b"last_updated_timestamp", "name", b"name", "owner", b"owner", "tags", b"tags", "type", b"type"]) -> None: ...

global___Feature = Feature

Expand Down
Loading
Loading